Sync picohttpparser.c with upstream commit a875a01

Pull in upstream commit a875a01 from h2o/picohttpparser: enforce use of
CRLF in chunk headers, by rejecting bare CR / LF. Replaces the lenient
CHUNKED_IN_CHUNK_CRLF state with strict CHUNKED_IN_CHUNK_HEADER_EXPECT_LF,
CHUNKED_IN_CHUNK_DATA_EXPECT_CR and CHUNKED_IN_CHUNK_DATA_EXPECT_LF states.

Synced with the h2o/picohttpparser upstream repository up to commit
f4d94b48b31e0abae029ebeafcfd9ca0680ede58.

This commit is just hygiene and consistency by keeping the vendored copy
current.

Assisted-by: Claude:claude-opus-4-7
This commit is contained in:
Michal Nowak 2026-06-01 16:37:12 +02:00 committed by Ondřej Surý
parent 88701b9112
commit cfd7fd867b

View file

@ -2,8 +2,6 @@
* Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
* Shigeo Mitsunari
*
* SPDX-License-Identifier: MIT
*
* The software is licensed under either the MIT License (below) or the Perl
* license.
*
@ -161,12 +159,11 @@ get_token_to_eol(const char *buf, const char *buf_end, const char **token,
/* find non-printable char within the next 8 bytes, this is the hottest
* code; manually inlined */
while (likely(buf_end - buf >= 8)) {
#define DOIT() \
do { \
if (unlikely(!IS_PRINTABLE_ASCII(*buf))) { \
goto NonPrintable; \
} \
++buf; \
#define DOIT() \
do { \
if (unlikely(!IS_PRINTABLE_ASCII(*buf))) \
goto NonPrintable; \
++buf; \
} while (0)
DOIT();
DOIT();
@ -444,7 +441,7 @@ phr_parse_request(const char *buf_start, size_t len, const char **method,
size_t *num_headers, size_t last_len) {
const char *buf = buf_start, *buf_end = buf_start + len;
size_t max_headers = *num_headers;
int r = -1;
int r;
*method = NULL;
*method_len = 0;
@ -580,8 +577,10 @@ phr_parse_headers(const char *buf_start, size_t len, struct phr_header *headers,
enum {
CHUNKED_IN_CHUNK_SIZE,
CHUNKED_IN_CHUNK_EXT,
CHUNKED_IN_CHUNK_HEADER_EXPECT_LF,
CHUNKED_IN_CHUNK_DATA,
CHUNKED_IN_CHUNK_CRLF,
CHUNKED_IN_CHUNK_DATA_EXPECT_CR,
CHUNKED_IN_CHUNK_DATA_EXPECT_LF,
CHUNKED_IN_TRAILERS_LINE_HEAD,
CHUNKED_IN_TRAILERS_LINE_MIDDLE
};
@ -646,7 +645,7 @@ phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf,
}
decoder->_hex_count = 0;
decoder->_state = CHUNKED_IN_CHUNK_EXT;
/* fall through */
/* fallthru */
case CHUNKED_IN_CHUNK_EXT:
/* RFC 7230 A.2 "Line folding in chunk extensions is
* disallowed" */
@ -654,11 +653,25 @@ phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf,
if (src == bufsz) {
goto Exit;
}
if (buf[src] == '\012') {
if (buf[src] == '\015') {
break;
} else if (buf[src] == '\012') {
ret = -1;
goto Exit;
}
}
++src;
decoder->_state = CHUNKED_IN_CHUNK_HEADER_EXPECT_LF;
/* fallthru */
case CHUNKED_IN_CHUNK_HEADER_EXPECT_LF:
if (src == bufsz) {
goto Exit;
}
if (buf[src] != '\012') {
ret = -1;
goto Exit;
}
++src;
if (decoder->bytes_left_in_chunk == 0) {
if (decoder->consume_trailer) {
decoder->_state =
@ -669,7 +682,7 @@ phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf,
}
}
decoder->_state = CHUNKED_IN_CHUNK_DATA;
/* fall through */
/* fallthru */
case CHUNKED_IN_CHUNK_DATA: {
size_t avail = bufsz - src;
if (avail < decoder->bytes_left_in_chunk) {
@ -688,17 +701,23 @@ phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf,
src += decoder->bytes_left_in_chunk;
dst += decoder->bytes_left_in_chunk;
decoder->bytes_left_in_chunk = 0;
decoder->_state = CHUNKED_IN_CHUNK_CRLF;
decoder->_state = CHUNKED_IN_CHUNK_DATA_EXPECT_CR;
}
/* fall through */
case CHUNKED_IN_CHUNK_CRLF:
for (;; ++src) {
if (src == bufsz) {
goto Exit;
}
if (buf[src] != '\015') {
break;
}
/* fallthru */
case CHUNKED_IN_CHUNK_DATA_EXPECT_CR:
if (src == bufsz) {
goto Exit;
}
if (buf[src] != '\015') {
ret = -1;
goto Exit;
}
++src;
decoder->_state = CHUNKED_IN_CHUNK_DATA_EXPECT_LF;
/* fallthru */
case CHUNKED_IN_CHUNK_DATA_EXPECT_LF:
if (src == bufsz) {
goto Exit;
}
if (buf[src] != '\012') {
ret = -1;
@ -720,7 +739,7 @@ phr_decode_chunked(struct phr_chunked_decoder *decoder, char *buf,
goto Complete;
}
decoder->_state = CHUNKED_IN_TRAILERS_LINE_MIDDLE;
/* fall through */
/* fallthru */
case CHUNKED_IN_TRAILERS_LINE_MIDDLE:
for (;; ++src) {
if (src == bufsz) {