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 <[email protected]> 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 *>("[email protected]"); + 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); +}
