diff --git a/mongoose.c b/mongoose.c index 76c630c7..a9c3b8d6 100644 --- a/mongoose.c +++ b/mongoose.c @@ -1,5 +1,5 @@ // Copyright (c) 2004-2013 Sergey Lyubka -// Copyright (c) 2013-2020 Cesanta Software Limited +// Copyright (c) 2013-2021 Cesanta Software Limited // All rights reserved // // This software is dual-licensed: you can redistribute it and/or modify @@ -15,7 +15,6 @@ // Alternatively, you can license this software under a commercial // license, as set out in . - #include "mongoose.h" #ifdef MG_ENABLE_LINES @@ -1189,7 +1188,7 @@ static size_t get_chunk_length(const char *buf, size_t len, size_t *ll) { // an MG_EV_HTTP_CHUNK event. static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, int reqlen) { - size_t off = 0, ll; + size_t off = 0, bl, ll; while (off < c->recv.len - reqlen) { char *buf = (char *) &c->recv.buf[reqlen]; size_t memo = c->recv.len; @@ -1201,10 +1200,22 @@ static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, // Increase offset only if user has not deleted this chunk if (memo == c->recv.len) off += cl; if (cl <= 5) { - // Zero chunk - last one. Set message length to indicate we've received + // Zero chunk - last one. Prepare body - cut off chunk lengths + off = bl = 0; + while (off < c->recv.len - reqlen) { + char *buf = (char *) &c->recv.buf[reqlen]; + size_t memo = c->recv.len; + size_t cl = get_chunk_length(&buf[off], memo - reqlen - off, &ll); + size_t n = cl < ll + 2 ? 0 : cl - ll - 2; + if (cl <= 5) break; + memmove(buf + bl, buf + off + ll, n); + bl += n; + off += cl; + } + // Set message length to indicate we've received // everything, to fire MG_EV_HTTP_MSG - hm->message.len = off + reqlen; - hm->body.len = off; + hm->message.len = bl + reqlen; + hm->body.len = bl; break; } } diff --git a/src/http.c b/src/http.c index 5b28b666..0245a6f3 100644 --- a/src/http.c +++ b/src/http.c @@ -769,7 +769,7 @@ static size_t get_chunk_length(const char *buf, size_t len, size_t *ll) { // an MG_EV_HTTP_CHUNK event. static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, int reqlen) { - size_t off = 0, ll; + size_t off = 0, bl, ll; while (off < c->recv.len - reqlen) { char *buf = (char *) &c->recv.buf[reqlen]; size_t memo = c->recv.len; @@ -781,10 +781,22 @@ static void walkchunks(struct mg_connection *c, struct mg_http_message *hm, // Increase offset only if user has not deleted this chunk if (memo == c->recv.len) off += cl; if (cl <= 5) { - // Zero chunk - last one. Set message length to indicate we've received + // Zero chunk - last one. Prepare body - cut off chunk lengths + off = bl = 0; + while (off < c->recv.len - reqlen) { + char *buf = (char *) &c->recv.buf[reqlen]; + size_t memo = c->recv.len; + size_t cl = get_chunk_length(&buf[off], memo - reqlen - off, &ll); + size_t n = cl < ll + 2 ? 0 : cl - ll - 2; + if (cl <= 5) break; + memmove(buf + bl, buf + off + ll, n); + bl += n; + off += cl; + } + // Set message length to indicate we've received // everything, to fire MG_EV_HTTP_MSG - hm->message.len = off + reqlen; - hm->body.len = off; + hm->message.len = bl + reqlen; + hm->body.len = bl; break; } } diff --git a/test/unit_test.c b/test/unit_test.c index d74e9e1a..ab9da266 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1231,7 +1231,7 @@ static void eh5(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { static void test_http_chunked(void) { struct mg_mgr mgr; - const char *url = "http://127.0.0.1:12344"; + const char *data, *url = "http://127.0.0.1:12344"; uint32_t i, done = 0; mg_mgr_init(&mgr); mg_http_listen(&mgr, url, eh2, NULL); @@ -1239,41 +1239,20 @@ 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); - { - const char *data = - "7\r\nchunk 0\r\n" - "7\r\nchunk 1\r\n" - "7\r\nchunk 2\r\n" - "0\r\n\r\n"; - ASSERT(done == mg_crc32(0, data, strlen(data))); - } + data = "chunk 0chunk 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); - { - const char *data = - "chunk 0" - "chunk 0" - "chunk 1" - "chunk 2" - "7\r\nchunk 0\r\n" - "7\r\nchunk 1\r\n" - "7\r\nchunk 2\r\n" - "0\r\n\r\n"; - ASSERT(done == mg_crc32(0, data, strlen(data))); - } + data = "chunk 0chunk 0chunk 1chunk 2chunk 0chunk 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); - { - const char *data = - "chunk 0" - "chunk 1" - "chunk 2"; - ASSERT(done == mg_crc32(0, data, strlen(data))); - } + data = "chunk 0chunk 1chunk 2"; + ASSERT(done == mg_crc32(0, data, strlen(data))); mg_mgr_free(&mgr); ASSERT(mgr.conns == NULL);