You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2019/11/08 21:33:06 UTC

[trafficserver] 03/04: Allow txn handler to be set from ssn on same hook

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

zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 712e1b9a340380e0aab45b6e7033557e37d85b13
Author: Susan Hinrichs <sh...@oath.com>
AuthorDate: Fri Oct 25 20:28:33 2019 +0000

    Allow txn handler to be set from ssn on same hook
    
    (cherry picked from commit be2102e4b2874e69823bee5e14f7f644f65cb501)
---
 proxy/InkAPIInternal.h                             |   5 +-
 src/traffic_server/InkAPI.cc                       |   9 +-
 .../gold_tests/pluginTest/test_hooks/hook_add.gold |   7 ++
 .../pluginTest/test_hooks/hook_add.test.py         |  57 +++++++++
 tests/tools/plugins/hook_add_plugin.cc             | 140 +++++++++++++++++++++
 5 files changed, 214 insertions(+), 4 deletions(-)

diff --git a/proxy/InkAPIInternal.h b/proxy/InkAPIInternal.h
index 25fab38..4a90f35 100644
--- a/proxy/InkAPIInternal.h
+++ b/proxy/InkAPIInternal.h
@@ -357,8 +357,9 @@ public:
 protected:
   /// Track the state of one scope of hooks.
   struct Scope {
-    APIHook const *_c; ///< Current hook (candidate for invocation).
-    APIHook const *_p; ///< Previous hook (already invoked).
+    APIHook const *_c;      ///< Current hook (candidate for invocation).
+    APIHook const *_p;      ///< Previous hook (already invoked).
+    APIHooks const *_hooks; ///< Reference to the real hook list
 
     /// Initialize the scope.
     void init(HttpAPIHooks const *scope, TSHttpHookID id);
diff --git a/src/traffic_server/InkAPI.cc b/src/traffic_server/InkAPI.cc
index fb910e0..b508e03 100644
--- a/src/traffic_server/InkAPI.cc
+++ b/src/traffic_server/InkAPI.cc
@@ -1426,16 +1426,21 @@ HttpHookState::is_enabled()
 void
 HttpHookState::Scope::init(HttpAPIHooks const *feature_hooks, TSHttpHookID id)
 {
-  APIHooks const *hooks = (*feature_hooks)[id];
+  _hooks = (*feature_hooks)[id];
 
   _p = nullptr;
-  _c = hooks->head();
+  _c = _hooks->head();
 }
 
 APIHook const *
 HttpHookState::Scope::candidate()
 {
   /// Simply returns _c hook for now. Later will do priority checking here
+
+  // Check to see if a hook has been added since this was initialized empty
+  if (nullptr == _c && nullptr == _p && _hooks != nullptr) {
+    _c = _hooks->head();
+  }
   return _c;
 }
 
diff --git a/tests/gold_tests/pluginTest/test_hooks/hook_add.gold b/tests/gold_tests/pluginTest/test_hooks/hook_add.gold
new file mode 100644
index 0000000..9141bac
--- /dev/null
+++ b/tests/gold_tests/pluginTest/test_hooks/hook_add.gold
@@ -0,0 +1,7 @@
+`` DIAG: (test)  -- globalHandler :: TS_EVENT_HTTP_SSN_START
+`` DIAG: (test) New session, cont is ``
+`` DIAG: (test)  -- sessionHandler :: TS_EVENT_HTTP_PRE_REMAP
+`` DIAG: (test)  -- transactionHandler :: TS_EVENT_HTTP_PRE_REMAP
+`` DIAG: (test)  -- transactionHandler :: TS_EVENT_HTTP_TXN_CLOSE
+`` DIAG: (test)  -- sessionHandler :: TS_EVENT_HTTP_SSN_CLOSE
+``
diff --git a/tests/gold_tests/pluginTest/test_hooks/hook_add.test.py b/tests/gold_tests/pluginTest/test_hooks/hook_add.test.py
new file mode 100644
index 0000000..3ea96bc
--- /dev/null
+++ b/tests/gold_tests/pluginTest/test_hooks/hook_add.test.py
@@ -0,0 +1,57 @@
+#  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.
+
+Test.Summary = '''
+Test adding hooks
+'''
+
+Test.ContinueOnFail = True
+
+server = Test.MakeOriginServer("server")
+
+request_header = {
+    "headers": "GET /argh HTTP/1.1\r\nHost: doesnotmatter\r\n\r\n", "timestamp": "1469733493.993", "body": "" }
+response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": "" }
+server.addResponse("sessionlog.json", request_header, response_header)
+
+ts = Test.MakeATSProcess("ts", select_ports=True, enable_tls=False)
+
+ts.Disk.records_config.update({
+    'proxy.config.diags.debug.tags': 'test',
+    'proxy.config.diags.debug.enabled': 1,
+    'proxy.config.http.cache.http': 0, 
+    'proxy.config.url_remap.remap_required': 0,
+})
+
+Test.PreparePlugin(Test.Variables.AtsTestToolsDir + '/plugins/hook_add_plugin.cc', ts)
+
+ts.Disk.remap_config.AddLine(
+    "map http://one http://127.0.0.1:{0}".format(server.Variables.Port)
+)
+
+tr = Test.AddTestRun()
+# Probe server port to check if ready.
+tr.Processes.Default.StartBefore(server, ready=When.PortOpen(server.Variables.Port))
+# Probe TS cleartext port to check if ready (probing TLS port causes spurious VCONN hook triggers).
+tr.Processes.Default.StartBefore(Test.Processes.ts, ready=When.PortOpen(ts.Variables.port))
+#
+tr.Processes.Default.Command = (
+    'curl --verbose --ipv4 --header "Host: one" http://localhost:{0}/argh'.format(ts.Variables.port)
+)
+tr.Processes.Default.ReturnCode = 0
+
+# Look at the debug output from the plugin
+ts.Streams.All = "hook_add.gold"
diff --git a/tests/tools/plugins/hook_add_plugin.cc b/tests/tools/plugins/hook_add_plugin.cc
new file mode 100644
index 0000000..f8fcfe4
--- /dev/null
+++ b/tests/tools/plugins/hook_add_plugin.cc
@@ -0,0 +1,140 @@
+/** @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>
+
+#define PLUGIN_TAG "test"
+
+int
+transactionHandler(TSCont continuation, TSEvent event, void *d)
+{
+  if (!(event == TS_EVENT_HTTP_PRE_REMAP || event == TS_EVENT_HTTP_TXN_CLOSE)) {
+    TSError("[" PLUGIN_TAG "] unexpected event on transactionHandler: %i\n", event);
+    return 0;
+  }
+
+  TSHttpTxn transaction = static_cast<TSHttpTxn>(d);
+
+  switch (event) {
+  case TS_EVENT_HTTP_PRE_REMAP: {
+    TSDebug(PLUGIN_TAG, " -- transactionHandler :: TS_EVENT_HTTP_PRE_REMAP");
+  } break;
+
+  case TS_EVENT_HTTP_TXN_CLOSE:
+    TSDebug(PLUGIN_TAG, " -- transactionHandler :: TS_EVENT_HTTP_TXN_CLOSE");
+    TSContDataSet(continuation, nullptr);
+    TSContDestroy(continuation);
+    break;
+
+  default:
+    break;
+  }
+
+  TSHttpTxnReenable(transaction, TS_EVENT_HTTP_CONTINUE);
+
+  return 0;
+}
+
+int
+sessionHandler(TSCont continuation, TSEvent event, void *d)
+{
+  TSHttpTxn txnp = (TSHttpTxn)d;
+  TSCont txn_contp;
+
+  switch (event) {
+  case TS_EVENT_HTTP_PRE_REMAP: {
+    TSDebug(PLUGIN_TAG, " -- sessionHandler :: TS_EVENT_HTTP_PRE_REMAP");
+    txn_contp = TSContCreate(transactionHandler, nullptr);
+
+    /* Registers locally to hook PRE_REMAP_HOOK and TXN_CLOSE */
+    TSHttpTxnHookAdd(txnp, TS_HTTP_PRE_REMAP_HOOK, txn_contp);
+    TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, txn_contp);
+  } break;
+
+  case TS_EVENT_HTTP_SSN_CLOSE: {
+    TSDebug(PLUGIN_TAG, " -- sessionHandler :: TS_EVENT_HTTP_SSN_CLOSE");
+    const TSHttpSsn session = static_cast<TSHttpSsn>(d);
+
+    TSHttpSsnReenable(session, TS_EVENT_HTTP_CONTINUE);
+    TSContDestroy(continuation);
+    return 0;
+  } break;
+
+  default:
+    TSAssert(!"Unexpected event");
+    break;
+  }
+
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return 0;
+}
+
+int
+globalHandler(TSCont continuation, TSEvent event, void *data)
+{
+  TSHttpSsn session = static_cast<TSHttpSsn>(data);
+
+  switch (event) {
+  case TS_EVENT_HTTP_SSN_START: {
+    TSDebug(PLUGIN_TAG, " -- globalHandler :: TS_EVENT_HTTP_SSN_START");
+    TSCont cont = TSContCreate(sessionHandler, TSMutexCreate());
+
+    TSHttpSsnHookAdd(session, TS_HTTP_PRE_REMAP_HOOK, cont);
+    TSHttpSsnHookAdd(session, TS_HTTP_SSN_CLOSE_HOOK, cont);
+
+    TSDebug(PLUGIN_TAG, "New session, cont is %p", cont);
+  } break;
+
+  default:
+    return 0;
+  }
+
+  TSHttpSsnReenable(session, TS_EVENT_HTTP_CONTINUE);
+
+  return 0;
+}
+
+void
+TSPluginInit(int argc, const char **argv)
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name   = const_cast<char *>(PLUGIN_TAG);
+  info.support_email = const_cast<char *>("shinrich@verizonmedia.com");
+  info.vendor_name   = const_cast<char *>("Verizon Media");
+
+  TSReturnCode ret;
+#if (TS_VERSION_MAJOR >= 7)
+  ret = TSPluginRegister(&info);
+#else
+  ret = TSPluginRegister(TS_SDK_VERSION_3_0, &info);
+#endif
+
+  if (TS_ERROR == ret) {
+    TSError("[" PLUGIN_TAG "] plugin registration failed\n");
+    return;
+  }
+
+  TSCont continuation = TSContCreate(globalHandler, nullptr);
+
+  TSHttpHookAdd(TS_HTTP_SSN_START_HOOK, continuation);
+}