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 }

Reply via email to