This is an automated email from the ASF dual-hosted git repository.
bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new df7ccfe86c Added Autest for H2 CONNECT and fix a crash triggered by
the test (#9781)
df7ccfe86c is described below
commit df7ccfe86c33c29d66dfd62c332ecb3ea568c204
Author: lzx404243 <[email protected]>
AuthorDate: Sat Jun 24 22:16:25 2023 -0400
Added Autest for H2 CONNECT and fix a crash triggered by the test (#9781)
In #9616, @maskit wrote an H2 CONNECT Autest but couldn't include that in
the final PR because of a Proxy Verifier issue.
Now that the Proxy Verifier issue is resolved, the Autest is added in this
PR(with a few tweaks).
ATS crashes with the new test executing HTTP/2 tunneling traffic. This PR
also includes a fix to resolve that.
---
proxy/http/HttpSM.cc | 11 +++-
tests/gold_tests/connect/connect.test.py | 64 ++++++++++++++++++++++
.../connect/replays/connect_h2.replay.yaml | 61 +++++++++++++++++++++
3 files changed, 135 insertions(+), 1 deletion(-)
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index 9b8896fd7e..c5672c7f85 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -4119,6 +4119,16 @@ HttpSM::tunnel_handler_ssl_producer(int event,
HttpTunnelProducer *p)
STATE_ENTER(&HttpSM::tunnel_handler_ssl_producer, event);
switch (event) {
+ case VC_EVENT_READ_READY:
+ // This event is triggered when receiving DATA frames without the
END_STREAM
+ // flag set in a HTTP/2 CONNECT request. Breaking as there are more DATA
+ // frames to come.
+ break;
+ case VC_EVENT_READ_COMPLETE:
+ // This event is triggered during an HTTP/2 CONNECT request when a DATA
+ // frame with the END_STREAM flag set is received, indicating the end of
the
+ // stream.
+ [[fallthrough]];
case VC_EVENT_EOS:
// The write side of this connection is still alive
// so half-close the read
@@ -4150,7 +4160,6 @@ HttpSM::tunnel_handler_ssl_producer(int event,
HttpTunnelProducer *p)
}
}
break;
- case VC_EVENT_READ_COMPLETE:
case HTTP_TUNNEL_EVENT_PRECOMPLETE:
// We should never get these event since we don't know
// how long the stream is
diff --git a/tests/gold_tests/connect/connect.test.py
b/tests/gold_tests/connect/connect.test.py
index 95b25958a7..90638ae3d4 100644
--- a/tests/gold_tests/connect/connect.test.py
+++ b/tests/gold_tests/connect/connect.test.py
@@ -165,3 +165,67 @@ class ConnectViaPVTest:
ConnectViaPVTest().run()
+
+
+class ConnectViaPVTest2:
+ # This test executes a HTTP/2 CONNECT request with Proxy Verifier.
+ connectReplayFile = "replays/connect_h2.replay.yaml"
+
+ def __init__(self):
+ self.setupOriginServer()
+ self.setupTS()
+
+ def setupOriginServer(self):
+ self.server = Test.MakeVerifierServerProcess(
+ "connect-verifier-server2",
+ self.connectReplayFile)
+ # Verify server output
+ self.server.Streams.stdout += Testers.ExcludesExpression(
+ "test: connect-request",
+ "Verify the CONNECT request doesn't reach the server.")
+ self.server.Streams.stdout += Testers.ContainsExpression(
+ "GET /get HTTP/1.1\nuuid: 1\ntest: real-request",
reflags=re.MULTILINE,
+ description="Verify the server gets the second(tunneled) request.")
+
+ def setupTS(self):
+ self.ts = Test.MakeATSProcess("connect-ts2", enable_tls=True)
+
+ self.ts.Disk.records_config.update({
+ 'proxy.config.diags.debug.enabled': 1,
+ 'proxy.config.diags.debug.tags': 'http|hpack',
+ 'proxy.config.ssl.server.cert.path': f'{self.ts.Variables.SSLDir}',
+ 'proxy.config.ssl.server.private_key.path':
f'{self.ts.Variables.SSLDir}',
+ 'proxy.config.http.server_ports':
f"{self.ts.Variables.ssl_port}:ssl",
+ 'proxy.config.http.connect_ports':
f"{self.server.Variables.http_port}",
+ })
+
+ self.ts.addDefaultSSLFiles()
+ self.ts.Disk.ssl_multicert_config.AddLine(
+ 'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
+ )
+
+ self.ts.Disk.remap_config.AddLines([
+ f"map / http://127.0.0.1:{self.server.Variables.http_port}/",
+ ])
+ # Verify ts logs
+ self.ts.Disk.traffic_out.Content += Testers.ContainsExpression(
+ f"Proxy's Request.*\n.*\nCONNECT
127.0.0.1:{self.server.Variables.http_port} HTTP/1.1", reflags=re.MULTILINE,
+ description="Verify that ATS recognizes the CONNECT request.")
+
+ def runTraffic(self):
+ tr = Test.AddTestRun("Verify correct handling of CONNECT request on
HTTP/2")
+ tr.AddVerifierClientProcess(
+ "connect-client2",
+ self.connectReplayFile,
+ https_ports=[self.ts.Variables.ssl_port],
+ other_args='--thread-limit 1')
+ tr.Processes.Default.StartBefore(self.server)
+ tr.Processes.Default.StartBefore(self.ts)
+ tr.StillRunningAfter = self.server
+ tr.StillRunningAfter = self.ts
+
+ def run(self):
+ self.runTraffic()
+
+
+ConnectViaPVTest2().run()
diff --git a/tests/gold_tests/connect/replays/connect_h2.replay.yaml
b/tests/gold_tests/connect/replays/connect_h2.replay.yaml
new file mode 100644
index 0000000000..140137730d
--- /dev/null
+++ b/tests/gold_tests/connect/replays/connect_h2.replay.yaml
@@ -0,0 +1,61 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# This replay file executes a HTTP/2 CONNECT request, whose DATA frame contains
+# a tunnelled HTTP/1 GET request.
+#
+meta:
+ version: "1.0"
+
+sessions:
+ - protocol:
+ - name: http
+ version: 2
+ - name: tls
+ sni: www.example.com
+ - name: tcp
+ - name: ip
+
+ transactions:
+ - client-request:
+ frames:
+ - HEADERS:
+ headers:
+ fields:
+ - [:method, CONNECT]
+ - [:authority, www.example.com:80]
+ - [uuid, 1]
+ - [test, connect-request]
+ - DATA:
+ content:
+ encoding: plain
+ data: "GET /get HTTP/1.1\r\nuuid: 1\r\ntest:
real-request\r\n\r\n"
+ # This is the server response for the tunnelled HTTP/1 request rather
+ # than for the CONNECT request.
+ server-response:
+ status: 200
+ reason: OK
+ content:
+ encoding: plain
+ data: response_to_tunnelled_request
+ size: 29
+ # Verify the client receives the response for the tunneled GET request
+ # from the origin server.
+ proxy-response:
+ status: 200
+ content:
+ verify: { value: "response_to_tunnelled_request", as: contains }