Bound the bytes around chunk data in chunked transfer coding

The payload limit counts only chunk data, and a chunk-size line is only
bounded by the line length limit, so a peer could send a few bytes of
data with any amount of padding, leading zeros and chunk extensions
around them. Count those bytes as Go does: each chunk may spend 16
bytes plus twice its data on its size line and the CRLF after it, which
still lets a stream send a byte at a time, and the excess may build up
to CPPHTTPLIB_HEADER_MAX_LENGTH before the read fails. This covers
request bodies on the server and response bodies on the client.
This commit is contained in:
yhirose committed 2026-10-21 23:01:39 -04:00
1 parent 5bcfea7b90
commit 247a2abe4a
2 files changed
+58

No files matched your search

+10
View File
@@ -4019,6 +4019,7 @@ struct ChunkedDecoder {
char line_buf[64];
size_t last_chunk_total = 0;
size_t last_chunk_offset = 0;
size_t overhead = 0;
explicit ChunkedDecoder(Stream &s);
@@ -16113,6 +16114,15 @@ inline ssize_t ChunkedDecoder::read_payload(char *buf, size_t len,
if (!is_space_or_tab(*p) && !fields::is_field_vchar(*p)) { return -1; }
}
// The bytes around the data are no payload, so they are counted on their
// own, as Go does: each chunk may spend 16 bytes and twice its data on
// them, which lets a stream send a byte at a time, and what goes past that
// in padding, leading zeros and extensions builds up to one header field.
overhead += lr.size() + 2;
overhead = overhead > 16 ? overhead - 16 : 0;
overhead = chunk_len > overhead / 2 ? 0 : overhead - 2 * chunk_len;
if (overhead > CPPHTTPLIB_HEADER_MAX_LENGTH) { return -1; }
if (chunk_len == 0) {
chunk_remaining = 0;
finished = true;