diff --git a/proxygen/lib/http/codec/HTTP1xCodec.cpp b/proxygen/lib/http/codec/HTTP1xCodec.cpp index 6d4d668118..31518f53b7 100644 --- a/proxygen/lib/http/codec/HTTP1xCodec.cpp +++ b/proxygen/lib/http/codec/HTTP1xCodec.cpp @@ -1198,7 +1198,10 @@ int HTTP1xCodec::onHeadersComplete(size_t len) { ignoreBody = false; } else { is1xxResponse_ = msg_->is1xxResponse(); - if (expectNoResponseBody_) { + std::string contentLengthHeader = msg_->getHeaders().getSingleOrEmpty(HTTP_HEADER_CONTENT_LENGTH); + if (connectRequest_ && (msg_->is4xxResponse() || msg_->is5xxResponse()) && !contentLengthHeader.empty() && std::stol(contentLengthHeader) != 0) { + ignoreBody = false; + } else if (expectNoResponseBody_) { ignoreBody = true; } else { ignoreBody = RFC2616::responseBodyMustBeEmpty(msg_->getStatusCode()); diff --git a/proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp b/proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp index ba3b13cd0e..b934a90a65 100644 --- a/proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp +++ b/proxygen/lib/http/codec/test/HTTP1xCodecTest.cpp @@ -1530,6 +1530,79 @@ TEST(HTTP1xCodecTest, AbsoluteURLNoPath) { EXPECT_EQ(callbacks.msg_->getPathAsStringPiece(), string("/")); } +TEST(HTTP1xCodecTest, ConnectRequestSuccess) { + HTTP1xCodec codec(TransportDirection::UPSTREAM); + HTTP1xCodecCallback callbacks; + HTTPMessage req; + auto id = codec.createStream(); + req.setHTTPVersion(1, 1); + req.setMethod(HTTPMethod::CONNECT); + req.setURL("facebook.com:443"); + codec.setCallback(&callbacks); + folly::IOBufQueue buf; + codec.generateHeader(buf, id, req, true); + auto buffer = folly::IOBuf::copyBuffer( + string("HTTP/1.1 200 Connection established\r\n\r\n")); + codec.onIngress(*buffer); + EXPECT_EQ(callbacks.headersComplete, 1); + EXPECT_EQ(callbacks.bodyLen, 0); + EXPECT_EQ(callbacks.errors, 0); + EXPECT_EQ(callbacks.messageComplete, 1); +} + +TEST(HTTP1xCodecTest, ConnectRequestError) { + HTTP1xCodec codec(TransportDirection::UPSTREAM); + HTTP1xCodecCallback callbacks; + HTTPMessage req; + auto id = codec.createStream(); + req.setHTTPVersion(1, 1); + req.setMethod(HTTPMethod::CONNECT); + req.setURL("facebook.com:443"); + codec.setCallback(&callbacks); + folly::IOBufQueue buf; + codec.generateHeader(buf, id, req, true); + auto buffer = folly::IOBuf::copyBuffer(string("HTTP/1.1 407 Proxy Authentication Required\r\n" + "Content-Type: text/html;charset=utf-8\r\n" + "Content-Length: 165\r\n" + "Proxy-Authenticate: Basic\r\n" + "Proxy-Authenticate: NTLM\r\n" + "Connection: keep-alive\r\n" + "\r\n" + "ERROR: " + "Cache Access Denied

ERROR

" + "Cache Access Denied.

")); + codec.onIngress(*buffer); + EXPECT_EQ(callbacks.headersComplete, 1); + EXPECT_EQ(callbacks.bodyLen, 165); + EXPECT_EQ(callbacks.errors, 0); + EXPECT_EQ(callbacks.messageComplete, 1); +} + +TEST(HTTP1xCodecTest, ConnectRequestErrorWithoutBody) { + HTTP1xCodec codec(TransportDirection::UPSTREAM); + HTTP1xCodecCallback callbacks; + HTTPMessage req; + auto id = codec.createStream(); + req.setHTTPVersion(1, 1); + req.setMethod(HTTPMethod::CONNECT); + req.setURL("facebook.com:443"); + codec.setCallback(&callbacks); + folly::IOBufQueue buf; + codec.generateHeader(buf, id, req, true); + auto buffer = folly::IOBuf::copyBuffer(string("HTTP/1.1 407 Proxy Authentication Required\r\n" + "Content-Type: text/html;charset=utf-8\r\n" + "Proxy-Authenticate: Basic\r\n" + "Proxy-Authenticate: NTLM\r\n" + "Connection: keep-alive\r\n" + "\r\n")); + codec.onIngress(*buffer); + EXPECT_EQ(callbacks.headersComplete, 1); + EXPECT_EQ(callbacks.bodyLen, 0); + EXPECT_EQ(callbacks.errors, 0); + EXPECT_EQ(callbacks.messageComplete, 1); +} + class ConnectionHeaderTest : public TestWithParam, string>> { public: