From 96b8cb9542480358dd1607d321625fdced23d49e Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Tue, 21 Feb 2023 17:18:32 +0000 Subject: [PATCH] Switch to the Debian fork of the now-obsolete http_parser library. We should look to switching to its replacement (llhttp) in v4. --- vendor/README.md | 4 ++-- vendor/http_parser/http_parser.c | 36 ++++++++++++++++++++++---------- vendor/http_parser/http_parser.h | 6 ++++-- vendor/update.toml | 3 ++- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/vendor/README.md b/vendor/README.md index d1739cc45..1692b8b4f 100644 --- a/vendor/README.md +++ b/vendor/README.md @@ -18,9 +18,9 @@ This directory contains vendored dependencies that are shipped with InspIRCd to **License** — MIT License -**Version** — v2.9.4 +**Version** — debian/2.9.4-5 -**Website** — [https://github.com/nodejs/http-parser](https://github.com/nodejs/http-parser) +**Website** — [https://git.in-ulm.de/cbiedl/http-parser](https://git.in-ulm.de/cbiedl/http-parser) ## sha2 diff --git a/vendor/http_parser/http_parser.c b/vendor/http_parser/http_parser.c index 95ff42f78..e9b2b9e83 100644 --- a/vendor/http_parser/http_parser.c +++ b/vendor/http_parser/http_parser.c @@ -653,6 +653,8 @@ size_t http_parser_execute (http_parser *parser, const char *status_mark = 0; enum state p_state = (enum state) parser->state; const unsigned int lenient = parser->lenient_http_headers; + const unsigned int allow_chunked_length = parser->allow_chunked_length; + uint32_t nread = parser->nread; /* We're in an error state. Don't bother doing anything. */ @@ -731,7 +733,7 @@ reexecute: if (ch == CR || ch == LF) break; parser->flags = 0; - parser->extra_flags = 0; + parser->uses_transfer_encoding = 0; parser->content_length = ULLONG_MAX; if (ch == 'H') { @@ -769,7 +771,7 @@ reexecute: if (ch == CR || ch == LF) break; parser->flags = 0; - parser->extra_flags = 0; + parser->uses_transfer_encoding = 0; parser->content_length = ULLONG_MAX; if (ch == 'H') { @@ -927,7 +929,7 @@ reexecute: if (ch == CR || ch == LF) break; parser->flags = 0; - parser->extra_flags = 0; + parser->uses_transfer_encoding = 0; parser->content_length = ULLONG_MAX; if (UNLIKELY(!IS_ALPHA(ch))) { @@ -1341,7 +1343,14 @@ reexecute: parser->header_state = h_general; } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { parser->header_state = h_transfer_encoding; - parser->extra_flags |= F_TRANSFER_ENCODING >> 8; + parser->uses_transfer_encoding = 1; + + /* Multiple `Transfer-Encoding` headers should be treated as + * one, but with values separate by a comma. + * + * See: https://tools.ietf.org/html/rfc7230#section-3.2.2 + */ + parser->flags &= ~F_CHUNKED; } break; @@ -1801,14 +1810,19 @@ reexecute: REEXECUTE(); } - /* Cannot us transfer-encoding and a content-length header together + /* Cannot use transfer-encoding and a content-length header together per the HTTP specification. (RFC 7230 Section 3.3.3) */ - if ((parser->extra_flags & (F_TRANSFER_ENCODING >> 8)) && + if ((parser->uses_transfer_encoding == 1) && (parser->flags & F_CONTENTLENGTH)) { /* Allow it for lenient parsing as long as `Transfer-Encoding` is - * not `chunked` + * not `chunked` or allow_length_with_encoding is set */ - if (!lenient || (parser->flags & F_CHUNKED)) { + if (parser->flags & F_CHUNKED) { + if (!allow_chunked_length) { + SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); + goto error; + } + } else if (!lenient) { SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); goto error; } @@ -1889,7 +1903,7 @@ reexecute: /* chunked encoding - ignore Content-Length header, * prepare for a chunk */ UPDATE_STATE(s_chunk_size_start); - } else if (parser->extra_flags & (F_TRANSFER_ENCODING >> 8)) { + } else if (parser->uses_transfer_encoding == 1) { if (parser->type == HTTP_REQUEST && !lenient) { /* RFC 7230 3.3.3 */ @@ -2165,7 +2179,7 @@ http_message_needs_eof (const http_parser *parser) } /* RFC 7230 3.3.3, see `s_headers_almost_done` */ - if ((parser->extra_flags & (F_TRANSFER_ENCODING >> 8)) && + if ((parser->uses_transfer_encoding == 1) && (parser->flags & F_CHUNKED) == 0) { return 1; } @@ -2517,7 +2531,7 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, end = buf + off + len; /* NOTE: The characters are already validated and are in the [0-9] range */ - assert(off + len <= buflen && "Port number overflow"); + assert((size_t) (off + len) <= buflen && "Port number overflow"); v = 0; for (p = buf + off; p < end; p++) { v *= 10; diff --git a/vendor/http_parser/http_parser.h b/vendor/http_parser/http_parser.h index df8825260..0f71b9340 100644 --- a/vendor/http_parser/http_parser.h +++ b/vendor/http_parser/http_parser.h @@ -225,7 +225,6 @@ enum flags , F_UPGRADE = 1 << 5 , F_SKIPBODY = 1 << 6 , F_CONTENTLENGTH = 1 << 7 - , F_TRANSFER_ENCODING = 1 << 8 /* Never set in http_parser.flags */ }; @@ -300,7 +299,10 @@ struct http_parser { unsigned int state : 7; /* enum state from http_parser.c */ unsigned int header_state : 7; /* enum header_state from http_parser.c */ unsigned int index : 5; /* index into current matcher */ - unsigned int extra_flags : 2; + unsigned int uses_transfer_encoding : 1; /* Transfer-Encoding header is present */ + unsigned int allow_chunked_length : 1; /* Allow headers with both + * `Content-Length` and + * `Transfer-Encoding: chunked` set */ unsigned int lenient_http_headers : 1; uint32_t nread; /* # bytes read in various scenarios */ diff --git a/vendor/update.toml b/vendor/update.toml index 7cc24a72d..cf64f4312 100644 --- a/vendor/update.toml +++ b/vendor/update.toml @@ -10,8 +10,9 @@ website = "https://www.openwall.com/crypt/" [http_parser] author = "Joyent, Inc. and other Node contributors" files = "{http_parser.[ch],LICENSE-MIT}" -git = "https://github.com/nodejs/http-parser" +git = "https://git.in-ulm.de/cbiedl/http-parser" license = "MIT License" +patches = "debian/patches/*.patch" [sha2] author = "Olivier Gay"