From 87c2e187bf7fc0132febcd31c4fd61de57ee4522 Mon Sep 17 00:00:00 2001 From: Gaurav Karna Date: Fri, 2 Oct 2026 15:11:45 -0700 Subject: [PATCH] Conform to appropriate Content-Length values Summary: Reject malformed Content-Length values in the HTTP/1 codec before they can be framed leniently and forwarded verbatim. Reviewed By: hanidamlaj, samdlinn Differential Revision: D122834844 fbshipit-source-id: 73e1922a36bfd33b844f5aa44d09e36e40b57e37 --- proxygen/lib/http/codec/HTTP1xCodec.cpp | 7 +++- .../lib/http/codec/test/HTTP1xCodecTest.cpp | 37 ++++++++++--------- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/proxygen/lib/http/codec/HTTP1xCodec.cpp b/proxygen/lib/http/codec/HTTP1xCodec.cpp index 1c80a8d76..15836d785 100644 --- a/proxygen/lib/http/codec/HTTP1xCodec.cpp +++ b/proxygen/lib/http/codec/HTTP1xCodec.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -77,13 +78,17 @@ bool validateContentLen(const HTTPHeaders& hdrs) noexcept { const std::string* contentLen{nullptr}; bool ok = !hdrs.forEachValueOfHeader( HTTP_HEADER_CONTENT_LENGTH, [&](const std::string& value) -> bool { + if (folly::tryTo(value).hasError()) { + return true; + } if (!contentLen) { contentLen = &value; return false; // continue } return *contentLen != value; // stop if different }); - LOG_IF(ERROR, !ok) << "Invalid message, multiple Content-Length headers"; + LOG_IF(ERROR, !ok) + << "Invalid message, malformed or multiple Content-Length headers"; return ok; } diff --git a/proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp b/proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp index a65df8cb6..d3bae0c85 100644 --- a/proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp +++ b/proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp @@ -592,25 +592,26 @@ TEST(HTTP1xCodecTest, TestMultipleIdenticalContentLengthHeaders) { EXPECT_EQ(callbacks.headersComplete, 1); } -TEST(HTTP1xCodecTest, TestMultipleDistinctContentLengthHeaders) { - HTTP1xCodec codec(TransportDirection::DOWNSTREAM); - FakeHTTPCodecCallback callbacks; - codec.setCallback(&callbacks); - folly::IOBufQueue writeBuf(folly::IOBufQueue::cacheChainLength()); +TEST(HTTP1xCodecTest, TestInvalidContentLengthHeaders) { + for (auto contentLength : {"5\r\nContent-Length: 6", "1 2", "1\r\n 2"}) { + SCOPED_TRACE(contentLength); + HTTP1xCodec codec(TransportDirection::DOWNSTREAM); + FakeHTTPCodecCallback callbacks; + codec.setCallback(&callbacks); + auto reqBuf = folly::IOBuf::copyBuffer(folly::to( + "POST /www.facebook.com HTTP/1.1\r\nHost: www.facebook.com\r\n" + "Content-Length: ", + contentLength, + "\r\n\r\n")); + codec.onIngress(*reqBuf); - // Generate a POST request with two distinct Content-Length headers - auto reqBuf = folly::IOBuf::copyBuffer( - "POST /www.facebook.com HTTP/1.1\r\nHost: www.facebook.com\r\n" - "Content-Length: 5\r\nContent-Length: 6\r\n\r\n"); - codec.onIngress(*reqBuf); - - // Check that the request fails before the codec finishes parsing the headers - EXPECT_EQ(callbacks.streamErrors, 1); - EXPECT_EQ(callbacks.messageBegin, 1); - EXPECT_EQ(callbacks.headersComplete, 0); - EXPECT_EQ(callbacks.lastParseError->getHttpStatusCode(), 400); - EXPECT_THAT(callbacks.lastParseError->what(), - HasSubstr("[Context]=invalid-content-length")); + EXPECT_EQ(callbacks.streamErrors, 1); + EXPECT_EQ(callbacks.messageBegin, 1); + EXPECT_EQ(callbacks.headersComplete, 0); + EXPECT_EQ(callbacks.lastParseError->getHttpStatusCode(), 400); + EXPECT_THAT(callbacks.lastParseError->what(), + HasSubstr("[Context]=invalid-content-length")); + } } TEST(HTTP1xCodecTest, TestCorrectTransferEncodingHeader) {