From c45b1ad95d6273fe1243aa8c66863f8fee3ce626 Mon Sep 17 00:00:00 2001 From: tangxinfa Date: Thu, 16 Nov 2017 20:07:50 +0800 Subject: [PATCH 1/6] websocket: Connection http header may contain multiple values firefox's Connection header value is: keep-alive, Upgrade Signed-off-by: tangxinfa --- source/common/http/utility.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index f6112d1ae5ed..ccb3fdc95ab6 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -185,9 +185,7 @@ bool Utility::isInternalRequest(const HeaderMap& headers) { bool Utility::isWebSocketUpgradeRequest(const HeaderMap& headers) { return (headers.Connection() && headers.Upgrade() && - (0 == StringUtil::caseInsensitiveCompare( - headers.Connection()->value().c_str(), - Http::Headers::get().ConnectionValues.Upgrade.c_str())) && + (NULL != strcasestr(headers.Connection()->value().c_str(), Http::Headers::get().ConnectionValues.Upgrade.c_str())) && (0 == StringUtil::caseInsensitiveCompare( headers.Upgrade()->value().c_str(), Http::Headers::get().UpgradeValues.WebSocket.c_str()))); From d11de77d54e4090053562cff968c14b3ad2f8080 Mon Sep 17 00:00:00 2001 From: tangxinfa Date: Sun, 19 Nov 2017 09:46:29 +0800 Subject: [PATCH 2/6] websocket: add tests Signed-off-by: tangxinfa --- include/envoy/http/header_map.h | 22 ++++++++++++++++++++++ source/common/http/utility.cc | 5 ++++- test/common/http/header_map_impl_test.cc | 13 +++++++++++++ test/integration/integration_test.cc | 24 ++++++++++++------------ 4 files changed, 51 insertions(+), 13 deletions(-) diff --git a/include/envoy/http/header_map.h b/include/envoy/http/header_map.h index 806ecdd17801..80d9d37c7dff 100644 --- a/include/envoy/http/header_map.h +++ b/include/envoy/http/header_map.h @@ -102,6 +102,28 @@ class HeaderString { */ bool find(const char* str) const { return strstr(c_str(), str); } + /** + * HeaderString is in token list form, each token separated by commas or whitespace, + * see https://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.1 for more information, + * header field value's case sensitivity depends on each header. + * @return whether contains token in case insensitive manner. + */ + bool caseInsensitiveContains(const char* token) const { + const int n = strlen(token); + if (n == 0) { + return true; + } + const char* tokens = c_str(); + const char* separators = " ,"; + for (const char* p = tokens; (p = strcasestr(p, token)); p += n) { + if ((p == tokens || strchr(separators, *(p - 1)) != NULL) && + (*(p + n) == '\0' || strchr(separators, *(p + n)) != NULL)) { + return true; + } + } + return false; + } + /** * Set the value of the string by copying data into it. This overwrites any existing string. */ diff --git a/source/common/http/utility.cc b/source/common/http/utility.cc index ccb3fdc95ab6..9976aa0895da 100644 --- a/source/common/http/utility.cc +++ b/source/common/http/utility.cc @@ -184,8 +184,11 @@ bool Utility::isInternalRequest(const HeaderMap& headers) { } bool Utility::isWebSocketUpgradeRequest(const HeaderMap& headers) { + // In firefox the "Connection" request header value is "keep-alive, Upgrade", + // we should check if it contains the "Upgrade" token. return (headers.Connection() && headers.Upgrade() && - (NULL != strcasestr(headers.Connection()->value().c_str(), Http::Headers::get().ConnectionValues.Upgrade.c_str())) && + headers.Connection()->value().caseInsensitiveContains( + Http::Headers::get().ConnectionValues.Upgrade.c_str()) && (0 == StringUtil::caseInsensitiveCompare( headers.Upgrade()->value().c_str(), Http::Headers::get().UpgradeValues.WebSocket.c_str()))); diff --git a/test/common/http/header_map_impl_test.cc b/test/common/http/header_map_impl_test.cc index 34c445f6d1be..bd6c87b61332 100644 --- a/test/common/http/header_map_impl_test.cc +++ b/test/common/http/header_map_impl_test.cc @@ -258,6 +258,19 @@ TEST(HeaderStringTest, All) { EXPECT_EQ(11U, string.size()); EXPECT_EQ(HeaderString::Type::Reference, string.type()); } + + // caseInsensitiveContains + { + std::string static_string("keep-alive, Upgrade"); + HeaderString string(static_string); + EXPECT_TRUE(string.caseInsensitiveContains("keep-alive")); + EXPECT_TRUE(string.caseInsensitiveContains("Keep-alive")); + EXPECT_TRUE(string.caseInsensitiveContains("Upgrade")); + EXPECT_TRUE(string.caseInsensitiveContains("upgrade")); + EXPECT_FALSE(string.caseInsensitiveContains("keep")); + EXPECT_FALSE(string.caseInsensitiveContains("alive")); + EXPECT_FALSE(string.caseInsensitiveContains("grade")); + } } TEST(HeaderMapImplTest, InlineInsert) { diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index 9d19724044d3..896e9e15341f 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -193,31 +193,31 @@ TEST_P(IntegrationTest, WebSocketConnectionDownstreamDisconnect) { IntegrationTcpClientPtr tcp_client; FakeRawConnectionPtr fake_upstream_connection; const std::string upgrade_req_str = "GET /websocket/test HTTP/1.1\r\nHost: host\r\nConnection: " - "Upgrade\r\nUpgrade: websocket\r\n\r\n"; + "keep-alive, Upgrade\r\nUpgrade: websocket\r\n\r\n"; const std::string upgrade_resp_str = "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n"; tcp_client = makeTcpConnection(lookupPort("http")); // Send websocket upgrade request // The request path gets rewritten from /websocket/test to /websocket. - // The size of headers received by the destination is 225 bytes. + // The size of headers received by the destination is 228 bytes. tcp_client->write(upgrade_req_str); fake_upstream_connection = fake_upstreams_[0]->waitForRawConnection(); - fake_upstream_connection->waitForData(225); + fake_upstream_connection->waitForData(228); // Accept websocket upgrade request fake_upstream_connection->write(upgrade_resp_str); tcp_client->waitForData(upgrade_resp_str); // Standard TCP proxy semantics post upgrade tcp_client->write("hello"); - // datalen = 225 + strlen(hello) - fake_upstream_connection->waitForData(230); + // datalen = 228 + strlen(hello) + fake_upstream_connection->waitForData(233); fake_upstream_connection->write("world"); tcp_client->waitForData(upgrade_resp_str + "world"); tcp_client->write("bye!"); // downstream disconnect tcp_client->close(); - // datalen = 225 + strlen(hello) + strlen(bye!) - fake_upstream_connection->waitForData(234); + // datalen = 228 + strlen(hello) + strlen(bye!) + fake_upstream_connection->waitForData(237); fake_upstream_connection->waitForDisconnect(); } @@ -230,7 +230,7 @@ TEST_P(IntegrationTest, WebSocketConnectionUpstreamDisconnect) { IntegrationTcpClientPtr tcp_client; FakeRawConnectionPtr fake_upstream_connection; const std::string upgrade_req_str = "GET /websocket/test HTTP/1.1\r\nHost: host\r\nConnection: " - "Upgrade\r\nUpgrade: websocket\r\n\r\n"; + "keep-alive, Upgrade\r\nUpgrade: websocket\r\n\r\n"; const std::string upgrade_resp_str = "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\r\n"; tcp_client = makeTcpConnection(lookupPort("http")); @@ -238,15 +238,15 @@ TEST_P(IntegrationTest, WebSocketConnectionUpstreamDisconnect) { tcp_client->write(upgrade_req_str); fake_upstream_connection = fake_upstreams_[0]->waitForRawConnection(); // The request path gets rewritten from /websocket/test to /websocket. - // The size of headers received by the destination is 225 bytes. - fake_upstream_connection->waitForData(225); + // The size of headers received by the destination is 228 bytes. + fake_upstream_connection->waitForData(228); // Accept websocket upgrade request fake_upstream_connection->write(upgrade_resp_str); tcp_client->waitForData(upgrade_resp_str); // Standard TCP proxy semantics post upgrade tcp_client->write("hello"); - // datalen = 225 + strlen(hello) - fake_upstream_connection->waitForData(230); + // datalen = 228 + strlen(hello) + fake_upstream_connection->waitForData(233); fake_upstream_connection->write("world"); // upstream disconnect fake_upstream_connection->close(); From 4ffbe412b6021c7b3c4171e5725a8a603ac0736a Mon Sep 17 00:00:00 2001 From: tangxinfa Date: Sun, 19 Nov 2017 10:37:40 +0800 Subject: [PATCH 3/6] websocket: avoid mistakenly add "transfer-encoding: chunked" header Signed-off-by: tangxinfa --- source/common/http/conn_manager_utility.cc | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/source/common/http/conn_manager_utility.cc b/source/common/http/conn_manager_utility.cc index 89dadb738231..6d9a3b8bb842 100644 --- a/source/common/http/conn_manager_utility.cc +++ b/source/common/http/conn_manager_utility.cc @@ -22,18 +22,31 @@ void ConnectionManagerUtility::mutateRequestHeaders( Runtime::RandomGenerator& random, Runtime::Loader& runtime, const LocalInfo::LocalInfo& local_info) { // Clean proxy headers. - request_headers.removeEnvoyInternalRequest(); - request_headers.removeKeepAlive(); - request_headers.removeProxyConnection(); - request_headers.removeTransferEncoding(); // If this is a WebSocket Upgrade request, do not remove the Connection and Upgrade headers, // as we forward them verbatim to the upstream hosts. - if (protocol != Protocol::Http11 || !Utility::isWebSocketUpgradeRequest(request_headers)) { + if (protocol == Protocol::Http11 && Utility::isWebSocketUpgradeRequest(request_headers)) { + // Current WebSocket implementation re-use the HTTP1 codec to send upgrade headers to + // upstream host, which add "transfer-encoding: chunked" request header if stream not end + // and content-length not exists. + // In HTTP1.1, if transfer-encoding and content-length both not exists means no request body, + // after transfer-encoding striped here, the upstream request become invalid: + // chunked encoding with no request body. + // We can fix it by explicitly add a "content-length: 0" request header here. + bool no_body = (!request_headers.TransferEncoding() && !request_headers.ContentLength()); + if (no_body) { + request_headers.insertContentLength().value(uint64_t(0)); + } + } else { request_headers.removeConnection(); request_headers.removeUpgrade(); } + request_headers.removeEnvoyInternalRequest(); + request_headers.removeKeepAlive(); + request_headers.removeProxyConnection(); + request_headers.removeTransferEncoding(); + // If we are "using remote address" this means that we create/append to XFF with our immediate // peer. Cases where we don't "use remote address" include trusted double proxy where we expect // our peer to have already properly set XFF, etc. From 4913e34270cc336bcde1ad70a5ee5eb2f7b39a7b Mon Sep 17 00:00:00 2001 From: tangxinfa Date: Mon, 20 Nov 2017 13:37:01 +0800 Subject: [PATCH 4/6] websocket: fix comments and tests Signed-off-by: tangxinfa --- include/envoy/http/header_map.h | 9 ++++++--- source/common/http/conn_manager_utility.cc | 15 +++++++-------- test/common/http/header_map_impl_test.cc | 5 ++++- test/integration/fake_upstream.cc | 3 ++- test/integration/fake_upstream.h | 2 +- test/integration/integration_test.cc | 12 ++++++++++-- 6 files changed, 30 insertions(+), 16 deletions(-) diff --git a/include/envoy/http/header_map.h b/include/envoy/http/header_map.h index 80d9d37c7dff..0bc66515d87c 100644 --- a/include/envoy/http/header_map.h +++ b/include/envoy/http/header_map.h @@ -109,18 +109,21 @@ class HeaderString { * @return whether contains token in case insensitive manner. */ bool caseInsensitiveContains(const char* token) const { + // Avoid dead loop if token argument is empty. const int n = strlen(token); if (n == 0) { return true; } + + // Find token substring, skip if it's partial of other token. const char* tokens = c_str(); - const char* separators = " ,"; for (const char* p = tokens; (p = strcasestr(p, token)); p += n) { - if ((p == tokens || strchr(separators, *(p - 1)) != NULL) && - (*(p + n) == '\0' || strchr(separators, *(p + n)) != NULL)) { + if ((p == tokens || *(p - 1) == ' ' || *(p - 1) == ',') && + (*(p + n) == '\0' || *(p + n) == ' ' || *(p + n) == ',')) { return true; } } + return false; } diff --git a/source/common/http/conn_manager_utility.cc b/source/common/http/conn_manager_utility.cc index 6d9a3b8bb842..30108f7982cc 100644 --- a/source/common/http/conn_manager_utility.cc +++ b/source/common/http/conn_manager_utility.cc @@ -26,14 +26,13 @@ void ConnectionManagerUtility::mutateRequestHeaders( // If this is a WebSocket Upgrade request, do not remove the Connection and Upgrade headers, // as we forward them verbatim to the upstream hosts. if (protocol == Protocol::Http11 && Utility::isWebSocketUpgradeRequest(request_headers)) { - // Current WebSocket implementation re-use the HTTP1 codec to send upgrade headers to - // upstream host, which add "transfer-encoding: chunked" request header if stream not end - // and content-length not exists. - // In HTTP1.1, if transfer-encoding and content-length both not exists means no request body, - // after transfer-encoding striped here, the upstream request become invalid: - // chunked encoding with no request body. - // We can fix it by explicitly add a "content-length: 0" request header here. - bool no_body = (!request_headers.TransferEncoding() && !request_headers.ContentLength()); + // The current WebSocket implementation re-uses the HTTP1 codec to send upgrade headers to + // the upstream host. This adds the "transfer-encoding: chunked" request header if the stream + // has not ended and content-length does not exist. In HTTP1.1, if transfer-encoding and + // content-length both do not exist this means there is no request body. After transfer-encoding + // is stripped here, the upstream request becomes invalid. We can fix it by explicitly adding a + // "content-length: 0" request header here. + const bool no_body = (!request_headers.TransferEncoding() && !request_headers.ContentLength()); if (no_body) { request_headers.insertContentLength().value(uint64_t(0)); } diff --git a/test/common/http/header_map_impl_test.cc b/test/common/http/header_map_impl_test.cc index bd6c87b61332..11d4507cd084 100644 --- a/test/common/http/header_map_impl_test.cc +++ b/test/common/http/header_map_impl_test.cc @@ -261,12 +261,15 @@ TEST(HeaderStringTest, All) { // caseInsensitiveContains { - std::string static_string("keep-alive, Upgrade"); + std::string static_string("keep-alive, Upgrade, close"); HeaderString string(static_string); EXPECT_TRUE(string.caseInsensitiveContains("keep-alive")); EXPECT_TRUE(string.caseInsensitiveContains("Keep-alive")); EXPECT_TRUE(string.caseInsensitiveContains("Upgrade")); EXPECT_TRUE(string.caseInsensitiveContains("upgrade")); + EXPECT_TRUE(string.caseInsensitiveContains("close")); + EXPECT_TRUE(string.caseInsensitiveContains("Close")); + EXPECT_TRUE(string.caseInsensitiveContains("")); EXPECT_FALSE(string.caseInsensitiveContains("keep")); EXPECT_FALSE(string.caseInsensitiveContains("alive")); EXPECT_FALSE(string.caseInsensitiveContains("grade")); diff --git a/test/integration/fake_upstream.cc b/test/integration/fake_upstream.cc index b523d84de2be..42261b8fbfe2 100644 --- a/test/integration/fake_upstream.cc +++ b/test/integration/fake_upstream.cc @@ -364,12 +364,13 @@ FakeRawConnectionPtr FakeUpstream::waitForRawConnection() { return connection; } -void FakeRawConnection::waitForData(uint64_t num_bytes) { +std::string FakeRawConnection::waitForData(uint64_t num_bytes) { std::unique_lock lock(lock_); while (data_.size() != num_bytes) { ENVOY_LOG(debug, "waiting for {} bytes of data", num_bytes); connection_event_.wait(lock); } + return data_; } void FakeRawConnection::write(const std::string& data) { diff --git a/test/integration/fake_upstream.h b/test/integration/fake_upstream.h index ee85810c0b27..999c26043ac5 100644 --- a/test/integration/fake_upstream.h +++ b/test/integration/fake_upstream.h @@ -252,7 +252,7 @@ class FakeRawConnection : Logger::Loggable, public FakeConn connection_.addReadFilter(Network::ReadFilterSharedPtr{new ReadFilter(*this)}); } - void waitForData(uint64_t num_bytes); + std::string waitForData(uint64_t num_bytes); void write(const std::string& data); private: diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index 896e9e15341f..b1c8f8f781f0 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -203,7 +203,11 @@ TEST_P(IntegrationTest, WebSocketConnectionDownstreamDisconnect) { // The size of headers received by the destination is 228 bytes. tcp_client->write(upgrade_req_str); fake_upstream_connection = fake_upstreams_[0]->waitForRawConnection(); - fake_upstream_connection->waitForData(228); + const std::string data = fake_upstream_connection->waitForData(228); + // The chunked transfer-encoding for no body upstream request must valid + if (std::string::npos != data.find("transfer-encoding: chunked")) { + EXPECT_NE(std::string::npos, data.find("\r\n\r\n0\r\n")); + } // Accept websocket upgrade request fake_upstream_connection->write(upgrade_resp_str); tcp_client->waitForData(upgrade_resp_str); @@ -239,7 +243,11 @@ TEST_P(IntegrationTest, WebSocketConnectionUpstreamDisconnect) { fake_upstream_connection = fake_upstreams_[0]->waitForRawConnection(); // The request path gets rewritten from /websocket/test to /websocket. // The size of headers received by the destination is 228 bytes. - fake_upstream_connection->waitForData(228); + const std::string data = fake_upstream_connection->waitForData(228); + // The chunked transfer-encoding for no body upstream request must valid + if (std::string::npos != data.find("transfer-encoding: chunked")) { + EXPECT_NE(std::string::npos, data.find("\r\n\r\n0\r\n")); + } // Accept websocket upgrade request fake_upstream_connection->write(upgrade_resp_str); tcp_client->waitForData(upgrade_resp_str); From 8d1b113785df1a7abce0c1b223c9cb078e7e91fe Mon Sep 17 00:00:00 2001 From: tangxinfa Date: Tue, 21 Nov 2017 01:46:26 +0800 Subject: [PATCH 5/6] websocket: fix comments and tests Signed-off-by: tangxinfa --- include/envoy/http/header_map.h | 2 +- test/common/http/header_map_impl_test.cc | 13 +++++++++++-- test/integration/integration_test.cc | 18 ++++++++++-------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/include/envoy/http/header_map.h b/include/envoy/http/header_map.h index 0bc66515d87c..1c5088a28302 100644 --- a/include/envoy/http/header_map.h +++ b/include/envoy/http/header_map.h @@ -112,7 +112,7 @@ class HeaderString { // Avoid dead loop if token argument is empty. const int n = strlen(token); if (n == 0) { - return true; + return false; } // Find token substring, skip if it's partial of other token. diff --git a/test/common/http/header_map_impl_test.cc b/test/common/http/header_map_impl_test.cc index 11d4507cd084..751fd9a38f3e 100644 --- a/test/common/http/header_map_impl_test.cc +++ b/test/common/http/header_map_impl_test.cc @@ -261,7 +261,7 @@ TEST(HeaderStringTest, All) { // caseInsensitiveContains { - std::string static_string("keep-alive, Upgrade, close"); + const std::string static_string("keep-alive, Upgrade, close"); HeaderString string(static_string); EXPECT_TRUE(string.caseInsensitiveContains("keep-alive")); EXPECT_TRUE(string.caseInsensitiveContains("Keep-alive")); @@ -269,10 +269,19 @@ TEST(HeaderStringTest, All) { EXPECT_TRUE(string.caseInsensitiveContains("upgrade")); EXPECT_TRUE(string.caseInsensitiveContains("close")); EXPECT_TRUE(string.caseInsensitiveContains("Close")); - EXPECT_TRUE(string.caseInsensitiveContains("")); + EXPECT_FALSE(string.caseInsensitiveContains("")); EXPECT_FALSE(string.caseInsensitiveContains("keep")); EXPECT_FALSE(string.caseInsensitiveContains("alive")); EXPECT_FALSE(string.caseInsensitiveContains("grade")); + + const std::string small("close"); + string.setCopy(small.c_str(), small.size()); + EXPECT_FALSE(string.caseInsensitiveContains("keep-alive")); + + const std::string empty(""); + string.setCopy(empty.c_str(), empty.size()); + EXPECT_FALSE(string.caseInsensitiveContains("keep-alive")); + EXPECT_FALSE(string.caseInsensitiveContains("")); } } diff --git a/test/integration/integration_test.cc b/test/integration/integration_test.cc index b1c8f8f781f0..2f4a547d9c25 100644 --- a/test/integration/integration_test.cc +++ b/test/integration/integration_test.cc @@ -204,10 +204,11 @@ TEST_P(IntegrationTest, WebSocketConnectionDownstreamDisconnect) { tcp_client->write(upgrade_req_str); fake_upstream_connection = fake_upstreams_[0]->waitForRawConnection(); const std::string data = fake_upstream_connection->waitForData(228); - // The chunked transfer-encoding for no body upstream request must valid - if (std::string::npos != data.find("transfer-encoding: chunked")) { - EXPECT_NE(std::string::npos, data.find("\r\n\r\n0\r\n")); - } + // In HTTP1, the transfer-length is defined by use of the "chunked" transfer-coding, even if + // content-length header is present. No body websocket upgrade request send to upstream has + // content-length header and has no transfer-encoding header. + EXPECT_NE(data.find("content-length:"), std::string::npos); + EXPECT_EQ(data.find("transfer-encoding:"), std::string::npos); // Accept websocket upgrade request fake_upstream_connection->write(upgrade_resp_str); tcp_client->waitForData(upgrade_resp_str); @@ -244,10 +245,11 @@ TEST_P(IntegrationTest, WebSocketConnectionUpstreamDisconnect) { // The request path gets rewritten from /websocket/test to /websocket. // The size of headers received by the destination is 228 bytes. const std::string data = fake_upstream_connection->waitForData(228); - // The chunked transfer-encoding for no body upstream request must valid - if (std::string::npos != data.find("transfer-encoding: chunked")) { - EXPECT_NE(std::string::npos, data.find("\r\n\r\n0\r\n")); - } + // In HTTP1, the transfer-length is defined by use of the "chunked" transfer-coding, even if + // content-length header is present. No body websocket upgrade request send to upstream has + // content-length header and has no transfer-encoding header. + EXPECT_NE(data.find("content-length:"), std::string::npos); + EXPECT_EQ(data.find("transfer-encoding:"), std::string::npos); // Accept websocket upgrade request fake_upstream_connection->write(upgrade_resp_str); tcp_client->waitForData(upgrade_resp_str); From f922cb8cb7630c67570d4bd645b9917d75cb4861 Mon Sep 17 00:00:00 2001 From: tangxinfa Date: Tue, 21 Nov 2017 07:30:14 +0800 Subject: [PATCH 6/6] websocket: fix comments Signed-off-by: tangxinfa --- source/common/http/conn_manager_utility.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/common/http/conn_manager_utility.cc b/source/common/http/conn_manager_utility.cc index 30108f7982cc..2c6210a4b0b0 100644 --- a/source/common/http/conn_manager_utility.cc +++ b/source/common/http/conn_manager_utility.cc @@ -21,8 +21,6 @@ void ConnectionManagerUtility::mutateRequestHeaders( ConnectionManagerConfig& config, const Router::Config& route_config, Runtime::RandomGenerator& random, Runtime::Loader& runtime, const LocalInfo::LocalInfo& local_info) { - // Clean proxy headers. - // If this is a WebSocket Upgrade request, do not remove the Connection and Upgrade headers, // as we forward them verbatim to the upstream hosts. if (protocol == Protocol::Http11 && Utility::isWebSocketUpgradeRequest(request_headers)) { @@ -41,6 +39,7 @@ void ConnectionManagerUtility::mutateRequestHeaders( request_headers.removeUpgrade(); } + // Clean proxy headers. request_headers.removeEnvoyInternalRequest(); request_headers.removeKeepAlive(); request_headers.removeProxyConnection();