On Thu, Apr 08, 2021 at 06:22:16PM +0200, Theo Buehler wrote: > On Thu, Apr 08, 2021 at 04:47:15PM +0200, Claudio Jeker wrote: > > This diff is a first step in tightening the code in http.c > > It should cleanup the poll handling and make adds some code to ensure that > > only expected results are returned. The goal is that http_handle() only > > does IO processing and http_nextstep() is used for transitions into new > > states. > > I like this direction. > > > I did shuffle the code around a bit. So that similar functions are together. > > Also by shuffling the poll loop now connections are added after the all > > active connections have been processed. > > This added quite a bit of noise to the diff (especially some parts > shuffling _write() functions are hard to read). > > I'm ok with this, one small comment below. >
Sorry about that. I committed the deck chair shuffle and some other minor bits. Here is the part that replaces the regular and chunked write functions with a single data_write one. I made the strtoul() check look like the man page example to detect overflows. There is some off_t vs size_t casts required but in that case the size limited bufpos is casted. -- :wq Claudio Index: http.c =================================================================== RCS file: /cvs/src/usr.sbin/rpki-client/http.c,v retrieving revision 1.24 diff -u -p -r1.24 http.c --- http.c 8 Apr 2021 16:56:34 -0000 1.24 +++ http.c 8 Apr 2021 17:12:49 -0000 @@ -107,9 +107,7 @@ struct http_connection { size_t bufsz; size_t bufpos; size_t id; - size_t chunksz; - off_t filesize; - off_t bytes; + off_t iosz; int status; int redirect_loop; int fd; @@ -727,10 +725,10 @@ http_parse_header(struct http_connection cp += sizeof(CONTENTLEN) - 1; if ((s = strcspn(cp, " \t")) != 0) *(cp+s) = 0; - conn->filesize = strtonum(cp, 0, LLONG_MAX, &errstr); + conn->iosz = strtonum(cp, 0, LLONG_MAX, &errstr); if (errstr != NULL) { - warnx("Improper response from %s", - http_info(conn->url)); + warnx("Content-Length of %s is %s", + http_info(conn->url), errstr); return -1; } } else if (http_isredirect(conn) && @@ -820,7 +818,7 @@ http_parse_chunked(struct http_connectio { char *header = buf; char *end; - int chunksize; + unsigned long chunksize; /* ignore empty lines, used between chunk and next header */ if (*header == '\0') @@ -830,14 +828,14 @@ http_parse_chunked(struct http_connectio header[strcspn(header, ";\r\n")] = '\0'; errno = 0; chunksize = strtoul(header, &end, 16); - if (errno != 0 || header[0] == '\0' || *end != '\0' || - chunksize > INT_MAX) { + if (header[0] == '\0' || *end != '\0' || (errno == ERANGE && + chunksize == ULONG_MAX) || chunksize > INT_MAX) { warnx("%s: Invalid chunk size", http_info(conn->url)); return -1; } - conn->chunksz = chunksize; + conn->iosz = chunksize; - if (conn->chunksz == 0) { + if (conn->iosz == 0) { http_done(conn, HTTP_OK); return 0; } @@ -895,11 +893,11 @@ http_read(struct http_connection *conn) return WANT_POLLIN; case STATE_RESPONSE_DATA: if (conn->bufpos == conn->bufsz || - conn->filesize - conn->bytes <= (off_t)conn->bufpos) + conn->iosz <= (off_t)conn->bufpos) return 0; return WANT_POLLIN; case STATE_RESPONSE_CHUNKED: - while (conn->chunksz == 0) { + while (conn->iosz == 0) { buf = http_get_line(conn); if (buf == NULL) return WANT_POLLIN; @@ -915,7 +913,7 @@ http_read(struct http_connection *conn) } if (conn->bufpos == conn->bufsz || - conn->chunksz <= conn->bufpos) + conn->iosz <= (off_t)conn->bufpos) return 0; return WANT_POLLIN; default: @@ -970,53 +968,30 @@ data_write(struct http_connection *conn) ssize_t s; size_t bsz = conn->bufpos; - if (conn->filesize - conn->bytes < (off_t)bsz) - bsz = conn->filesize - conn->bytes; + if (conn->iosz < (off_t)bsz) + bsz = conn->iosz; s = write(conn->outfd, conn->buf, bsz); if (s == -1) { - warn("%s: Data write", http_info(conn->url)); + warn("%s: data write", http_info(conn->url)); return -1; } conn->bufpos -= s; - conn->bytes += s; + conn->iosz -= s; memmove(conn->buf, conn->buf + s, conn->bufpos); - if (conn->bytes == conn->filesize) { + /* check if regular file transfer is finished */ + if (conn->iosz == 0 && conn->chunked == 0) { http_done(conn, HTTP_OK); return 0; } - if (conn->bufpos == 0) - return 0; - - return WANT_POLLOUT; -} - -static int -chunk_write(struct http_connection *conn) -{ - ssize_t s; - size_t bsz = conn->bufpos; - - if (bsz > conn->chunksz) - bsz = conn->chunksz; - - s = write(conn->outfd, conn->buf, bsz); - if (s == -1) { - warn("%s: Chunk write", http_info(conn->url)); - return -1; - } - - conn->bufpos -= s; - conn->chunksz -= s; - conn->bytes += s; - memmove(conn->buf, conn->buf + s, conn->bufpos); - - if (conn->bufpos == 0 || conn->chunksz == 0) + /* all data written, switch back to read */ + if (conn->bufpos == 0 || conn->iosz == 0) return 0; + /* still more data to write in buffer */ return WANT_POLLOUT; } @@ -1041,10 +1016,7 @@ http_handle(struct http_connection *conn case STATE_RESPONSE_CHUNKED: return http_read(conn); case STATE_WRITE_DATA: - if (conn->chunked) - return chunk_write(conn); - else - return data_write(conn); + return data_write(conn); case STATE_DONE: return http_close(conn); case STATE_FREE: