You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by cm...@apache.org on 2024/04/15 15:10:42 UTC

(trafficserver) branch 10.0.x updated (eaf34fd330 -> 4c8fd0c005)

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

cmcfarlen pushed a change to branch 10.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


    from eaf34fd330 IP Allow: document when rules are applied (#11240)
     new d5a6d4333b Fixed asan leak issues with RegexContext (#11184)
     new 5c82874dc1 Allow Cripts to be used directly as @plugin (#11192)
     new 6c9143f51d Terminate H2 connection by COMPRESSION_ERROR (#11222)
     new 829a2617f8 AuTest: Make ja3_fingerprint test stable (#11230)
     new 163fbc55a7 header_rewrite: add debug to accompany parse_line errors (#11238)
     new cef3cbc62c Fix asan leak errors for cachevol test (#11239)
     new ffe023a579 HttpSM::tunnel_handler: Handle WRITE events (#11242)
     new b6df6de977 CID 1374999: plugin stale_response, delete pointer on early exit. (#11248)
     new dbcf2fe9da CID 1534744: txn_box: Move config object insetad of copy. (#11249)
     new ed2b5731a0 Avoid including pcre2.h in Regex.h. (#11246)
     new 4c8fd0c005 Fixes the HRW regexes after refactoring in #11152 (#11250)

The 11 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 doc/admin-guide/files/records.yaml.en.rst          |  14 ++
 include/proxy/http/remap/PluginDso.h               |   2 +-
 include/proxy/http/remap/PluginFactory.h           |   2 +
 include/proxy/http/remap/RemapPluginInfo.h         |   2 +-
 include/tsutil/Regex.h                             |  46 +++---
 .../experimental/stale_response/stale_response.cc  |   1 +
 .../txn_box/plugin/src/txn_box_remap.cc            |   2 +-
 plugins/header_rewrite/header_rewrite.cc           |   7 +-
 plugins/header_rewrite/matcher.h                   |   6 +-
 plugins/header_rewrite/value.cc                    |   1 +
 src/iocore/cache/unit_tests/test_CacheVol.cc       |   7 +-
 src/proxy/http/HttpSM.cc                           |   6 +
 src/proxy/http/remap/PluginDso.cc                  |  24 ++-
 src/proxy/http/remap/PluginFactory.cc              |  24 ++-
 src/proxy/http/remap/RemapPluginInfo.cc            |   4 +-
 src/proxy/http/remap/UrlRewrite.cc                 |  19 +++
 src/proxy/http2/Http2ConnectionState.cc            |   9 +-
 src/records/RecordsConfig.cc                       |   2 +
 src/traffic_server/traffic_server.cc               |   2 +-
 src/tsutil/DbgCtl.cc                               |  16 +-
 src/tsutil/Regex.cc                                | 163 ++++++++++++++-------
 .../ja3_fingerprint/modify-sent-client.gold        |   2 -
 tools/cripts/compiler.sh                           |  97 ++++++++++++
 23 files changed, 372 insertions(+), 86 deletions(-)
 create mode 100755 tools/cripts/compiler.sh


(trafficserver) 01/11: Fixed asan leak issues with RegexContext (#11184)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit d5a6d4333b7644336a64d7e50cd6630e03916c05
Author: Bryan Call <bc...@apache.org>
AuthorDate: Thu Apr 11 15:29:56 2024 -0700

    Fixed asan leak issues with RegexContext (#11184)
    
    (cherry picked from commit a39b8f112dc977e0f2d41daa3dc42d2fe5b7cd05)
---
 src/tsutil/DbgCtl.cc | 16 ++++++++++++-
 src/tsutil/Regex.cc  | 66 +++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 72 insertions(+), 10 deletions(-)

diff --git a/src/tsutil/DbgCtl.cc b/src/tsutil/DbgCtl.cc
index da17985893..18112318f2 100644
--- a/src/tsutil/DbgCtl.cc
+++ b/src/tsutil/DbgCtl.cc
@@ -150,7 +150,7 @@ DbgCtl::_new_reference(char const *tag)
   DebugInterface *p = DebugInterface::get_instance();
   debug_assert(tag != nullptr);
 
-  // DbgCtl instances may be declared as static objects in the destructors of objects not destoyed till program exit.
+  // DbgCtl instances may be declared as static objects in the destructors of objects not destroyed till program exit.
   // So, we must handle the case where the construction of such instances of DbgCtl overlaps with the destruction of
   // other instances of DbgCtl.  That is why it is important to make sure the reference count is non-zero before
   // constructing _RegistryAccessor.  The _RegistryAccessor constructor is thereby able to assume that, if it creates
@@ -158,6 +158,20 @@ DbgCtl::_new_reference(char const *tag)
 
   ++_RegistryAccessor::registry_reference_count;
 
+  // There is a mutex in the C/C++ runtime that both dlopen() and _cxa_thread_atexit() lock while running.
+  // Creating a _RegistryAccessor instance locks the registry mutex.  If the subsequent code in this function triggers
+  // the construction of a thread_local variable (with a non-trivial destructor), the following deadlock scenario is
+  // possible:
+  // 1.  Thread 1 calls a DbgCtl constructor, which locks the registry mutex, but then is suspended.
+  // 2.  Thread 2 calls dlopen() for a plugin, locking the runtime mutex.  It then executes the constructor for a
+  //     statically allocated DbgCtl object, which blocks on locking the registry mutex.
+  // 3.  Thread 1 resumes, and calls member functions of the derived class of DebugInterface.  If this causes the
+  //     the construction of a thread_local variable with a non-trivial destructor, _cxa_thread_atexit() will be called
+  //     to set up a call of the variable's destructor at thread exit.  The call to _cxa_thread_atexit() will block on
+  //     the runtime mutex (held by Thread 2).  So Thread 1 holds the registry mutex and is blocked waiting for the
+  //     runtime mutex.  And Thread 2 holds the runtime mutex and is blocked waiting for the registry mutex.  Deadlock.
+  //
+  // This deadlock is avoided by having the thread_local variable register its destruction in a non-thread_local class.
   _RegistryAccessor ra;
 
   auto &d{ra.data()};
diff --git a/src/tsutil/Regex.cc b/src/tsutil/Regex.cc
index faea3b8546..37e4b4337b 100644
--- a/src/tsutil/Regex.cc
+++ b/src/tsutil/Regex.cc
@@ -25,6 +25,8 @@
 
 #include <array>
 #include <assert.h>
+#include <vector>
+#include <mutex>
 
 //----------------------------------------------------------------------------
 namespace
@@ -41,7 +43,19 @@ my_free(void *ptr, void * /*caller*/)
 {
   free(ptr);
 }
-} // namespace
+
+class RegexContext; // defined below
+class RegexContextCleanup
+{
+public:
+  void push_back(RegexContext *ctx);
+  ~RegexContextCleanup();
+
+private:
+  std::vector<RegexContext *> _contexts;
+  std::mutex _mutex;
+};
+RegexContextCleanup regex_context_cleanup;
 
 //----------------------------------------------------------------------------
 class RegexContext
@@ -50,13 +64,20 @@ public:
   static RegexContext *
   get_instance()
   {
-    if (!_regex_context) {
+    if (_shutdown == true) {
+      return nullptr;
+    }
+
+    if (_regex_context == nullptr) {
       _regex_context = new RegexContext();
+      regex_context_cleanup.push_back(_regex_context);
     }
     return _regex_context;
   }
   ~RegexContext()
   {
+    _shutdown = true;
+
     if (_general_context != nullptr) {
       pcre2_general_context_free(_general_context);
     }
@@ -100,17 +121,28 @@ private:
   pcre2_match_context *_match_context     = nullptr;
   pcre2_jit_stack *_jit_stack             = nullptr;
   thread_local static RegexContext *_regex_context;
+  static bool _shutdown; // flag to indicate destructor was called, so no new instances can be created
 };
 
 thread_local RegexContext *RegexContext::_regex_context = nullptr;
+bool RegexContext::_shutdown                            = false;
 
 //----------------------------------------------------------------------------
-namespace
+
+RegexContextCleanup::~RegexContextCleanup()
 {
-struct RegexContextCleanup {
-  ~RegexContextCleanup() { delete RegexContext::get_instance(); }
-};
-thread_local RegexContextCleanup cleanup;
+  std::lock_guard<std::mutex> guard(_mutex);
+  for (auto ctx : _contexts) {
+    delete ctx;
+  }
+}
+void
+RegexContextCleanup::push_back(RegexContext *ctx)
+{
+  std::lock_guard<std::mutex> guard(_mutex);
+  _contexts.push_back(ctx);
+}
+
 } // namespace
 
 //----------------------------------------------------------------------------
@@ -225,13 +257,21 @@ Regex::compile(std::string_view pattern, uint32_t flags)
 bool
 Regex::compile(std::string_view pattern, std::string &error, int &erroroffset, uint32_t flags)
 {
+  // free the existing compiled regex if there is one
   if (_code != nullptr) {
     pcre2_code_free(_code);
   }
+
+  // get the RegexContext instance - should only be null when shutting down
+  RegexContext *regex_context = RegexContext::get_instance();
+  if (regex_context == nullptr) {
+    return false;
+  }
+
   PCRE2_SIZE error_offset;
   int error_code;
   _code = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(pattern.data()), pattern.size(), flags, &error_code, &error_offset,
-                        RegexContext::get_instance()->get_compile_context());
+                        regex_context->get_compile_context());
   if (!_code) {
     erroroffset = error_offset;
 
@@ -265,11 +305,19 @@ Regex::exec(std::string_view subject) const
 int32_t
 Regex::exec(std::string_view subject, RegexMatches &matches) const
 {
+  // check if there is a compiled regex
   if (_code == nullptr) {
     return 0;
   }
+
+  // get the RegexContext instance - should only be null when shutting down
+  RegexContext *regex_context = RegexContext::get_instance();
+  if (regex_context == nullptr) {
+    return 0;
+  }
+
   int count = pcre2_match(_code, reinterpret_cast<PCRE2_SPTR>(subject.data()), subject.size(), 0, 0, matches.get_match_data(),
-                          RegexContext::get_instance()->get_match_context());
+                          regex_context->get_match_context());
 
   matches.set_size(count);
 


(trafficserver) 03/11: Terminate H2 connection by COMPRESSION_ERROR (#11222)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6c9143f51de90740e0ec1c7fe352e5c482b08614
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Fri Apr 12 08:16:09 2024 +0900

    Terminate H2 connection by COMPRESSION_ERROR (#11222)
    
    (cherry picked from commit 14d5b2ce401446a13b2fef4ab8dbc7cf890acf25)
---
 src/proxy/http2/Http2ConnectionState.cc | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/proxy/http2/Http2ConnectionState.cc b/src/proxy/http2/Http2ConnectionState.cc
index 9bb38b097a..c15102e3c5 100644
--- a/src/proxy/http2/Http2ConnectionState.cc
+++ b/src/proxy/http2/Http2ConnectionState.cc
@@ -320,6 +320,13 @@ Http2ConnectionState::rcv_headers_frame(const Http2Frame &frame)
       stream     = this->create_stream(stream_id, error);
       new_stream = true;
       if (!stream) {
+        // Terminate the connection with COMPRESSION_ERROR because we don't decompress the field block in this HEADERS frame.
+        // TODO: try to decompress to keep HPACK Dynamic Table in sync.
+        if (error.cls == Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM) {
+          return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR,
+                            error.msg);
+        }
+
         return error;
       }
     }
@@ -377,7 +384,7 @@ Http2ConnectionState::rcv_headers_frame(const Http2Frame &frame)
     }
     // Protocol error if the stream depends on itself
     if (stream_id == params.priority.stream_dependency) {
-      return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_STREAM, Http2ErrorCode::HTTP2_ERROR_PROTOCOL_ERROR,
+      return Http2Error(Http2ErrorClass::HTTP2_ERROR_CLASS_CONNECTION, Http2ErrorCode::HTTP2_ERROR_COMPRESSION_ERROR,
                         "recv headers self dependency");
     }
 


(trafficserver) 05/11: header_rewrite: add debug to accompany parse_line errors (#11238)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 163fbc55a73fe8e612b7ace3cbae42e230a1a616
Author: Brian Olsen <br...@comcast.com>
AuthorDate: Thu Apr 11 16:03:35 2024 -0600

    header_rewrite: add debug to accompany parse_line errors (#11238)
    
    (cherry picked from commit 1feaba123536c14a462a507d12fbd95f3a26f8e4)
---
 plugins/header_rewrite/header_rewrite.cc | 7 ++++++-
 plugins/header_rewrite/value.cc          | 1 +
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/plugins/header_rewrite/header_rewrite.cc b/plugins/header_rewrite/header_rewrite.cc
index b6999b3b68..60a1f72f29 100644
--- a/plugins/header_rewrite/header_rewrite.cc
+++ b/plugins/header_rewrite/header_rewrite.cc
@@ -180,7 +180,12 @@ RulesConfig::parse_config(const std::string &fname, TSHttpHookID default_hook)
     Parser p;
 
     // Tokenize and parse this line
-    if (!p.parse_line(line) || p.empty()) {
+    if (!p.parse_line(line)) {
+      Dbg(dbg_ctl, "Error parsing line '%s'", line.c_str());
+      continue;
+    }
+
+    if (p.empty()) {
       continue;
     }
 
diff --git a/plugins/header_rewrite/value.cc b/plugins/header_rewrite/value.cc
index 9256565a9d..d5d8f5727a 100644
--- a/plugins/header_rewrite/value.cc
+++ b/plugins/header_rewrite/value.cc
@@ -60,6 +60,7 @@ Value::set_value(const std::string &val)
             tcond_val->initialize(parser);
           } else {
             // TODO: should we produce error here?
+            Dbg(dbg_ctl, "Error parsing value '%s'", _value.c_str());
           }
         }
       } else {


(trafficserver) 09/11: CID 1534744: txn_box: Move config object insetad of copy. (#11249)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit dbcf2fe9dafc348a08f5cd3b0841ae7b4cfeca56
Author: Damian Meden <dm...@apache.org>
AuthorDate: Mon Apr 15 10:04:02 2024 +0200

    CID 1534744: txn_box: Move config object insetad of copy. (#11249)
    
    (cherry picked from commit b83c795e52b3643e235861530a2c470ec0bc05d7)
---
 plugins/experimental/txn_box/plugin/src/txn_box_remap.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/plugins/experimental/txn_box/plugin/src/txn_box_remap.cc b/plugins/experimental/txn_box/plugin/src/txn_box_remap.cc
index f3747adf52..b866c5e6ab 100644
--- a/plugins/experimental/txn_box/plugin/src/txn_box_remap.cc
+++ b/plugins/experimental/txn_box/plugin/src/txn_box_remap.cc
@@ -112,7 +112,7 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuff, int errbuff
   }
 
   G._remap_ctx_storage_required += cfg->reserved_ctx_storage_size();
-  *ih                            = new RemapContext{cfg};
+  *ih                            = new RemapContext{std::move(cfg)};
   return TS_SUCCESS;
 }
 


(trafficserver) 06/11: Fix asan leak errors for cachevol test (#11239)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit cef3cbc62c1d7302be4a0fb647480aac1c8f8e23
Author: Chris McFarlen <ch...@mcfarlen.us>
AuthorDate: Fri Apr 12 14:54:22 2024 -0500

    Fix asan leak errors for cachevol test (#11239)
    
    * Fix asan leak errors for cachevol test
    
    * uneeded
    
    (cherry picked from commit 7cc8e3a0e84c54ae209003ea52d904f32df3b6e6)
---
 src/iocore/cache/unit_tests/test_CacheVol.cc | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/iocore/cache/unit_tests/test_CacheVol.cc b/src/iocore/cache/unit_tests/test_CacheVol.cc
index 3bed1afada..eafcbc3062 100644
--- a/src/iocore/cache/unit_tests/test_CacheVol.cc
+++ b/src/iocore/cache/unit_tests/test_CacheVol.cc
@@ -323,6 +323,10 @@ ClearCacheVolList(Queue<CacheVol> *cpl, int len)
   int i        = 0;
   CacheVol *cp = nullptr;
   while ((cp = cpl->dequeue())) {
+    for (int d_no = 0; d_no < gndisks; d_no++) {
+      cp->disk_stripes[d_no]->disk->delete_volume(cp->vol_number);
+      cp->disk_stripes[d_no] = nullptr;
+    }
     ats_free(cp->disk_stripes);
     ats_free(cp->stripes);
     delete (cp);
@@ -365,6 +369,8 @@ public:
   cache_init_success_callback(int event, void *e) override
   {
     // Test
+    ClearCacheVolList(&cp_list, cp_list_len);
+
     save_state();
     srand48(time(nullptr));
 
@@ -393,6 +399,5 @@ TEST_CASE("CacheVol")
 
   this_ethread()->schedule_imm(init);
   this_thread()->execute();
-
   return;
 }


(trafficserver) 02/11: Allow Cripts to be used directly as @plugin (#11192)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 5c82874dc17df4add57090123495809a7ad9c647
Author: Leif Hedstrom <zw...@apache.org>
AuthorDate: Thu Apr 11 10:07:13 2024 -0600

    Allow Cripts to be used directly as @plugin (#11192)
    
    * Allow for traffic_server to compile Cripts directly
    
    This relies on an external script / application to do the
    actual work. If not configured, no new behavior is introduced.
    
    * Fixes from review
    
    (cherry picked from commit defd0f2f5b8efcf366a4651f30a4ba9d266b1b99)
---
 doc/admin-guide/files/records.yaml.en.rst  | 14 +++++
 include/proxy/http/remap/PluginDso.h       |  2 +-
 include/proxy/http/remap/PluginFactory.h   |  2 +
 include/proxy/http/remap/RemapPluginInfo.h |  2 +-
 src/proxy/http/remap/PluginDso.cc          | 24 ++++++--
 src/proxy/http/remap/PluginFactory.cc      | 24 +++++++-
 src/proxy/http/remap/RemapPluginInfo.cc    |  4 +-
 src/proxy/http/remap/UrlRewrite.cc         | 19 ++++++
 src/records/RecordsConfig.cc               |  2 +
 src/traffic_server/traffic_server.cc       |  2 +-
 tools/cripts/compiler.sh                   | 97 ++++++++++++++++++++++++++++++
 11 files changed, 182 insertions(+), 10 deletions(-)

diff --git a/doc/admin-guide/files/records.yaml.en.rst b/doc/admin-guide/files/records.yaml.en.rst
index a75647aba4..6b2172bb1b 100644
--- a/doc/admin-guide/files/records.yaml.en.rst
+++ b/doc/admin-guide/files/records.yaml.en.rst
@@ -4895,6 +4895,20 @@ Plug-in Configuration
    Enables (``1``) or disables (``0``) the dynamic reload feature for remap
    plugins (`remap.config`). Global plugins (`plugin.config`) do not have dynamic reload feature yet.
 
+.. ts:cv:: CONFIG proxy.config.plugin.compiler_path STRING ""
+
+   Specifies an optional compiler tool path for compiling plugins. This tool should
+   be an executable, which takes two arguments:
+
+   === ======================================================================
+   Arg Description
+   === ======================================================================
+   1   This is the path to the source file, which should be compiled
+   2   This is the path to the DSO file, which will be created and loaded
+   === ======================================================================
+
+   The script should exit with a status code of ``0`` if the compilation was successful.
+
 .. ts:cv:: CONFIG proxy.config.plugin.vc.default_buffer_index INT 8
    :reloadable:
    :overridable:
diff --git a/include/proxy/http/remap/PluginDso.h b/include/proxy/http/remap/PluginDso.h
index 41f18b943d..9c0d6e452d 100644
--- a/include/proxy/http/remap/PluginDso.h
+++ b/include/proxy/http/remap/PluginDso.h
@@ -66,7 +66,7 @@ public:
   virtual ~PluginDso();
 
   /* DSO Load, unload, get symbols from DSO */
-  virtual bool load(std::string &error);
+  virtual bool load(std::string &error, const fs::path &compilerPath);
   virtual bool unload(std::string &error);
   bool isLoaded();
   bool getSymbol(const char *symbol, void *&address, std::string &error) const;
diff --git a/include/proxy/http/remap/PluginFactory.h b/include/proxy/http/remap/PluginFactory.h
index 5a63a13f41..1ebcadd81e 100644
--- a/include/proxy/http/remap/PluginFactory.h
+++ b/include/proxy/http/remap/PluginFactory.h
@@ -95,6 +95,7 @@ public:
   virtual ~PluginFactory();
 
   PluginFactory &setRuntimeDir(const fs::path &runtimeDir);
+  PluginFactory &setCompilerPath(const fs::path &compilerPath);
   PluginFactory &addSearchDir(const fs::path &searchDir);
 
   RemapPluginInst *getRemapPlugin(const fs::path &configPath, int argc, char **argv, std::string &error, bool dynamicReloadEnabled);
@@ -112,6 +113,7 @@ protected:
 
   std::vector<fs::path> _searchDirs; /** @brief ordered list of search paths where we look for plugins */
   fs::path _runtimeDir;              /** @brief the path where we would create a temporary copies of the plugins to load */
+  fs::path _compilerPath;            /** @brief the compilation script to use for cripts and other non-DSO plugins */
 
   PluginInstList _instList;
 
diff --git a/include/proxy/http/remap/RemapPluginInfo.h b/include/proxy/http/remap/RemapPluginInfo.h
index dda7695ce6..73a91643f0 100644
--- a/include/proxy/http/remap/RemapPluginInfo.h
+++ b/include/proxy/http/remap/RemapPluginInfo.h
@@ -83,7 +83,7 @@ public:
   ~RemapPluginInfo();
 
   /* Overload to add / execute remap plugin specific tasks during the plugin loading */
-  bool load(std::string &error) override;
+  bool load(std::string &error, const fs::path &compilerPath) override;
 
   /* Used by the factory to invoke callbacks during plugin load, init and unload  */
   bool init(std::string &error) override;
diff --git a/src/proxy/http/remap/PluginDso.cc b/src/proxy/http/remap/PluginDso.cc
index 9da092a790..4f59167164 100644
--- a/src/proxy/http/remap/PluginDso.cc
+++ b/src/proxy/http/remap/PluginDso.cc
@@ -38,6 +38,8 @@
 #define PluginError Error
 #endif
 
+#include <cstdlib>
+
 namespace
 {
 
@@ -69,7 +71,7 @@ PluginDso::~PluginDso()
 }
 
 bool
-PluginDso::load(std::string &error)
+PluginDso::load(std::string &error, const fs::path &compilerPath)
 {
   /* Clear all errors */
   error.clear();
@@ -89,13 +91,27 @@ PluginDso::load(std::string &error)
   } else {
     PluginDbg(_dbg_ctl(), "plugin '%s' effective path: %s", _configPath.c_str(), _effectivePath.c_str());
 
-    /* Copy the installed plugin DSO to a runtime directory if dynamic reload enabled */
     std::error_code ec;
-    if (isDynamicReloadEnabled() && !copy(_effectivePath, _runtimePath, ec)) {
+
+    if (!_effectivePath.string().ends_with(".so")) {
+      if (!isDynamicReloadEnabled()) {
+        concat_error(error, "Dynamic reload must be enabled for Cript files");
+        result = false;
+      } else {
+        std::string command = compilerPath.string() + " " + _effectivePath.string() + " " + _runtimePath.string();
+
+        if (std::system(command.c_str()) != 0) {
+          concat_error(error, "Compile script failed");
+          result = false;
+        }
+      }
+    } else if (isDynamicReloadEnabled() && !copy(_effectivePath, _runtimePath, ec)) {
       concat_error(error, "failed to create a copy");
       concat_error(error, ec.message());
       result = false;
-    } else {
+    }
+
+    if (result) {
       PluginDbg(_dbg_ctl(), "plugin '%s' runtime path: %s", _configPath.c_str(), _runtimePath.c_str());
 
       /* Save the time for later checking if DSO got modified in consecutive DSO reloads */
diff --git a/src/proxy/http/remap/PluginFactory.cc b/src/proxy/http/remap/PluginFactory.cc
index 399da3c042..74b25a8673 100644
--- a/src/proxy/http/remap/PluginFactory.cc
+++ b/src/proxy/http/remap/PluginFactory.cc
@@ -124,6 +124,14 @@ PluginFactory::setRuntimeDir(const fs::path &runtimeDir)
   return *this;
 }
 
+PluginFactory &
+PluginFactory::setCompilerPath(const fs::path &compilerPath)
+{
+  _compilerPath = compilerPath;
+  PluginDbg(_dbg_ctl(), "set plugin compiler path %s", compilerPath.c_str());
+  return *this;
+}
+
 const char *
 PluginFactory::getUuid()
 {
@@ -175,6 +183,20 @@ PluginFactory::getRemapPlugin(const fs::path &configPath, int argc, char **argv,
       runtimePath /= _runtimeDir;
       runtimePath /= effectivePath.relative_path();
 
+      // Special case for Cripts
+      if (!runtimePath.string().ends_with(".so")) {
+        if (_compilerPath.empty()) {
+          error.assign("compiler path not set for compiling plugins");
+          return nullptr;
+        }
+
+        // Add .so to the source file, so e.g. example.cc.so. ToDo: libswoc doesn't allow appending to the extension.
+        std::string newPath = runtimePath.string();
+
+        newPath.append(".so");
+        runtimePath = newPath;
+      }
+
       fs::path parent = runtimePath.parent_path();
       PluginDbg(_dbg_ctl(), "Using effectivePath: [%s] runtimePath: [%s] parent: [%s]", effectivePath.c_str(), runtimePath.c_str(),
                 parent.c_str());
@@ -189,7 +211,7 @@ PluginFactory::getRemapPlugin(const fs::path &configPath, int argc, char **argv,
 
     plugin = new RemapPluginInfo(configPath, effectivePath, runtimePath);
     if (nullptr != plugin) {
-      if (plugin->load(error)) {
+      if (plugin->load(error, _compilerPath)) {
         if (plugin->init(error)) {
           PluginDso::loadedPlugins()->add(plugin);
           inst = RemapPluginInst::init(plugin, argc, argv, error);
diff --git a/src/proxy/http/remap/RemapPluginInfo.cc b/src/proxy/http/remap/RemapPluginInfo.cc
index 001fad8a86..849214ba47 100644
--- a/src/proxy/http/remap/RemapPluginInfo.cc
+++ b/src/proxy/http/remap/RemapPluginInfo.cc
@@ -77,11 +77,11 @@ RemapPluginInfo::RemapPluginInfo(const fs::path &configPath, const fs::path &eff
 }
 
 bool
-RemapPluginInfo::load(std::string &error)
+RemapPluginInfo::load(std::string &error, const fs::path &compilerPath)
 {
   error.clear();
 
-  if (!PluginDso::load(error)) {
+  if (!PluginDso::load(error, compilerPath)) {
     return false;
   }
 
diff --git a/src/proxy/http/remap/UrlRewrite.cc b/src/proxy/http/remap/UrlRewrite.cc
index 80b1460749..fa13988035 100644
--- a/src/proxy/http/remap/UrlRewrite.cc
+++ b/src/proxy/http/remap/UrlRewrite.cc
@@ -87,6 +87,25 @@ UrlRewrite::load()
   /* Initialize the plugin factory */
   pluginFactory.setRuntimeDir(RecConfigReadRuntimeDir()).addSearchDir(RecConfigReadPluginDir());
 
+  // This is "optional", and this configuration is not set by default.
+  char buf[PATH_NAME_MAX];
+
+  buf[0] = '\0';
+  RecGetRecordString("proxy.config.plugin.compiler_path", buf, PATH_NAME_MAX);
+  if (strlen(buf) > 0) {
+    std::error_code ec;
+    fs::path compilerPath  = fs::path(buf);
+    fs::file_status status = fs::status(compilerPath, ec);
+
+    if (ec || !swoc::file::is_regular_file(status)) {
+      Error("Configured plugin compiler path '%s' is not a regular file", buf);
+      return false;
+    } else {
+      // This also adds the configuration directory (etc/trafficserver) to find Cripts etc.
+      pluginFactory.setCompilerPath(compilerPath).addSearchDir(RecConfigReadConfigDir());
+    }
+  }
+
   /* Initialize the next hop strategy factory */
   std::string sf = RecConfigReadConfigPath("proxy.config.url_remap.strategies.filename", "strategies.yaml");
   Dbg(dbg_ctl_url_rewrite_regex, "strategyFactory file: %s", sf.c_str());
diff --git a/src/records/RecordsConfig.cc b/src/records/RecordsConfig.cc
index 77751488ee..00ac0c4de1 100644
--- a/src/records/RecordsConfig.cc
+++ b/src/records/RecordsConfig.cc
@@ -53,6 +53,8 @@ static const RecordElement RecordsConfig[] =
   ,
   {RECT_CONFIG, "proxy.config.bin_path", RECD_STRING, TS_BUILD_BINDIR, RECU_NULL, RR_REQUIRED, RECC_NULL, nullptr, RECA_READ_ONLY}
   ,
+  {RECT_CONFIG, "proxy.config.plugin.compiler_path", RECD_STRING, "", RECU_NULL, RR_REQUIRED, RECC_NULL, nullptr, RECA_READ_ONLY}
+  ,
   // Jira TS-21
   {RECT_CONFIG, "proxy.config.local_state_dir", RECD_STRING, TS_BUILD_RUNTIMEDIR, RECU_RESTART_TS, RR_NULL, RECC_NULL, nullptr, RECA_READ_ONLY}
   ,
diff --git a/src/traffic_server/traffic_server.cc b/src/traffic_server/traffic_server.cc
index f6df676b3e..5d7dd9c579 100644
--- a/src/traffic_server/traffic_server.cc
+++ b/src/traffic_server/traffic_server.cc
@@ -1036,7 +1036,7 @@ try_loading_plugin(plugin_type_t plugin_type, const fs::path &plugin_path, std::
     const auto runtime_path = temporary_directory / plugin_path.filename();
     const fs::path unused_config;
     auto plugin_info = std::make_unique<RemapPluginInfo>(unused_config, plugin_path, runtime_path);
-    bool loaded      = plugin_info->load(error);
+    bool loaded      = plugin_info->load(error, unused_config); // ToDo: Will this ever need support for cripts
     if (!fs::remove(temporary_directory, ec)) {
       fprintf(stderr, "ERROR: could not remove temporary directory '%s': %s\n", temporary_directory.c_str(), ec.message().c_str());
     }
diff --git a/tools/cripts/compiler.sh b/tools/cripts/compiler.sh
new file mode 100755
index 0000000000..74e6d3dd64
--- /dev/null
+++ b/tools/cripts/compiler.sh
@@ -0,0 +1,97 @@
+#!/usr/bin/env bash
+
+#  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 is an example compiler script for compiling Cripts and other plugins
+# on the fly. You would set proxy.config.plugin.compiler_path to point to a
+# customized version of this script, and it will be called whenever a plugin
+# needs to be compiled via remap.config.
+##############################################################################
+
+# Configurable parts
+ATS_ROOT=/opt/ats
+CXX=clang++
+CXXFLAGS="-std=c++20 -I/opt/homebrew/include -undefined dynamic_lookup"
+
+# Probably don't need to change these ?
+STDFLAGS="-shared -fPIC -Wall -Werror -I${ATS_ROOT}/include -L${ATS_ROOT}/lib -lcripts"
+
+# This is optional, but if set, the script will cache the compiled shared objects for faster restarts/reloads
+CACHE_DIR=/tmp/ats-cache
+
+# Extract the arguments, and do some sanity checks
+SOURCE=$1
+DEST=$2
+
+SOURCE_DIR=$(dirname $SOURCE)
+DEST_DIR=$(dirname $DEST)
+SOURCE_FILE=$(basename $SOURCE)
+DEST_FILE=$(basename $DEST)
+
+cd "$SOURCE_DIR"
+if [ $(pwd) != "$SOURCE_DIR" ]; then
+    echo "Failed to cd to $SOURCE_DIR"
+    exit 1
+fi
+
+cd "$DEST_DIR"
+if [ $(pwd) != "$DEST_DIR" ]; then
+    echo "Failed to cd to $DEST_DIR"
+    exit 1
+fi
+
+if [ ! -f "$SOURCE" ]; then
+    echo "Source file $SOURCE does not exist"
+    exit 1
+fi
+
+if [ "${DEST_FILE}" != "${SOURCE_FILE}.so" ]; then
+    echo "Destination file name must match source file name with .so extension"
+    exit 1
+fi
+
+cache_file=""
+if [ -d "$CACHE_DIR" ]; then
+    cache_tree="${CACHE_DIR}${SOURCE_DIR}"
+    cache_file="${cache_tree}/${DEST_FILE}"
+
+    [ -d "$cache_tree" ] || mkdir -p "$cache_tree"
+
+    if [ "$SOURCE" -ot "$cache_file" ]; then
+        cp "$cache_file" "$DEST"
+        exit 0
+    fi
+
+    DEST="$cache_file"
+fi
+
+# Compile the plugin
+${CXX} ${CXXFLAGS} ${STDFLAGS} -o $DEST $SOURCE
+exit_code=$?
+
+if [ $exit_code -ne 0 ]; then
+    echo "Compilation failed with exit code $exit_code"
+    exit $exit_code
+fi
+
+# In case we compiled to the cache, copy from the cache to the runtime destination
+if [ -f "$cache_file" ]; then
+    cp "$cache_file" "${DEST_DIR}/${DEST_FILE}"
+fi
+
+exit 0


(trafficserver) 10/11: Avoid including pcre2.h in Regex.h. (#11246)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ed2b5731a0fce52046dbaf7d6216ee2991af496b
Author: Walt Karas <wk...@yahooinc.com>
AuthorDate: Mon Apr 15 10:58:32 2024 -0400

    Avoid including pcre2.h in Regex.h. (#11246)
    
    (cherry picked from commit 08506ef708b9bb05c6254be1a521f7d60f12e1cf)
---
 include/tsutil/Regex.h |  46 ++++++++++++--------
 src/tsutil/Regex.cc    | 115 +++++++++++++++++++++++++++----------------------
 2 files changed, 93 insertions(+), 68 deletions(-)

diff --git a/include/tsutil/Regex.h b/include/tsutil/Regex.h
index c4ca8feb03..44e10d53b2 100644
--- a/include/tsutil/Regex.h
+++ b/include/tsutil/Regex.h
@@ -28,14 +28,14 @@
 #include <vector>
 #include <memory>
 
-#define PCRE2_CODE_UNIT_WIDTH 8
-#include <pcre2.h>
-
 /// @brief Match flags for regular expression evaluation.
+///
+/// @internal These values are copied from pcre2.h, to avoid having to include it.  The values are checked (with
+/// static_assert) in Regex.cc against PCRE2 named constants, in case they change in future PCRE2 releases.
 enum REFlags {
-  RE_CASE_INSENSITIVE = PCRE2_CASELESS,  ///< Ignore case (default: case sensitive).
-  RE_UNANCHORED       = PCRE2_MULTILINE, ///< Unanchored (DFA defaults to anchored).
-  RE_ANCHORED         = PCRE2_ANCHORED,  ///< Anchored (Regex defaults to unanchored).
+  RE_CASE_INSENSITIVE = 0x00000008u, ///< Ignore case (default: case sensitive).
+  RE_UNANCHORED       = 0x00000400u, ///< Unanchored (DFA defaults to anchored).
+  RE_ANCHORED         = 0x80000000u, ///< Anchored (Regex defaults to unanchored).
 };
 
 /// @brief Wrapper for PCRE2 match data.
@@ -63,19 +63,25 @@ public:
   size_t *get_ovector_pointer();
   int32_t size() const;
 
-protected:
-  pcre2_match_data *get_match_data();
-  void set_subject(std::string_view subject);
-  void set_size(int32_t size);
-
 private:
   constexpr static uint32_t DEFAULT_MATCHES = 10;
   static void *malloc(size_t size, void *caller);
-  pcre2_match_data *_match_data = nullptr;
   std::string_view _subject;
   char _buffer[24 + 96 + 16 * DEFAULT_MATCHES]; // 24 bytes for the general context, 96 bytes overhead, 16 bytes per match.
   size_t _buffer_bytes_used = 0;
   int32_t _size             = 0;
+
+  /// @internal This effectively wraps a void* so that we can avoid requiring the pcre2.h include for the user of the Regex
+  /// API (see Regex.cc).
+  struct _MatchData;
+  class _MatchDataPtr
+  {
+    friend struct _MatchData;
+
+  private:
+    void *_ptr = nullptr;
+  };
+  _MatchDataPtr _match_data;
 };
 
 /// @brief Wrapper for PCRE2 regular expression.
@@ -135,11 +141,17 @@ public:
   int get_capture_count();
 
 private:
-  // @internal - Because the PCRE header is badly done, we can't forward declare the PCRE
-  // enough to use as pointers. For some reason the header defines in name only a struct and
-  // then aliases it to the standard name, rather than simply declare the latter in name only.
-  // The goal is completely wrap PCRE and not include that header in client code.
-  pcre2_code *_code = nullptr;
+  /// @internal This effectively wraps a void* so that we can avoid requiring the pcre2.h include for the user of the Regex
+  /// API (see Regex.cc).
+  struct _Code;
+  class _CodePtr
+  {
+    friend struct _Code;
+
+  private:
+    void *_ptr = nullptr;
+  };
+  _CodePtr _code;
 };
 
 /** Deterministic Finite state Automata container.
diff --git a/src/tsutil/Regex.cc b/src/tsutil/Regex.cc
index 37e4b4337b..fb2cddbb2e 100644
--- a/src/tsutil/Regex.cc
+++ b/src/tsutil/Regex.cc
@@ -23,11 +23,18 @@
 
 #include "tsutil/Regex.h"
 
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
+
 #include <array>
 #include <assert.h>
 #include <vector>
 #include <mutex>
 
+static_assert(RE_CASE_INSENSITIVE == PCRE2_CASELESS, "Update RE_CASE_INSERSITIVE for current PCRE2 version.");
+static_assert(RE_UNANCHORED == PCRE2_MULTILINE, "Update RE_MULTILINE for current PCRE2 version.");
+static_assert(RE_ANCHORED == PCRE2_ANCHORED, "Update RE_ANCHORED for current PCRE2 version.");
+
 //----------------------------------------------------------------------------
 namespace
 {
@@ -145,13 +152,27 @@ RegexContextCleanup::push_back(RegexContext *ctx)
 
 } // namespace
 
+//----------------------------------------------------------------------------
+struct RegexMatches::_MatchData {
+  static pcre2_match_data *
+  get(_MatchDataPtr const &p)
+  {
+    return static_cast<pcre2_match_data *>(p._ptr);
+  }
+  static void
+  set(_MatchDataPtr &p, pcre2_match_data *ptr)
+  {
+    p._ptr = ptr;
+  }
+};
+
 //----------------------------------------------------------------------------
 RegexMatches::RegexMatches(uint32_t size)
 {
   pcre2_general_context *ctx = pcre2_general_context_create(
     &RegexMatches::malloc, [](void *, void *) -> void {}, static_cast<void *>(this));
 
-  _match_data = pcre2_match_data_create(size, ctx);
+  _MatchData::set(_match_data, pcre2_match_data_create(size, ctx));
 }
 
 //----------------------------------------------------------------------------
@@ -175,8 +196,9 @@ RegexMatches::malloc(size_t size, void *caller)
 //----------------------------------------------------------------------------
 RegexMatches::~RegexMatches()
 {
-  if (_match_data != nullptr) {
-    pcre2_match_data_free(_match_data);
+  auto ptr = _MatchData::get(_match_data);
+  if (ptr != nullptr) {
+    pcre2_match_data_free(ptr);
   }
 }
 
@@ -184,7 +206,7 @@ RegexMatches::~RegexMatches()
 size_t *
 RegexMatches::get_ovector_pointer()
 {
-  return pcre2_get_ovector_pointer(_match_data);
+  return pcre2_get_ovector_pointer(_MatchData::get(_match_data));
 }
 
 //----------------------------------------------------------------------------
@@ -194,52 +216,46 @@ RegexMatches::size() const
   return _size;
 }
 
-//----------------------------------------------------------------------------
-pcre2_match_data *
-RegexMatches::get_match_data()
-{
-  return _match_data;
-}
-
-//----------------------------------------------------------------------------
-void
-RegexMatches::set_size(int32_t size)
-{
-  _size = size;
-}
-
-//----------------------------------------------------------------------------
-void
-RegexMatches::set_subject(std::string_view subject)
-{
-  _subject = subject;
-}
-
 //----------------------------------------------------------------------------
 std::string_view
 RegexMatches::operator[](size_t index) const
 {
   // check if the index is valid
-  if (index >= pcre2_get_ovector_count(_match_data)) {
+  if (index >= pcre2_get_ovector_count(_MatchData::get(_match_data))) {
     return std::string_view();
   }
 
-  PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(_match_data);
+  PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(_MatchData::get(_match_data));
   return std::string_view(_subject.data() + ovector[2 * index], ovector[2 * index + 1] - ovector[2 * index]);
 }
 
+//----------------------------------------------------------------------------
+struct Regex::_Code {
+  static pcre2_code *
+  get(_CodePtr const &p)
+  {
+    return static_cast<pcre2_code *>(p._ptr);
+  }
+  static void
+  set(_CodePtr &p, pcre2_code *ptr)
+  {
+    p._ptr = ptr;
+  }
+};
+
 //----------------------------------------------------------------------------
 Regex::Regex(Regex &&that) noexcept
 {
-  _code      = that._code;
-  that._code = nullptr;
+  _code = that._code;
+  _Code::set(that._code, nullptr);
 }
 
 //----------------------------------------------------------------------------
 Regex::~Regex()
 {
-  if (_code != nullptr) {
-    pcre2_code_free(_code);
+  auto ptr = _Code::get(_code);
+  if (ptr != nullptr) {
+    pcre2_code_free(ptr);
   }
 }
 
@@ -258,8 +274,8 @@ bool
 Regex::compile(std::string_view pattern, std::string &error, int &erroroffset, uint32_t flags)
 {
   // free the existing compiled regex if there is one
-  if (_code != nullptr) {
-    pcre2_code_free(_code);
+  if (auto ptr = _Code::get(_code); ptr != nullptr) {
+    pcre2_code_free(ptr);
   }
 
   // get the RegexContext instance - should only be null when shutting down
@@ -270,9 +286,9 @@ Regex::compile(std::string_view pattern, std::string &error, int &erroroffset, u
 
   PCRE2_SIZE error_offset;
   int error_code;
-  _code = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(pattern.data()), pattern.size(), flags, &error_code, &error_offset,
-                        regex_context->get_compile_context());
-  if (!_code) {
+  auto code = pcre2_compile(reinterpret_cast<PCRE2_SPTR>(pattern.data()), pattern.size(), flags, &error_code, &error_offset,
+                            regex_context->get_compile_context());
+  if (!code) {
     erroroffset = error_offset;
 
     // get pcre2 error message
@@ -283,7 +299,9 @@ Regex::compile(std::string_view pattern, std::string &error, int &erroroffset, u
   }
 
   // support for JIT
-  pcre2_jit_compile(_code, PCRE2_JIT_COMPLETE);
+  pcre2_jit_compile(code, PCRE2_JIT_COMPLETE);
+
+  _Code::set(_code, code);
 
   return true;
 }
@@ -292,7 +310,7 @@ Regex::compile(std::string_view pattern, std::string &error, int &erroroffset, u
 bool
 Regex::exec(std::string_view subject) const
 {
-  if (_code == nullptr) {
+  if (_Code::get(_code) == nullptr) {
     return false;
   }
   RegexMatches matches;
@@ -305,28 +323,23 @@ Regex::exec(std::string_view subject) const
 int32_t
 Regex::exec(std::string_view subject, RegexMatches &matches) const
 {
-  // check if there is a compiled regex
-  if (_code == nullptr) {
-    return 0;
-  }
+  auto code = _Code::get(_code);
 
-  // get the RegexContext instance - should only be null when shutting down
-  RegexContext *regex_context = RegexContext::get_instance();
-  if (regex_context == nullptr) {
+  // check if there is a compiled regex
+  if (code == nullptr) {
     return 0;
   }
+  int count = pcre2_match(code, reinterpret_cast<PCRE2_SPTR>(subject.data()), subject.size(), 0, 0,
+                          RegexMatches::_MatchData::get(matches._match_data), RegexContext::get_instance()->get_match_context());
 
-  int count = pcre2_match(_code, reinterpret_cast<PCRE2_SPTR>(subject.data()), subject.size(), 0, 0, matches.get_match_data(),
-                          regex_context->get_match_context());
-
-  matches.set_size(count);
+  matches._size = count;
 
   if (count < 0) {
     return count;
   }
 
   if (count > 0) {
-    matches.set_subject(subject);
+    matches._subject = subject;
   }
 
   return count;
@@ -337,7 +350,7 @@ int32_t
 Regex::get_capture_count()
 {
   int captures = -1;
-  if (pcre2_pattern_info(_code, PCRE2_INFO_CAPTURECOUNT, &captures) != 0) {
+  if (pcre2_pattern_info(_Code::get(_code), PCRE2_INFO_CAPTURECOUNT, &captures) != 0) {
     return -1;
   }
   return captures;


(trafficserver) 08/11: CID 1374999: plugin stale_response, delete pointer on early exit. (#11248)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b6df6de977596bab788439f14861ffafff0daac0
Author: Damian Meden <dm...@apache.org>
AuthorDate: Mon Apr 15 14:16:00 2024 +0200

    CID 1374999: plugin stale_response, delete pointer on early exit. (#11248)
    
    (cherry picked from commit 10e01239e9c6ef5b969de65b9256d55b83fb497f)
---
 plugins/experimental/stale_response/stale_response.cc | 1 +
 1 file changed, 1 insertion(+)

diff --git a/plugins/experimental/stale_response/stale_response.cc b/plugins/experimental/stale_response/stale_response.cc
index a4c81649d4..bb1d1dfff6 100644
--- a/plugins/experimental/stale_response/stale_response.cc
+++ b/plugins/experimental/stale_response/stale_response.cc
@@ -1068,6 +1068,7 @@ TSPluginInit(int argc, const char *argv[])
   // proxy.config.http.insert_age_in_response
   if (TS_SUCCESS != TSUserArgIndexReserve(TS_USER_ARGS_TXN, PLUGIN_TAG, "reserve state info slot", &(plugin_config->txn_slot))) {
     TSError("stale_response [%s] failed to user argument data. Plugin registration failed.", PLUGIN_TAG);
+    delete plugin_config;
     return;
   }
   TSCont main_contp = TSContCreate(global_request_header_hook, nullptr);


(trafficserver) 11/11: Fixes the HRW regexes after refactoring in #11152 (#11250)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 4c8fd0c0055214d29d7bfc927d95c1eddba42e02
Author: Leif Hedstrom <zw...@apache.org>
AuthorDate: Fri Apr 12 16:16:14 2024 -0600

    Fixes the HRW regexes after refactoring in #11152 (#11250)
    
    (cherry picked from commit dfbea61df5cba3b63658c522d67e52080874691a)
---
 plugins/header_rewrite/matcher.h | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/plugins/header_rewrite/matcher.h b/plugins/header_rewrite/matcher.h
index fb56a29df6..f094ede33e 100644
--- a/plugins/header_rewrite/matcher.h
+++ b/plugins/header_rewrite/matcher.h
@@ -85,7 +85,7 @@ public:
   get() const
   {
     return _data;
-  };
+  }
 
   void
   set(const T &d, CondModifiers mods)
@@ -205,6 +205,10 @@ private:
   bool _nocase = false;
 };
 
+// Specializations for the strings, since they can be both strings and regexes
+template <> void Matchers<std::string>::set(const std::string &d, CondModifiers mods);
+template <> bool Matchers<std::string>::test_eq(const std::string &t) const;
+
 // Specialized case matcher for the IP addresses matches.
 template <> class Matchers<const sockaddr *> : public Matcher
 {


(trafficserver) 07/11: HttpSM::tunnel_handler: Handle WRITE events (#11242)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ffe023a57921d3f0902e271f2860193bcc26d08f
Author: Brian Neradt <br...@gmail.com>
AuthorDate: Thu Apr 11 20:01:06 2024 -0500

    HttpSM::tunnel_handler: Handle WRITE events (#11242)
    
    Multiple HttpSM handlers have logic to handle write events after an EOS
    is sent. This applies that logic to the HttpSM::tunnel_handler as well,
    avoiding an unneccesary assertion.
    
    Fixes: #10681
    (cherry picked from commit ed29bf7bed9e62f75bdc088a58a845a5b9689a2b)
---
 src/proxy/http/HttpSM.cc | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/proxy/http/HttpSM.cc b/src/proxy/http/HttpSM.cc
index d268d74db9..bc688d009f 100644
--- a/src/proxy/http/HttpSM.cc
+++ b/src/proxy/http/HttpSM.cc
@@ -2969,6 +2969,12 @@ HttpSM::tunnel_handler(int event, void *data)
 {
   STATE_ENTER(&HttpSM::tunnel_handler, event);
 
+  // If we had already received EOS, just go away. We would sometimes see
+  // a WRITE event appear after receiving EOS from the server connection
+  if ((event == VC_EVENT_WRITE_READY || event == VC_EVENT_WRITE_COMPLETE) && server_entry->eos) {
+    return 0;
+  }
+
   ink_assert(event == HTTP_TUNNEL_EVENT_DONE || event == VC_EVENT_INACTIVITY_TIMEOUT);
   // The tunnel calls this when it is done
   terminate_sm = true;


(trafficserver) 04/11: AuTest: Make ja3_fingerprint test stable (#11230)

Posted by cm...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 829a2617f8907841ea3a97f0c4b3ef8992270e66
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Fri Apr 12 08:12:40 2024 +0900

    AuTest: Make ja3_fingerprint test stable (#11230)
    
    (cherry picked from commit b4c6b8bafa272b727098cfc091070b9180ad7d51)
---
 tests/gold_tests/pluginTest/ja3_fingerprint/modify-sent-client.gold | 2 --
 1 file changed, 2 deletions(-)

diff --git a/tests/gold_tests/pluginTest/ja3_fingerprint/modify-sent-client.gold b/tests/gold_tests/pluginTest/ja3_fingerprint/modify-sent-client.gold
index f50c2dea7c..4fe02c02a7 100644
--- a/tests/gold_tests/pluginTest/ja3_fingerprint/modify-sent-client.gold
+++ b/tests/gold_tests/pluginTest/ja3_fingerprint/modify-sent-client.gold
@@ -1,6 +1,4 @@
 +++++++++ Incoming Request +++++++++
-``
-+++++++++ Incoming Request +++++++++
 -- State Machine Id``
 POST ``
 Host: ``