From 4382aaf7361f4df07d89794c39f35261c56dc317 Mon Sep 17 00:00:00 2001 From: RajaMuhammadAwais <1.19938988e+08+RajaMuhammadAwais@users.noreply.github.com> Date: Thu, 27 Aug 2026 16:47:40 +0000 Subject: [PATCH] Normalize repeated carriage returns in headers --- src/proxy/hdrs/MIME.cc | 3 ++- src/proxy/hdrs/unit_tests/test_Hdrs.cc | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/proxy/hdrs/MIME.cc b/src/proxy/hdrs/MIME.cc index 9430385d42c..25e2cd43145 100644 --- a/src/proxy/hdrs/MIME.cc +++ b/src/proxy/hdrs/MIME.cc @@ -2509,7 +2509,8 @@ mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char } field_name.rtrim_if(&ParseRules::is_ws); raw_print_field = false; - } else if (parsed.suffix(2) != "\r\n") { + } else if (parsed.suffix(2) != "\r\n" || (parsed.size() > 2 && parsed[parsed.size() - 3] == '\r')) { + // Do not preserve malformed line endings when forwarding the field. raw_print_field = false; } diff --git a/src/proxy/hdrs/unit_tests/test_Hdrs.cc b/src/proxy/hdrs/unit_tests/test_Hdrs.cc index 71d52af9a23..7c00b3ca504 100644 --- a/src/proxy/hdrs/unit_tests/test_Hdrs.cc +++ b/src/proxy/hdrs/unit_tests/test_Hdrs.cc @@ -2983,6 +2983,32 @@ TEST_CASE("HTTP parser tolerates high-bit bytes without UB", "[proxy][hdrtest]") req_hdr.destroy(); } +TEST_CASE("HTTP parser normalizes repeated carriage returns in header line endings", "[proxy][hdrtest]") +{ + constexpr std::string_view message = "GET / HTTP/1.1\r\nHost: example.com\r\nExtra-CRs: \r\r\r\r\n\r\n"sv; + + HTTPParser parser; + http_parser_init(&parser); + + HTTPHdr req_hdr; + HdrHeap *heap = new_HdrHeap(HdrHeap::DEFAULT_SIZE + 64); + req_hdr.create(HTTPType::REQUEST, HTTP_1_1, heap); + + auto start = message.data(); + REQUIRE(req_hdr.parse_req(&parser, &start, message.data() + message.size(), true) == ParseResult::DONE); + + std::string serialized(static_cast(req_hdr.length_get()), '\0'); + int index = 0; + int offset = 0; + req_hdr.print(serialized.data(), static_cast(serialized.size()), &index, &offset); + serialized.resize(static_cast(index)); + + CHECK(serialized.find("Extra-CRs: \r\n") != std::string::npos); + CHECK(serialized.find("Extra-CRs: \r\r") == std::string::npos); + + req_hdr.destroy(); +} + TEST_CASE("HTTP response parser tolerates high-bit bytes without UB", "[proxy][hdrtest]") { struct Test {