commit 2216d3fb02772c0d13430959e9545ce4749bd4ce from: Omar Polo date: Thu Sep 07 16:58:59 2023 UTC amused-web: parse POST data in bufio' rbuf Add a proper upper limit (4096 seems enough for now) and safely NUL-terminate the rbuf. The idea is to later drop the clt->buf static buffer and allocate it on demand only when we need to do (http) chunking. commit - 2fbdef5f8f1cdbf19ffa1f58316b3987488cbb71 commit + 2216d3fb02772c0d13430959e9545ce4749bd4ce blob - 636cacdc9a1de01019b34182c0f749ab55c144b7 blob + d2b0020075d21db9c6ff1705fce193294e43735c --- web/bufio.c +++ web/bufio.c @@ -61,6 +61,18 @@ buf_grow(struct buffer *buf) return (-1); buf->buf = t; buf->cap = newcap; + return (0); +} + +int +buf_write(struct buffer *buf, const void *d, size_t len) +{ + if (buf->len + len > buf->cap) { + if (buf_grow(buf) == -1) + return (-1); + } + memcpy(buf->buf + buf->len, d, len); + buf->len += len; return (0); } blob - 823ac23e75511a2a22fa33bb96944c3ae2f5af79 blob + 98fdeb1d1412eae123638b65b2c840c85352e4ea --- web/bufio.h +++ web/bufio.h @@ -38,6 +38,7 @@ struct bufio { }; int buf_init(struct buffer *); +int buf_write(struct buffer *, const void *, size_t); int buf_has_line(struct buffer *, const char *); void buf_drain(struct buffer *, size_t); void buf_drain_line(struct buffer *, const char *); blob - 81940c551e893a3645608a3fafd9e2f336ac1577 blob + 1c29822b521c29a29a1855145d4fa50fae3d306e --- web/http.c +++ web/http.c @@ -46,6 +46,8 @@ #define nitems(x) (sizeof(x)/sizeof(x[0])) #endif +#define HTTP_MAX_UPLOAD 4096 + int http_init(struct client *clt, int fd) { @@ -125,7 +127,7 @@ http_parse(struct client *clt) if (!strncasecmp(line, "Content-Length:", 15)) { line += 15; line += strspn(line, " \t"); - clt->req.clen = strtonum(line, 0, LONG_MAX, + clt->req.clen = strtonum(line, 0, HTTP_MAX_UPLOAD, &errstr); if (errstr) { log_warnx("content-length is %s: %s", @@ -185,38 +187,38 @@ http_parse(struct client *clt) int http_read(struct client *clt) { - struct request *req = &clt->req; - size_t left; - size_t nr; + struct request *req = &clt->req; + struct buffer *rbuf = &clt->bio.rbuf; + size_t left; - if (req->clen > sizeof(clt->buf) - 1) { - log_warnx("POST has more data then what can be accepted"); - return -1; - } - /* clients may have sent more data than advertised */ - if (req->clen < clt->len) + if (req->clen < rbuf->len) left = 0; else - left = req->clen - clt->len; + left = req->clen - rbuf->len; if (left > 0) { - nr = bufio_drain(&clt->bio, clt->buf + clt->len, left); - clt->len += nr; - if (nr < left) { - errno = EAGAIN; - return -1; - } + errno = EAGAIN; + return -1; } - clt->buf[clt->len] = '\0'; - while (clt->len > 0 && (clt->buf[clt->len - 1] == '\r' || - (clt->buf[clt->len - 1] == '\n'))) - clt->buf[--clt->len] = '\0'; + buf_write(rbuf, "", 1); /* append a NUL byte */ + while (rbuf->len > 0 && (rbuf->buf[rbuf->len - 1] == '\r' || + (rbuf->buf[rbuf->len - 1] == '\n'))) + rbuf->buf[--rbuf->len] = '\0'; return 0; } +void +http_postdata(struct client *clt, char **data, size_t *len) +{ + if (data) + *data = clt->bio.rbuf.buf; + if (len) + *len = clt->bio.rbuf.len; +} + int http_reply(struct client *clt, int code, const char *reason, const char *ctype) blob - 2403eca6280267892002ab5278333b526468bfef blob + 781a9319946305f5b6e5d037ebe3cd9c85b16221 --- web/http.h +++ web/http.h @@ -73,6 +73,7 @@ struct client { int http_init(struct client *, int); int http_parse(struct client *); int http_read(struct client *); +void http_postdata(struct client *, char **, size_t *); int http_reply(struct client *, int, const char *, const char *); int http_flush(struct client *); int http_write(struct client *, const char *, size_t); blob - aeb504854f7188a8d1ac8eadbb17446f1ee7771e blob + 98cdd4168ca2bde0b1767982d8c8fb0616826e34 --- web/web.c +++ web/web.c @@ -673,7 +673,7 @@ route_jump(struct client *clt) char *form, *field; int found = 0; - form = clt->buf; + http_postdata(clt, &form, NULL); while ((field = strsep(&form, "&")) != NULL) { if (url_decode(field) == -1) goto badreq; @@ -713,7 +713,7 @@ route_controls(struct client *clt) char *form, *field; int cmd, found = 0; - form = clt->buf; + http_postdata(clt, &form, NULL); while ((field = strsep(&form, "&")) != NULL) { if (url_decode(field) == -1) goto badreq; @@ -762,7 +762,7 @@ route_mode(struct client *clt) pm.repeat_one = pm.repeat_all = pm.consume = MODE_UNDEF; - form = clt->buf; + http_postdata(clt, &form, NULL); while ((field = strsep(&form, "&")) != NULL) { if (url_decode(field) == -1) goto badreq;