This is an automated email from the ASF dual-hosted git repository.

duke8253 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 36bbb0ee90 add test to check H2 grace shutdown works as intended 
(#11046)
36bbb0ee90 is described below

commit 36bbb0ee900d152637daac35044e24b6c4308c21
Author: Fei Deng <[email protected]>
AuthorDate: Wed Jun 26 11:45:56 2024 -0400

    add test to check H2 grace shutdown works as intended (#11046)
---
 tests/gold_tests/h2/http2_close_connection.test.py |  68 ++++++++++++++
 tests/gold_tests/h2/http2_close_connection.yaml    | 100 +++++++++++++++++++++
 tests/tools/plugins/CMakeLists.txt                 |   1 +
 tests/tools/plugins/http2_close_connection.cc      |  92 +++++++++++++++++++
 4 files changed, 261 insertions(+)

diff --git a/tests/gold_tests/h2/http2_close_connection.test.py 
b/tests/gold_tests/h2/http2_close_connection.test.py
new file mode 100644
index 0000000000..fd69360a32
--- /dev/null
+++ b/tests/gold_tests/h2/http2_close_connection.test.py
@@ -0,0 +1,68 @@
+#  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.
+
+import os
+
+Test.Summary = '''
+Check whether the HTTP/2 grace shutdown works as intended.
+'''
+
+Test.SkipUnless(Condition.HasProxyVerifierVersion('2.8.0'))
+
+pv_server = Test.MakeVerifierServerProcess("pv_server", 
"http2_close_connection.yaml")
+
+ts = Test.MakeATSProcess('ts', select_ports=True, enable_tls=True)
+
+ts.addDefaultSSLFiles()
+ts.Disk.ssl_multicert_config.AddLine("dest_ip=* ssl_cert_name=server.pem 
ssl_key_name=server.key")
+ts.Disk.records_config.update(
+    {
+        "proxy.config.http.server_ports": f"{ts.Variables.port} 
{ts.Variables.ssl_port}:ssl",
+        'proxy.config.ssl.server.cert.path': f'{ts.Variables.SSLDir}',
+        'proxy.config.ssl.server.private_key.path': f'{ts.Variables.SSLDir}',
+        'proxy.config.ssl.client.verify.server.policy': 'PERMISSIVE',
+        'proxy.config.diags.debug.enabled': 3,
+        'proxy.config.diags.debug.tags': 'http',
+        'proxy.config.exec_thread.autoconfig.enabled': 0,
+        'proxy.config.exec_thread.limit': 4,
+        'proxy.config.ssl.client.alpn_protocols': 'h2,http/1.1',
+        'proxy.config.http.server_session_sharing.pool': 'thread',
+        'proxy.config.http.server_session_sharing.match': 'ip,sni,cert',
+    })
+
+ts.Disk.remap_config.AddLines([f'map / 
https://127.0.0.1:{pv_server.Variables.https_port}'])
+
+Test.PrepareTestPlugin(os.path.join(Test.Variables.AtsTestPluginsDir, 
'http2_close_connection.so'), ts)
+
+tr = Test.AddTestRun()
+tr.Processes.Default.StartBefore(pv_server)
+tr.Processes.Default.StartBefore(ts)
+tr.AddVerifierClientProcess(
+    "pv_client",
+    "http2_close_connection.yaml",
+    http_ports=[ts.Variables.port],
+    https_ports=[ts.Variables.ssl_port],
+    other_args='--thread-limit 1')
+tr.Processes.Default.ReturnCode = 0
+
+tr.Processes.Default.Streams.All += Testers.ContainsExpression(
+    'Equals Success: Key: "1", Content Data: "body", Value: "server_test_1"', 
'Response check')
+tr.Processes.Default.Streams.All += Testers.ContainsExpression(
+    'Received GOAWAY frame with last stream id 2147483647, error code 0', 
'initial GOAWAY frame with last stream id set to max')
+tr.Processes.Default.Streams.All += Testers.ContainsExpression(
+    'Received GOAWAY frame with last stream id 1, error code 0', 'updated 
GOAWAY frame with last stream id set to 1')
+
+pv_server.Streams.All += Testers.ExcludesExpression('server_test_2', 'Only one 
response should be sent')
diff --git a/tests/gold_tests/h2/http2_close_connection.yaml 
b/tests/gold_tests/h2/http2_close_connection.yaml
new file mode 100644
index 0000000000..5e2d7e6b5a
--- /dev/null
+++ b/tests/gold_tests/h2/http2_close_connection.yaml
@@ -0,0 +1,100 @@
+#  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 assumes that caching is enabled and
+# proxy.config.http.cache.ignore_client_cc_max_age is set to 0 so that we can
+# test max-age in the client requests.
+#
+
+
+meta:
+  version: '1.0'
+sessions:
+- protocol:
+  - name: http
+    version: 2
+  - name: tls
+    sni: test_sni
+  - name: tcp
+  - name: ip
+    version: 4
+  transactions:
+  - client-request:
+      frames:
+      - HEADERS:
+          headers:
+            fields:
+            - [:method, GET]
+            - [:scheme, https]
+            - [:authority, example.data.com]
+            - [:path, /a/path]
+            - [Content-Type, text/html]
+            - [uuid, 1]
+
+    server-response:
+      frames:
+      - HEADERS:
+          headers:
+            fields:
+            - [:status, 200]
+            - [Content-Type, text/html]
+            - [Content-Length, '13']
+      - DATA:
+          delay: 4s
+          content:
+            encoding: plain
+            data: server_test_1
+            size: 13
+
+    proxy-response:
+      content:
+        encoding: plain
+        data: server_test_1
+        verify: {as: equal}
+
+  - client-request:
+      delay: 4s
+      frames:
+      - HEADERS:
+          headers:
+            fields:
+            - [:method, GET]
+            - [:scheme, https]
+            - [:authority, example.data.com]
+            - [:path, /b/path]
+            - [Content-Type, text/html]
+            - [uuid, 2]
+
+    server-response:
+      frames:
+      - HEADERS:
+          headers:
+            fields:
+            - [:status, 200]
+            - [Content-Type, text/html]
+            - [Content-Length, '13']
+      - DATA:
+          content:
+            encoding: plain
+            data: server_test_2
+            size: 13
+
+    proxy-response:
+      content:
+        encoding: plain
+        data: server_test_2
+        verify: {as: equal}
diff --git a/tests/tools/plugins/CMakeLists.txt 
b/tests/tools/plugins/CMakeLists.txt
index 437965bc54..05a4d3d6e1 100644
--- a/tests/tools/plugins/CMakeLists.txt
+++ b/tests/tools/plugins/CMakeLists.txt
@@ -37,6 +37,7 @@ add_autest_plugin(user_args user_args.cc)
 add_autest_plugin(async_engine async_engine.c)
 add_autest_plugin(hook_tunnel_plugin hook_tunnel_plugin.cc)
 add_autest_plugin(tunnel_transform tunnel_transform.cc)
+add_autest_plugin(http2_close_connection http2_close_connection.cc)
 
 target_link_libraries(continuations_verify PRIVATE OpenSSL::SSL)
 target_link_libraries(ssl_client_verify_test PRIVATE OpenSSL::SSL)
diff --git a/tests/tools/plugins/http2_close_connection.cc 
b/tests/tools/plugins/http2_close_connection.cc
new file mode 100644
index 0000000000..2faef81f9f
--- /dev/null
+++ b/tests/tools/plugins/http2_close_connection.cc
@@ -0,0 +1,92 @@
+/** @file
+
+  Test adding continuation from same hook point
+
+  @section license License
+
+  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.
+ */
+#include <ts/ts.h>
+#include <string>
+#include <cstring>
+
+#define PLUGIN_NAME "http2_close_connection"
+
+static DbgCtl dbg_ctl_tag{PLUGIN_NAME};
+
+const char *FIELD_CONNECTION = "Connection";
+const char *VALUE_CLOSE      = "close";
+
+const int LEN_CONNECTION = 10;
+const int LEN_CLOSE      = 5;
+
+static int
+txn_handler(TSCont /* contp */, TSEvent event, void *edata)
+{
+  Dbg(dbg_ctl_tag, "txn_handler event: %d", event);
+
+  TSHttpTxn txnp = static_cast<TSHttpTxn>(edata);
+
+  TSMBuffer resp_bufp    = nullptr;
+  TSMLoc    resp_hdr_loc = nullptr;
+  if (TSHttpTxnClientRespGet(txnp, &resp_bufp, &resp_hdr_loc) != TS_SUCCESS) {
+    Dbg(dbg_ctl_tag, "TSHttpTxnClientRespGet failed");
+  } else {
+    Dbg(dbg_ctl_tag, "TSHttpTxnClientRespGet success");
+    TSMLoc field_loc = TSMimeHdrFieldFind(resp_bufp, resp_hdr_loc, 
FIELD_CONNECTION, LEN_CONNECTION);
+    if (field_loc) {
+      Dbg(dbg_ctl_tag, "Found header %s", FIELD_CONNECTION);
+      TSMimeHdrFieldValueStringSet(resp_bufp, resp_hdr_loc, field_loc, 0, 
VALUE_CLOSE, LEN_CLOSE);
+      Dbg(dbg_ctl_tag, "Setting header %s:%s", FIELD_CONNECTION, VALUE_CLOSE);
+    } else {
+      Dbg(dbg_ctl_tag, "Header %s not found", FIELD_CONNECTION);
+      if (TSMimeHdrFieldCreate(resp_bufp, resp_hdr_loc, &field_loc) == 
TS_SUCCESS) {
+        TSMimeHdrFieldNameSet(resp_bufp, resp_hdr_loc, field_loc, 
FIELD_CONNECTION, LEN_CONNECTION);
+        TSMimeHdrFieldAppend(resp_bufp, resp_hdr_loc, field_loc);
+        TSMimeHdrFieldValueStringInsert(resp_bufp, resp_hdr_loc, field_loc, 0, 
VALUE_CLOSE, LEN_CLOSE);
+        Dbg(dbg_ctl_tag, "Adding header %s:%s", FIELD_CONNECTION, VALUE_CLOSE);
+      } else {
+        Dbg(dbg_ctl_tag, "TSMimeHdrFieldCreate failed");
+      }
+    }
+    TSHandleMLocRelease(resp_bufp, resp_hdr_loc, field_loc);
+  }
+  TSHandleMLocRelease(resp_bufp, TS_NULL_MLOC, resp_hdr_loc);
+  resp_bufp = nullptr;
+
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return TS_EVENT_NONE;
+}
+
+void
+TSPluginInit(int argc, const char **argv)
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name   = const_cast<char *>(PLUGIN_NAME);
+  info.support_email = const_cast<char *>("[email protected]");
+  info.vendor_name   = const_cast<char *>("Yahoo");
+
+  if (TSPluginRegister(&info) != TS_SUCCESS) {
+    TSError("[" PLUGIN_NAME "] plugin registration failed\n");
+    return;
+  }
+
+  Dbg(dbg_ctl_tag, "plugin registered");
+  TSCont txn_cont = TSContCreate(txn_handler, nullptr);
+  TSHttpHookAdd(TS_HTTP_SEND_RESPONSE_HDR_HOOK, txn_cont);
+}

Reply via email to