diff --git a/docs/root/intro/arch_overview/http/upgrades.rst b/docs/root/intro/arch_overview/http/upgrades.rst index 6a4338d39ee5..ba015ff838a9 100644 --- a/docs/root/intro/arch_overview/http/upgrades.rst +++ b/docs/root/intro/arch_overview/http/upgrades.rst @@ -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 ` For an example of terminating connect, please see :repo:`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 diff --git a/docs/root/version_history/current.rst b/docs/root/version_history/current.rst index bb04894db478..3ef7e0a8cd04 100644 --- a/docs/root/version_history/current.rst +++ b/docs/root/version_history/current.rst @@ -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 ` for details. Deprecated ----------- \ No newline at end of file +---------- diff --git a/source/common/http/http1/codec_impl.cc b/source/common/http/http1/codec_impl.cc index f0ce0cfb5f88..bbbff2035344 100644 --- a/source/common/http/http1/codec_impl.cc +++ b/source/common/http/http1/codec_impl.cc @@ -1212,15 +1212,6 @@ Envoy::StatusOr 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)) { diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index f662744274f9..70e19b7400b8 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -1645,10 +1645,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()); } diff --git a/test/integration/tcp_tunneling_integration_test.cc b/test/integration/tcp_tunneling_integration_test.cc index aef3d5f66fef..1369dfa79c81 100644 --- a/test/integration/tcp_tunneling_integration_test.cc +++ b/test/integration/tcp_tunneling_integration_test.cc @@ -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; } @@ -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) {