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 468e76405a redo_cache_lookup: move to examples; fix `fallback` 
lifetime (#13209)
468e76405a is described below

commit 468e76405a932efa55332a9ff70745e0a04c3b35
Author: Brian Neradt <[email protected]>
AuthorDate: Tue Jun 23 12:57:58 2026 -0500

    redo_cache_lookup: move to examples; fix `fallback` lifetime (#13209)
    
    The redo_cache_lookup plugin kept the fallback URL as a pointer into
    the plugin.config argv storage. That storage can be released after
    plugin initialization, leaving cache-lookup-complete callbacks to
    dereference stale memory.
    
    This copies the parsed fallback URL into plugin-owned storage and
    passes its owned bytes to TSHttpTxnRedoCacheLookup.
    
    Also, while investigating this, it looks like this plugin was made
    simply to demonstrate the use of TSHttpTxnRedoCacheLookup rather than
    being a production-useful plugin. The initial commit says as much and
    there is no customer-facing documentation for this plugin. As such, I'm
    moving this to the examples plugin.
---
 cmake/ExperimentalPlugins.cmake                    |   1 -
 example/plugins/c-api/CMakeLists.txt               |   8 ++
 example/plugins/c-api/redo_cache_lookup/readme.txt |  13 +++
 .../c-api/redo_cache_lookup/redo_cache_lookup.cc   |  91 ++++++++++++++++
 .../redo_cache_lookup/redo_cache_lookup_config.h   |  78 ++++++++++++++
 .../unit_tests/test_redo_cache_lookup_config.cc    |  66 ++++++++++++
 plugins/experimental/CMakeLists.txt                |   3 -
 .../experimental/redo_cache_lookup/CMakeLists.txt  |  21 ----
 plugins/experimental/redo_cache_lookup/README.md   |  11 --
 .../redo_cache_lookup/redo_cache_lookup.cc         | 115 ---------------------
 10 files changed, 256 insertions(+), 151 deletions(-)

diff --git a/cmake/ExperimentalPlugins.cmake b/cmake/ExperimentalPlugins.cmake
index 5e73ffa5ec..4aff4543ab 100644
--- a/cmake/ExperimentalPlugins.cmake
+++ b/cmake/ExperimentalPlugins.cmake
@@ -83,7 +83,6 @@ auto_option(
 )
 auto_option(RATE_LIMIT FEATURE_VAR BUILD_RATE_LIMIT DEFAULT ${_DEFAULT})
 auto_option(REALIP FEATURE_VAR BUILD_REALIP DEFAULT ${_DEFAULT})
-auto_option(REDO_CACHE_LOOKUP FEATURE_VAR BUILD_REDO_CACHE_LOOKUP DEFAULT 
${_DEFAULT})
 auto_option(SSLHEADERS FEATURE_VAR BUILD_SSLHEADERS DEFAULT ${_DEFAULT})
 auto_option(STALE_RESPONSE FEATURE_VAR BUILD_STALE_RESPONSE DEFAULT 
${_DEFAULT})
 auto_option(
diff --git a/example/plugins/c-api/CMakeLists.txt 
b/example/plugins/c-api/CMakeLists.txt
index 65594cd391..ea40f39cea 100644
--- a/example/plugins/c-api/CMakeLists.txt
+++ b/example/plugins/c-api/CMakeLists.txt
@@ -24,6 +24,7 @@ add_atsplugin(secure_link ./secure_link/secure_link.cc)
 target_link_libraries(secure_link PRIVATE OpenSSL::SSL)
 add_atsplugin(remap ./remap/remap.cc)
 add_atsplugin(redirect_1 ./redirect_1/redirect_1.cc)
+add_atsplugin(redo_cache_lookup ./redo_cache_lookup/redo_cache_lookup.cc)
 add_atsplugin(query_remap ./query_remap/query_remap.cc)
 add_atsplugin(thread_pool ./thread_pool/psi.cc ./thread_pool/thread.cc)
 add_atsplugin(bnull_transform ./bnull_transform/bnull_transform.cc)
@@ -66,3 +67,10 @@ add_atsplugin(protocol_stack 
./protocol_stack/protocol_stack.cc)
 add_atsplugin(client_context_dump ./client_context_dump/client_context_dump.cc)
 target_link_libraries(client_context_dump PRIVATE OpenSSL::SSL 
libswoc::libswoc)
 add_atsplugin(custom_logfield ./custom_logfield/custom_logfield.cc)
+
+if(BUILD_TESTING)
+  add_executable(test_redo_cache_lookup 
./redo_cache_lookup/unit_tests/test_redo_cache_lookup_config.cc)
+  target_include_directories(test_redo_cache_lookup PRIVATE 
${CMAKE_CURRENT_SOURCE_DIR}/redo_cache_lookup)
+  target_link_libraries(test_redo_cache_lookup PRIVATE Catch2::Catch2WithMain)
+  add_catch2_test(NAME test_redo_cache_lookup COMMAND test_redo_cache_lookup)
+endif()
diff --git a/example/plugins/c-api/redo_cache_lookup/readme.txt 
b/example/plugins/c-api/redo_cache_lookup/readme.txt
new file mode 100644
index 0000000000..9f3008400f
--- /dev/null
+++ b/example/plugins/c-api/redo_cache_lookup/readme.txt
@@ -0,0 +1,13 @@
+# Redo Cache Lookup Example Plugin
+
+This plugin shows how to use the `TSHttpTxnRedoCacheLookup` C API. It
+checks cache lookup results and asks ATS to retry the lookup with a fallback
+URL when the original lookup misses or is skipped.
+
+## Configuration
+
+Add this plugin to `plugin.config` with the `--fallback` option:
+
+```
+redo_cache_lookup.so --fallback http://example.com/fallback_url
+```
diff --git a/example/plugins/c-api/redo_cache_lookup/redo_cache_lookup.cc 
b/example/plugins/c-api/redo_cache_lookup/redo_cache_lookup.cc
new file mode 100644
index 0000000000..c370fae0e2
--- /dev/null
+++ b/example/plugins/c-api/redo_cache_lookup/redo_cache_lookup.cc
@@ -0,0 +1,91 @@
+/** @file
+
+  An example plugin to redo cache lookups with a fallback URL.
+
+  @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 <string>
+#include <string_view>
+
+#include "ts/ts.h"
+#include "redo_cache_lookup_config.h"
+
+#define PLUGIN_NAME "redo_cache_lookup"
+
+namespace
+{
+DbgCtl dbg_ctl{PLUGIN_NAME};
+
+struct RedoCacheLookupConfig {
+  RedoCacheLookupConfig(std::string_view fallback) : fallback(fallback) {}
+
+  std::string fallback;
+};
+
+int
+handle_cache_lookup_complete(TSCont contp, TSEvent event, void *edata)
+{
+  if (event != TS_EVENT_HTTP_CACHE_LOOKUP_COMPLETE) {
+    return 0;
+  }
+
+  TSHttpTxn txnp   = static_cast<TSHttpTxn>(edata);
+  auto     *config = static_cast<RedoCacheLookupConfig 
*>(TSContDataGet(contp));
+  int       status = TS_CACHE_LOOKUP_MISS;
+
+  if (TSHttpTxnCacheLookupStatusGet(txnp, &status) != TS_SUCCESS || status == 
TS_CACHE_LOOKUP_MISS ||
+      status == TS_CACHE_LOOKUP_SKIPPED) {
+    Dbg(dbg_ctl, "rewinding to check for fallback url: %s", 
config->fallback.c_str());
+    TSHttpTxnRedoCacheLookup(txnp, config->fallback.c_str(), 
static_cast<int>(config->fallback.size()));
+  }
+
+  TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE);
+  return 0;
+}
+} // namespace
+
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  Dbg(dbg_ctl, "Init");
+  info.plugin_name   = PLUGIN_NAME;
+  info.vendor_name   = "Apache Software Foundation";
+  info.support_email = "[email protected]";
+
+  if (TSPluginRegister(&info) != TS_SUCCESS) {
+    TSError("[%s] Plugin registration failed", PLUGIN_NAME);
+    return;
+  }
+
+  auto fallback = redo_cache_lookup::parse_fallback_url(argc, argv);
+
+  if (!fallback) {
+    Dbg(dbg_ctl, "Missing fallback option.");
+    TSError("[%s] Missing fallback option", PLUGIN_NAME);
+    return;
+  }
+  Dbg(dbg_ctl, "Initialized with fallback: %s", fallback->c_str());
+
+  TSCont contp = TSContCreate(handle_cache_lookup_complete, nullptr);
+  TSContDataSet(contp, new RedoCacheLookupConfig(*fallback));
+  TSHttpHookAdd(TS_HTTP_CACHE_LOOKUP_COMPLETE_HOOK, contp);
+}
diff --git a/example/plugins/c-api/redo_cache_lookup/redo_cache_lookup_config.h 
b/example/plugins/c-api/redo_cache_lookup/redo_cache_lookup_config.h
new file mode 100644
index 0000000000..8158e4aec0
--- /dev/null
+++ b/example/plugins/c-api/redo_cache_lookup/redo_cache_lookup_config.h
@@ -0,0 +1,78 @@
+/** @file
+
+  Configuration helpers for the redo_cache_lookup plugin.
+
+  @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.
+ */
+
+#pragma once
+
+#include <getopt.h>
+#include <optional>
+#include <string>
+
+namespace redo_cache_lookup
+{
+/** Parse the configured fallback URL from plugin arguments.
+ *
+ * @param[in] argc The number of plugin argument entries in @a argv.
+ * @param[in] argv The plugin arguments supplied from @c plugin.config.
+ * @return The configured fallback URL, or @c std::nullopt if no fallback URL
+ *   is configured.
+ */
+inline std::optional<std::string>
+parse_fallback_url(int argc, const char *argv[])
+{
+  std::optional<std::string> fallback;
+
+  static const struct option longopts[] = {
+    {"fallback", required_argument, nullptr, 'f'},
+    {nullptr,    0,                 nullptr, 0  },
+  };
+
+#if (!defined(kfreebsd) && defined(freebsd)) || defined(darwin)
+  optreset = 1;
+#endif
+#if defined(__GLIBC__)
+  optind = 0;
+#else
+  optind = 1;
+#endif
+  opterr = 0;
+  optarg = nullptr;
+
+  int opt = 0;
+
+  while (opt >= 0) {
+    opt = getopt_long(argc, const_cast<char *const *>(argv), "f:", longopts, 
nullptr);
+    switch (opt) {
+    case 'f':
+      fallback = optarg;
+      break;
+    case -1:
+    case '?':
+      break;
+    default:
+      return std::nullopt;
+    }
+  }
+
+  return fallback;
+}
+} // namespace redo_cache_lookup
diff --git 
a/example/plugins/c-api/redo_cache_lookup/unit_tests/test_redo_cache_lookup_config.cc
 
b/example/plugins/c-api/redo_cache_lookup/unit_tests/test_redo_cache_lookup_config.cc
new file mode 100644
index 0000000000..905af6dfe6
--- /dev/null
+++ 
b/example/plugins/c-api/redo_cache_lookup/unit_tests/test_redo_cache_lookup_config.cc
@@ -0,0 +1,66 @@
+/** @file
+
+  Tests for redo_cache_lookup plugin configuration parsing.
+
+  @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 <catch2/catch_test_macros.hpp>
+
+#include <cstring>
+
+#include "redo_cache_lookup_config.h"
+
+TEST_CASE("redo_cache_lookup fallback option is copied", "[redo_cache_lookup]")
+{
+  char        plugin_name[]  = "redo_cache_lookup.so";
+  char        fallback_opt[] = "--fallback";
+  char        fallback_url[] = "http://example.test/fallback";;
+  const char *argv[]         = {plugin_name, fallback_opt, fallback_url};
+
+  auto parsed = redo_cache_lookup::parse_fallback_url(3, argv);
+
+  REQUIRE(parsed.has_value());
+
+  std::memset(fallback_url, 'x', sizeof(fallback_url) - 1);
+
+  REQUIRE(*parsed == "http://example.test/fallback";);
+}
+
+TEST_CASE("redo_cache_lookup fallback option accepts short form", 
"[redo_cache_lookup]")
+{
+  char        plugin_name[]  = "redo_cache_lookup.so";
+  char        fallback_opt[] = "-f";
+  char        fallback_url[] = "http://example.test/short";;
+  const char *argv[]         = {plugin_name, fallback_opt, fallback_url};
+
+  auto parsed = redo_cache_lookup::parse_fallback_url(3, argv);
+
+  REQUIRE(parsed == "http://example.test/short";);
+}
+
+TEST_CASE("redo_cache_lookup fallback option is required", 
"[redo_cache_lookup]")
+{
+  char        plugin_name[] = "redo_cache_lookup.so";
+  const char *argv[]        = {plugin_name};
+
+  auto parsed = redo_cache_lookup::parse_fallback_url(1, argv);
+
+  REQUIRE_FALSE(parsed.has_value());
+}
diff --git a/plugins/experimental/CMakeLists.txt 
b/plugins/experimental/CMakeLists.txt
index fe7897c585..bd8cf64e0f 100644
--- a/plugins/experimental/CMakeLists.txt
+++ b/plugins/experimental/CMakeLists.txt
@@ -98,9 +98,6 @@ endif()
 if(BUILD_REALIP)
   add_subdirectory(realip)
 endif()
-if(BUILD_REDO_CACHE_LOOKUP)
-  add_subdirectory(redo_cache_lookup)
-endif()
 if(BUILD_SSLHEADERS)
   add_subdirectory(sslheaders)
 endif()
diff --git a/plugins/experimental/redo_cache_lookup/CMakeLists.txt 
b/plugins/experimental/redo_cache_lookup/CMakeLists.txt
deleted file mode 100644
index 1b6c41d47b..0000000000
--- a/plugins/experimental/redo_cache_lookup/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-#######################
-#
-#  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.
-#
-#######################
-
-add_atsplugin(redo_cache_lookup redo_cache_lookup.cc)
-
-target_link_libraries(redo_cache_lookup PRIVATE ts::tscppapi)
-verify_global_plugin(redo_cache_lookup)
diff --git a/plugins/experimental/redo_cache_lookup/README.md 
b/plugins/experimental/redo_cache_lookup/README.md
deleted file mode 100644
index 7ad5ddae36..0000000000
--- a/plugins/experimental/redo_cache_lookup/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Redo Cache Lookup Plugin
-
-This plugin shows how to use the experimental `TSHttpTxnRedoCacheLookup` api. 
It works by checking the cache for a fallback url if the cache lookup failed 
for any given url.
-
-## Configuration
-
-Add this plugin to `plugin.config` with the `--fallback` option:
-
-```
-redo_cache_lookup.so --fallback http://example.com/fallback_url
-```
\ No newline at end of file
diff --git a/plugins/experimental/redo_cache_lookup/redo_cache_lookup.cc 
b/plugins/experimental/redo_cache_lookup/redo_cache_lookup.cc
deleted file mode 100644
index 6e917c700a..0000000000
--- a/plugins/experimental/redo_cache_lookup/redo_cache_lookup.cc
+++ /dev/null
@@ -1,115 +0,0 @@
-/** @file
-
-  A plugin to redo cache lookups with a fallback if cache lookups fail for 
specific urls.
-
-  @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 <iostream>
-#include <regex>
-#include <cstring>
-#include <set>
-#include <sstream>
-#include <getopt.h>
-
-#include <ts/ts.h>
-#include "tscpp/api/GlobalPlugin.h"
-#include "tscpp/api/utils.h"
-
-#define PLUGIN_NAME "redo_cache_lookup"
-
-using namespace atscppapi;
-
-namespace
-{
-GlobalPlugin *plugin;
-
-DbgCtl dbg_ctl{PLUGIN_NAME};
-} // namespace
-
-class RedoCacheLookupPlugin : public GlobalPlugin
-{
-public:
-  RedoCacheLookupPlugin(const char *fallback) : fallback(fallback)
-  {
-    Dbg(dbg_ctl, "registering transaction hooks");
-    RedoCacheLookupPlugin::registerHook(HOOK_CACHE_LOOKUP_COMPLETE);
-  }
-
-  void
-  handleReadCacheLookupComplete(Transaction &transaction) override
-  {
-    Transaction::CacheStatus status = transaction.getCacheStatus();
-
-    if (status == Transaction::CacheStatus::CACHE_LOOKUP_NONE || status == 
Transaction::CacheStatus::CACHE_LOOKUP_SKIPED ||
-        status == Transaction::CacheStatus::CACHE_LOOKUP_MISS) {
-      Dbg(dbg_ctl, "rewinding to check for fallback url: %s", fallback);
-      TSHttpTxn txnp = static_cast<TSHttpTxn>(transaction.getAtsHandle());
-      TSHttpTxnRedoCacheLookup(txnp, fallback, strlen(fallback));
-    }
-
-    transaction.resume();
-  }
-
-private:
-  const char *fallback;
-};
-
-void
-TSPluginInit(int argc, const char *argv[])
-{
-  Dbg(dbg_ctl, "Init");
-  if (!RegisterGlobalPlugin("RedoCacheLookupPlugin", PLUGIN_NAME, 
"[email protected]")) {
-    return;
-  }
-
-  const char *fallback = nullptr;
-
-  // Read options from plugin.config
-  static const struct option longopts[] = {
-    {"fallback", required_argument, nullptr, 'f'}
-  };
-
-  int opt = 0;
-
-  while (opt >= 0) {
-    opt = getopt_long(argc, const_cast<char *const *>(argv), "f:", longopts, 
nullptr);
-    switch (opt) {
-    case 'f':
-      fallback = optarg;
-      break;
-    case -1:
-    case '?':
-      break;
-    default:
-      Dbg(dbg_ctl, "Unexpected option: %i", opt);
-      TSError("[%s] Unexpected options error.", PLUGIN_NAME);
-      return;
-    }
-  }
-
-  if (nullptr == fallback) {
-    Dbg(dbg_ctl, "Missing fallback option.");
-    TSError("[%s] Missing fallback option", PLUGIN_NAME);
-    return;
-  }
-  Dbg(dbg_ctl, "Initialized with fallback: %s", fallback);
-
-  plugin = new RedoCacheLookupPlugin(fallback);
-}

Reply via email to