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);
+}