From 8c4cdd9b21e07f17d6200f0bc883c29cc39be333 Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Wed, 20 Jul 2022 10:18:56 +0000 Subject: [PATCH] Fix statistics channel multiple request processing with non-empty bodies When the HTTP request has a body part after the HTTP headers, it is not getting processed and is being prepended to the next request's data, which results in an error when trying to parse it. Improve the httpd.c:process_request() function with the following additions: 1. Require that HTTP POST requests must have Content-Length header. 2. When Content-Length header is set, extract its value, and make sure that it is valid and that the whole request's body is received before processing the request. 3. Discard the request's body by consuming Content-Length worth of data in the buffer. --- lib/isc/httpd.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/isc/httpd.c b/lib/isc/httpd.c index 368b9cd2e1..b154b3aa6c 100644 --- a/lib/isc/httpd.c +++ b/lib/isc/httpd.c @@ -408,8 +408,10 @@ have_header(isc_httpd_t *httpd, const char *header, const char *value, static isc_result_t process_request(isc_httpd_t *httpd, isc_region_t *region, size_t *buflen) { char *s = NULL, *p = NULL, *urlend = NULL; + const char *content_length = NULL; size_t limit = sizeof(httpd->recvbuf) - httpd->recvlen - 1; size_t len = region->length; + size_t clen = 0; int delim; bool truncated = false; @@ -566,6 +568,29 @@ process_request(isc_httpd_t *httpd, isc_region_t *region, size_t *buflen) { httpd->headers = s; + if (!have_header(httpd, "Content-Length:", NULL, NULL, &content_length)) + { + /* Require a Content-Length header for POST requests. */ + if (httpd->method == METHOD_POST) { + return (ISC_R_BADNUMBER); + } + } else { + INSIST(content_length != NULL); + + clen = (size_t)strtoul(content_length, NULL, 10); + if (clen == ULONG_MAX) { + /* Invalid number in the header value. */ + return (ISC_R_BADNUMBER); + } + if (httpd->recvlen < httpd->consume + clen) { + /* The request data isn't complete yet. */ + return (ISC_R_NOTFOUND); + } + + /* Consume the request's data, which we do not use. */ + httpd->consume += clen; + } + if (have_header(httpd, "Connection:", "close", ", \t\r\n", NULL)) { httpd->flags |= HTTPD_CLOSE; }