Skip to content

Commit

Permalink
tcp_proxy: ignore transfer encoding in HTTP/1.1 CONNECT responses (#1…
Browse files Browse the repository at this point in the history
…4623)

Commit Message: Ignore the transfer encoding header in CONNECT responses
Additional Description: NONE
Risk Level: low
Testing: integration test
Docs Changes: NONE
Release Notes: https://github.com/irozzo-1A/envoy/blob/ignore-transfer-encoding/docs/root/version_history/current.rst#new-features
Platform Specific Features: NONE
Fixes #11308

Signed-off-by: Iacopo Rozzo <[email protected]>
  • Loading branch information
irozzo-1A authored Jan 12, 2021
1 parent e9ffbc5 commit e53227e
Show file tree
Hide file tree
Showing 5 changed files with 20 additions and 21 deletions.
2 changes: 2 additions & 0 deletions docs/root/intro/arch_overview/http/upgrades.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ will synthesize 200 response headers, and then forward the TCP data as the HTTP
For an example of proxying connect, please see :repo:`configs/proxy_connect.yaml <configs/proxy_connect.yaml>`
For an example of terminating connect, please see :repo:`configs/terminate_connect.yaml <configs/terminate_connect.yaml>`

.. _tunneling-tcp-over-http:

Tunneling TCP over HTTP
^^^^^^^^^^^^^^^^^^^^^^^
Envoy also has support for tunneling raw TCP over HTTP CONNECT requests. Find
Expand Down
3 changes: 2 additions & 1 deletion docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Removed Config or Runtime

New Features
------------
* tcp_proxy: add support for converting raw TCP streams into HTTP/1.1 CONNECT requests. See :ref:`upgrade documentation <tunneling-tcp-over-http>` for details.

Deprecated
----------
----------
9 changes: 0 additions & 9 deletions source/common/http/http1/codec_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1212,15 +1212,6 @@ Envoy::StatusOr<int> ClientConnectionImpl::onHeadersComplete() {
pending_response_.value().encoder_.connectRequest()) {
ENVOY_CONN_LOG(trace, "codec entering upgrade mode for CONNECT response.", connection_);
handling_upgrade_ = true;

// For responses to connect requests, do not accept the chunked
// encoding header: https://tools.ietf.org/html/rfc7231#section-4.3.6
if (headers->TransferEncoding() &&
absl::EqualsIgnoreCase(headers->TransferEncoding()->value().getStringView(),
Headers::get().TransferEncodingValues.Chunked)) {
RETURN_IF_ERROR(sendProtocolError(Http1ResponseCodeDetails::get().InvalidTransferEncoding));
return codecProtocolError("http/1.1 protocol error: unsupported transfer encoding");
}
}

if (strict_1xx_and_204_headers_ && (parser_.status_code < 200 || parser_.status_code == 204)) {
Expand Down
11 changes: 7 additions & 4 deletions test/integration/integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1697,10 +1697,13 @@ TEST_P(IntegrationTest, ConnectWithChunkedBody) {
EXPECT_FALSE(absl::StrContains(data, "onnection")) << data;
ASSERT_TRUE(fake_upstream_connection->write(
"HTTP/1.1 200 OK\r\ntransfer-encoding: chunked\r\n\r\nb\r\nHello World\r\n0\r\n\r\n"));
// The response will be rejected because chunked headers are not allowed with CONNECT upgrades.
// Envoy will send a local reply due to the invalid upstream response.
tcp_client->waitForDisconnect(false);
EXPECT_TRUE(absl::StartsWith(tcp_client->data(), "HTTP/1.1 503 Service Unavailable\r\n"));
tcp_client->waitForData("\r\n\r\n", false);
EXPECT_TRUE(absl::StartsWith(tcp_client->data(), "HTTP/1.1 200 OK\r\n")) << tcp_client->data();
// Make sure the following payload is proxied without chunks or any other modifications.
ASSERT_TRUE(fake_upstream_connection->waitForData(
FakeRawConnection::waitForInexactMatch("\r\n\r\npayload"), &data));

tcp_client->close();
ASSERT_TRUE(fake_upstream_connection->waitForDisconnect());
}

Expand Down
16 changes: 9 additions & 7 deletions test/integration/tcp_tunneling_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -792,9 +792,7 @@ TEST_P(TcpTunnelingIntegrationTest, ContentLengthHeaderIgnoredHttp1) {
ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect());
}

// TODO(irozzo): temporarily disabled as a protocol error is thrown when
// transfer-encoding header is received in CONNECT responses.
TEST_P(TcpTunnelingIntegrationTest, DISABLED_TransferEncodingHeaderIgnoredHttp1) {
TEST_P(TcpTunnelingIntegrationTest, TransferEncodingHeaderIgnoredHttp1) {
if (upstreamProtocol() == FakeHttpConnection::Type::HTTP2) {
return;
}
Expand All @@ -812,13 +810,17 @@ TEST_P(TcpTunnelingIntegrationTest, DISABLED_TransferEncodingHeaderIgnoredHttp1)

// Send upgrade headers downstream, fully establishing the connection.
ASSERT_TRUE(
fake_upstream_connection->write("HTTP/1.1 299 OK\r\nTransfer-encoding: chunked\r\n\r\n"));
fake_upstream_connection->write("HTTP/1.1 200 OK\r\nTransfer-encoding: chunked\r\n\r\n"));

// Now send some data and close the TCP client.
ASSERT_TRUE(tcp_client->write("hello", false));
ASSERT_TRUE(tcp_client->write("hello"));
ASSERT_TRUE(
fake_upstream_connection->waitForData(FakeRawConnection::waitForInexactMatch("hello")));

// Close connections.
ASSERT_TRUE(fake_upstream_connection->close());
ASSERT_TRUE(fake_upstream_connection->waitForDisconnect());
tcp_client->close();
ASSERT_TRUE(upstream_request_->waitForData(*dispatcher_, 5));
ASSERT_TRUE(fake_upstream_connection_->waitForDisconnect());
}

TEST_P(TcpTunnelingIntegrationTest, DeferTransmitDataUntilSuccessConnectResponseIsReceived) {
Expand Down

0 comments on commit e53227e

Please sign in to comment.