From f6f0e49de4d06c0225223b4518afa3e30935e24c Mon Sep 17 00:00:00 2001 From: Kristof Havasi Date: Mon, 23 Aug 2021 08:19:46 +0200 Subject: [PATCH 1/2] Add failing test for HTTP chunk This test would have caught #1340: handling chunks longer than 15 chars --- test/unit_test.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/unit_test.c b/test/unit_test.c index 6f3604b4..0a89ebb6 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1207,12 +1207,14 @@ static void test_crc32(void) { ASSERT(mg_crc32(mg_crc32(0, "ab", 2), "c", 1) == 891568578); } +#define LONG_CHUNK "chunk with length taking up more than two hex digits" + // Streaming server event handler. // Send one chunk immediately, then drain, then send two chunks in one go static void eh2(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { if (ev == MG_EV_HTTP_MSG) { mg_printf(c, "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); - mg_http_printf_chunk(c, "chunk 0"); + mg_http_printf_chunk(c, LONG_CHUNK); c->label[0] = 1; } else if (ev == MG_EV_POLL) { if (c->label[0] > 0 && c->send.len == 0) c->label[0]++; @@ -1287,25 +1289,27 @@ static void test_http_chunked(void) { mg_http_connect(&mgr, url, eh3, &done); for (i = 0; i < 50 && done == 0; i++) mg_mgr_poll(&mgr, 1); ASSERT(i < 50); - data = "chunk 0chunk 1chunk 2"; + data = LONG_CHUNK "chunk 1chunk 2"; ASSERT(done == mg_crc32(0, data, strlen(data))); done = 0; mg_http_connect(&mgr, url, eh4, &done); for (i = 0; i < 50 && done == 0; i++) mg_mgr_poll(&mgr, 1); - data = "chunk 0chunk 0chunk 1chunk 2chunk 0chunk 1chunk 2"; + data = LONG_CHUNK LONG_CHUNK "chunk 1chunk 2" LONG_CHUNK "chunk 1chunk 2"; ASSERT(done == mg_crc32(0, data, strlen(data))); done = 0; mg_http_connect(&mgr, url, eh5, &done); for (i = 0; i < 50 && done == 0; i++) mg_mgr_poll(&mgr, 1); - data = "chunk 0chunk 1chunk 2"; + data = LONG_CHUNK "chunk 1chunk 2"; ASSERT(done == mg_crc32(0, data, strlen(data))); mg_mgr_free(&mgr); ASSERT(mgr.conns == NULL); } +#undef LONG_CHUNK + static void test_multipart(void) { struct mg_http_part part; size_t ofs; From 4d07a99ee2cd55e2cfe19eed49dd2a440c590a67 Mon Sep 17 00:00:00 2001 From: Kristof Havasi Date: Mon, 23 Aug 2021 08:40:35 +0200 Subject: [PATCH 2/2] Fix bug in long HTTP chunk handling Due to a copy/paste error, the start of the payload in the latest parsed chunk was compared to chunk-length of the terminating chunk (5 chars). So only chunks were parsed as expected, which also had a single hex digit length. --- mongoose.c | 2 +- src/http.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mongoose.c b/mongoose.c index 873090cd..4dc96c38 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1401,7 +1401,7 @@ static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, char *buf2 = (char *) &c->recv.buf[reqlen]; size_t memo2 = c->recv.len; size_t cl2 = get_chunk_length(&buf2[off], memo2 - reqlen - off, &ll); - size_t n = cl < ll + 2 ? 0 : cl2 - ll - 2; + size_t n = cl2 < ll + 2 ? 0 : cl2 - ll - 2; memmove(buf2 + bl, buf2 + off + ll, n); bl += n; off += cl2; diff --git a/src/http.c b/src/http.c index 2f045971..2411f30d 100644 --- a/src/http.c +++ b/src/http.c @@ -990,7 +990,7 @@ static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, char *buf2 = (char *) &c->recv.buf[reqlen]; size_t memo2 = c->recv.len; size_t cl2 = get_chunk_length(&buf2[off], memo2 - reqlen - off, &ll); - size_t n = cl < ll + 2 ? 0 : cl2 - ll - 2; + size_t n = cl2 < ll + 2 ? 0 : cl2 - ll - 2; memmove(buf2 + bl, buf2 + off + ll, n); bl += n; off += cl2;