Process chunked body before sending MG_EV_HTTP_MSG

This commit is contained in:
cpq 2021-03-09 08:21:29 +00:00
parent 2dcb10ef36
commit e84ea91a4a
3 changed files with 40 additions and 38 deletions

View File

@ -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 <https://www.cesanta.com/license>.
#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;
}
}

View File

@ -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;
}
}

View File

@ -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);