Skip to content

Commit f2a190a

Browse files
hanidamlajmeta-codesync[bot]
authored andcommitted
HTTP1xCodec validate all transfer-encoding header values
Summary: * http_parser only allows "transfer-encoding" header names with "chunked" values, otherwise it does not treat the message as chunked (see https://fburl.com/code/662pef39) * HTTP1xCodec now prevents any "transfer-encoding" headers with value other than "chunked", or if duplicate "transfer-encoding" headers are present they must all be "chunked" Reviewed By: joanna-jo Differential Revision: D90215312 fbshipit-source-id: 0644e8e16dd66c9ea0446f6cba730589a44371d8
1 parent acbbaae commit f2a190a

File tree

2 files changed

+37
-27
lines changed

2 files changed

+37
-27
lines changed

proxygen/lib/http/codec/HTTP1xCodec.cpp

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,34 @@ void appendString(IOBufQueue& queue, size_t& len, StringPiece str) {
7474
len += str.size();
7575
}
7676

77+
using namespace proxygen;
78+
// discard messages with multiple content-length headers, if they differ
79+
// (t12767790)
80+
bool validateContentLen(const HTTPHeaders& hdrs) noexcept {
81+
const std::string* contentLen{nullptr};
82+
bool ok = !hdrs.forEachValueOfHeader(
83+
HTTP_HEADER_CONTENT_LENGTH, [&](const std::string& value) -> bool {
84+
if (!contentLen) {
85+
contentLen = &value;
86+
return false; // continue
87+
}
88+
return *contentLen != value; // stop if different
89+
});
90+
LOG_IF(ERROR, !ok) << "Invalid message, multiple Content-Length headers";
91+
return ok;
92+
}
93+
94+
// only supports transfer-encoding of "chunked" (identical to http_parser.cpp)
95+
bool validateTransferEncoding(const HTTPHeaders& hdrs) noexcept {
96+
bool ok = !hdrs.forEachValueOfHeader(
97+
HTTP_HEADER_TRANSFER_ENCODING, [&](folly::StringPiece value) -> bool {
98+
bool err = !value.equals(kChunked, folly::AsciiCaseInsensitive{});
99+
LOG_IF(ERROR, err) << "invalid transfer-encoding val=" << value;
100+
return err; // stop on err
101+
});
102+
return ok;
103+
}
104+
77105
} // anonymous namespace
78106

79107
namespace proxygen {
@@ -906,6 +934,7 @@ bool HTTP1xCodec::pushHeaderNameAndValue(HTTPHeaders& hdrs) {
906934
currentHeaderName_.clear();
907935
currentHeaderNameStringPiece_.clear();
908936
currentHeaderValue_.clear();
937+
909938
return true;
910939
}
911940

@@ -978,34 +1007,12 @@ int HTTP1xCodec::onHeadersComplete(size_t len) {
9781007
}
9791008
}
9801009

981-
// discard messages with folded or multiple valued Transfer-Encoding headers
982-
// ex : "chunked , zorg\r\n" or "\r\n chunked \r\n" (t12767790)
9831010
HTTPHeaders& hdrs = msg_->getHeaders();
984-
const std::string& headerVal =
985-
hdrs.getSingleOrEmpty(HTTP_HEADER_TRANSFER_ENCODING);
986-
if (!headerVal.empty() && !caseInsensitiveEqual(headerVal, kChunked)) {
987-
LOG(ERROR) << "Invalid Transfer-Encoding header. Value =" << headerVal;
1011+
if (!validateContentLen(hdrs)) {
9881012
return -1;
9891013
}
990-
991-
// discard messages with multiple content-length headers (t12767790)
992-
if (hdrs.getNumberOfValues(HTTP_HEADER_CONTENT_LENGTH) > 1) {
993-
// Only reject the message if the Content-Length headers have different
994-
// values
995-
folly::Optional<folly::StringPiece> contentLen;
996-
bool error = hdrs.forEachValueOfHeader(
997-
HTTP_HEADER_CONTENT_LENGTH, [&](folly::StringPiece value) -> bool {
998-
if (!contentLen.has_value()) {
999-
contentLen = value;
1000-
return false;
1001-
}
1002-
return (contentLen.value() != value);
1003-
});
1004-
1005-
if (error) {
1006-
LOG(ERROR) << "Invalid message, multiple Content-Length headers";
1007-
return -1;
1008-
}
1014+
if (!validateTransferEncoding(hdrs)) {
1015+
return -1;
10091016
}
10101017

10111018
// Update the HTTPMessage with the values parsed from the header

proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,8 +624,11 @@ TEST(HTTP1xCodecTest, TestBadTransferEncodingHeader) {
624624
folly::IOBufQueue writeBuf(folly::IOBufQueue::cacheChainLength());
625625

626626
auto reqBuf = folly::IOBuf::copyBuffer(
627-
"POST /www.facebook.com HTTP/1.1\r\nHost: www.facebook.com\r\n"
628-
"Transfer-Encoding: chunked, zorg\r\n\r\n");
627+
"POST /www.facebook.com HTTP/1.1\r\n"
628+
"Host: www.facebook.com\r\n"
629+
"Transfer-Encoding: chunked, zorg\r\n"
630+
"Transfer-Encoding: chunked, zorg\r\n"
631+
"\r\n");
629632
downstream.onIngress(*reqBuf);
630633

631634
// Check that the request fails before the codec finishes parsing the headers

0 commit comments

Comments
 (0)