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

gancho 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 f7e3cf7  cachekey: running as global plugin
f7e3cf7 is described below

commit f7e3cf7a92b7deb1bfafd6bf16a3c0a9dac3d37c
Author: Gancho Tenev <gan...@apache.org>
AuthorDate: Thu Jul 5 08:21:35 2018 -0700

    cachekey: running as global plugin
    
    The plugin can now run as a global plugin (a single global instance
    configured using `plugin.config`) or as per-remap plugin
    (a separate instance configured per remap rule in `remap.config`).
    
    If both global and per-remap instance are used the per-remap
    configuration would take precedence (per-remap configuration
    would be applied and the global configuration ignored).
---
 doc/admin-guide/plugins/cachekey.en.rst |  40 +++++++++
 plugins/cachekey/cachekey.cc            | 131 ++++++++++++++++++++++-----
 plugins/cachekey/cachekey.h             |  20 +++--
 plugins/cachekey/configs.cc             |  13 ++-
 plugins/cachekey/configs.h              |   3 +-
 plugins/cachekey/plugin.cc              | 153 +++++++++++++++++++-------------
 6 files changed, 264 insertions(+), 96 deletions(-)

diff --git a/doc/admin-guide/plugins/cachekey.en.rst 
b/doc/admin-guide/plugins/cachekey.en.rst
index bc126ca..958cdbe 100644
--- a/doc/admin-guide/plugins/cachekey.en.rst
+++ b/doc/admin-guide/plugins/cachekey.en.rst
@@ -177,6 +177,46 @@ Cache key elements separator
 * ``--separator=<string>`` - the cache key is constructed by extracting 
elements from HTTP URI and headers or by using the UA classifiers and they are 
appended during the key construction and separated by ``/`` (by default). This 
options allows to override the default separator to any string (including an 
empty string).
 
 
+How to run the plugin
+=====================
+
+The plugin can run as a global plugin (a single global instance configured 
using `plugin.config`) or as per-remap plugin (a separate instance configured 
per remap rule in `remap.config`).
+
+Global instance
+^^^^^^^^^^^^^^^
+
+::
+
+  $ cat plugin.config
+  cachekey.so \
+      --include-params=a,b,c \
+      --sort-params=true
+
+
+Per-remap instance
+^^^^^^^^^^^^^^^^^^
+
+::
+
+  $cat remap.config
+  map http://www.example.com http://www.origin.com \
+      @plugin=cachekey.so \
+          @pparam=--include-params=a,b,c \
+          @pparam=--sort-params=true
+
+
+If both global and per-remap instance are used the per-remap configuration 
would take precedence (per-remap configuration would be applied and the global 
configuration ignored).
+
+Because of the ATS core (remap) and the CacheKey plugin implementation there 
is a slight difference between the global and the per-remap functionality when 
``--uri-type=remap`` is used.
+
+* The global instance always uses the URI **after** remap (at 
``TS_HTTP_POST_REMAP_HOOK``).
+
+* The per-remap instance uses the URI **during** remap (after 
``TS_HTTP_PRE_REMAP_HOOK`` and  before ``TS_HTTP_POST_REMAP_HOOK``) which leads 
to a different URI to be used depending on plugin order in the remap rule.
+
+    * If CacheKey plugin is the first plugin in the remap rule the URI used 
will be practically the same as the pristine URI.
+    * If the CacheKey plugin is the last plugin in the remap rule (which is 
right before ``TS_HTTP_POST_REMAP_HOOK``) the behavior will be simillar to the 
global instnance.
+
+
 Detailed examples and troubleshooting
 =====================================
 
diff --git a/plugins/cachekey/cachekey.cc b/plugins/cachekey/cachekey.cc
index 2a0b140..a31d628 100644
--- a/plugins/cachekey/cachekey.cc
+++ b/plugins/cachekey/cachekey.cc
@@ -172,17 +172,98 @@ classifyUserAgent(const Classifier &c, TSMBuffer buf, 
TSMLoc hdrs, String &class
   return matched;
 }
 
+static String
+getUri(TSMBuffer buf, TSMLoc url)
+{
+  String uri;
+  int uriLen;
+  const char *uriPtr = TSUrlStringGet(buf, url, &uriLen);
+  if (nullptr != uriPtr && 0 != uriLen) {
+    uri.assign(uriPtr, uriLen);
+    TSfree((void *)uriPtr);
+  } else {
+    CacheKeyError("failed to get URI");
+  }
+  return uri;
+}
+
 /**
  * @brief Constructor setting up the cache key prefix, initializing request 
info.
  * @param txn transaction handle.
- * @param buf marshal buffer
- * @param url URI handle
- * @param hdrs headers handle
+ * @param separator cache key elements separator
+ * @param uriType type of the URI used to create the cachekey ("remap" or 
"pristine")
+ * @param rri remap request info
  */
-CacheKey::CacheKey(TSHttpTxn txn, TSMBuffer buf, TSMLoc url, TSMLoc hdrs, 
String separator)
-  : _txn(txn), _buf(buf), _url(url), _hdrs(hdrs), _separator(separator)
+CacheKey::CacheKey(TSHttpTxn txn, String separator, CacheKeyUriType uriType, 
TSRemapRequestInfo *rri)
+  : _txn(txn), _separator(separator), _uriType(uriType)
 {
   _key.reserve(512);
+
+  _remap = (nullptr != rri);
+
+  /* Get the URI and header to base the cachekey on.
+   * @TODO it might make sense to add more supported URI types */
+
+  if (_remap) {
+    CacheKeyDebug("setting cache key from a remap plugin");
+    if (PRISTINE == _uriType) {
+      if (TS_SUCCESS != TSHttpTxnPristineUrlGet(_txn, &_buf, &_url)) {
+        /* Failing here is unlikely. No action seems the only reasonable thing 
to do from within this plug-in */
+        CacheKeyError("failed to get pristine URI handle");
+        return;
+      }
+      CacheKeyDebug("using pristine uri '%s'", getUri(_buf, _url).c_str());
+    } else {
+      _buf = rri->requestBufp;
+      _url = rri->requestUrl;
+      CacheKeyDebug("using remap uri '%s'", getUri(_buf, _url).c_str());
+    }
+    _hdrs = rri->requestHdrp;
+  } else {
+    CacheKeyDebug("setting cache key from a global plugin");
+    if (TS_SUCCESS != TSHttpTxnClientReqGet(_txn, &_buf, &_hdrs)) {
+      /* Failing here is unlikely. No action seems the only reasonable thing 
to do from within this plug-in */
+      CacheKeyError("failed to get client request handle");
+      return;
+    }
+
+    if (PRISTINE == _uriType) {
+      if (TS_SUCCESS != TSHttpTxnPristineUrlGet(_txn, &_buf, &_url)) {
+        TSHandleMLocRelease(_buf, TS_NULL_MLOC, _hdrs);
+        CacheKeyError("failed to get pristine URI handle");
+        return;
+      }
+      CacheKeyDebug("using pristine uri '%s'", getUri(_buf, _url).c_str());
+    } else {
+      if (TS_SUCCESS != TSHttpHdrUrlGet(_buf, _hdrs, &_url)) {
+        TSHandleMLocRelease(_buf, TS_NULL_MLOC, _hdrs);
+        CacheKeyError("failed to get URI handle");
+        return;
+      }
+      CacheKeyDebug("using post-remap uri '%s','", getUri(_buf, _url).c_str());
+    }
+  }
+  _valid = true; /* success, we got all necessary elements - URI, headers, 
etc. */
+}
+
+CacheKey::~CacheKey()
+{
+  if (_valid) {
+    /* free resources only if valid, if not valid it is assumed nothing was 
allocated or was freed */
+    if (_remap) {
+      /* _buf and _hdrs are assigned from remap info - no need to release 
here. */
+      if (PRISTINE == _uriType) {
+        if (TS_SUCCESS != TSHandleMLocRelease(_buf, TS_NULL_MLOC, _url)) {
+          CacheKeyError("failed to release pristine URI handle");
+        }
+      }
+    } else {
+      if (TS_SUCCESS != TSHandleMLocRelease(_buf, TS_NULL_MLOC, _hdrs) &&
+          TS_SUCCESS != TSHandleMLocRelease(_buf, TS_NULL_MLOC, _url)) {
+        CacheKeyError("failed to release URI and headers handle");
+      }
+    }
+  }
 }
 
 /**
@@ -230,23 +311,9 @@ CacheKey::append(const char *s, unsigned n)
   ::appendEncoded(_key, s, n);
 }
 
-static String
-getUri(TSMBuffer buf, TSMLoc url)
-{
-  String uri;
-  int uriLen;
-  const char *uriPtr = TSUrlStringGet(buf, url, &uriLen);
-  if (nullptr != uriPtr && 0 != uriLen) {
-    uri.assign(uriPtr, uriLen);
-    TSfree((void *)uriPtr);
-  } else {
-    CacheKeyError("failed to get URI");
-  }
-  return uri;
-}
-
 /**
- * @brief Append to the cache key a custom prefix, capture from hots:port, 
capture from URI or default to host:port part of the URI.
+ * @brief Append to the cache key a custom prefix, capture from hots:port, 
capture from URI or default to host:port part of the
+ * URI.
  * @note This is the only cache key component from the key which is always 
available.
  * @param prefix if not empty string will append the static prefix to the 
cache key.
  * @param prefixCapture if not empty will append regex capture/replacement 
from the host:port.
@@ -592,6 +659,24 @@ CacheKey::appendUaClass(Classifier &classifier)
 bool
 CacheKey::finalize() const
 {
-  CacheKeyDebug("finalizing cache key '%s'", _key.c_str());
-  return TSCacheUrlSet(_txn, &(_key[0]), _key.size()) == TS_SUCCESS;
+  bool res = true;
+  CacheKeyDebug("finalizing cache key '%s' from a %s plugin", _key.c_str(), 
(_remap ? "remap" : "global"));
+  if (TS_SUCCESS != TSCacheUrlSet(_txn, &(_key[0]), _key.size())) {
+    int len;
+    char *url = TSHttpTxnEffectiveUrlStringGet(_txn, &len);
+    if (nullptr != url) {
+      if (_remap) {
+        /* Remap instance. Always runs first by design (before 
TS_HTTP_POST_REMAP_HOOK) */
+        CacheKeyError("failed to set cache key for url %.*s", len, url);
+      } else {
+        /* Global instance. We would fail and get here if a per-remap instance 
has already set the cache key
+         * (currently TSCacheUrlSet() can be called only once successfully). 
Don't error, just debug.
+         * @todo avoid the consecutive attempts and error only on unexpected 
failures. */
+        CacheKeyDebug("failed to set cache key for url %.*s", len, url);
+      }
+      TSfree(url);
+    }
+    res = false;
+  }
+  return res;
 }
diff --git a/plugins/cachekey/cachekey.h b/plugins/cachekey/cachekey.h
index 3a24631..6116bba 100644
--- a/plugins/cachekey/cachekey.h
+++ b/plugins/cachekey/cachekey.h
@@ -23,6 +23,8 @@
 
 #pragma once
 
+#include "ts/ts.h"
+#include "ts/remap.h"
 #include "common.h"
 #include "configs.h"
 
@@ -48,7 +50,8 @@
 class CacheKey
 {
 public:
-  CacheKey(TSHttpTxn txn, TSMBuffer buf, TSMLoc url, TSMLoc hdrs, String 
separator);
+  CacheKey(TSHttpTxn txn, String separator, CacheKeyUriType urlType, 
TSRemapRequestInfo *rri = nullptr);
+  ~CacheKey();
 
   void append(unsigned number);
   void append(const String &);
@@ -71,11 +74,14 @@ private:
   CacheKey(); // disallow
 
   /* Information from the request */
-  TSHttpTxn _txn; /**< @brief transaction handle */
-  TSMBuffer _buf; /**< @brief marshal buffer */
-  TSMLoc _url;    /**< @brief URI handle */
-  TSMLoc _hdrs;   /**< @brief headers handle */
+  TSHttpTxn _txn;      /**< @brief transaction handle */
+  TSMBuffer _buf;      /**< @brief marshal buffer */
+  TSMLoc _url;         /**< @brief URI handle */
+  TSMLoc _hdrs;        /**< @brief headers handle */
+  bool _valid = false; /**< @brief shows if the constructor discovered the 
input correctly */
+  bool _remap = false; /**< @brief shows if the input URI was from remap info 
*/
 
-  String _key;       /**< @brief cache key */
-  String _separator; /**< @brief a separator used to separate the cache key 
elements extracted from the URI */
+  String _key;              /**< @brief cache key */
+  String _separator;        /**< @brief a separator used to separate the cache 
key elements extracted from the URI */
+  CacheKeyUriType _uriType; /**< @brief the URI type used as a cachekey base: 
pristine, remap, etc. */
 };
diff --git a/plugins/cachekey/configs.cc b/plugins/cachekey/configs.cc
index dff01b5..16cf27a 100644
--- a/plugins/cachekey/configs.cc
+++ b/plugins/cachekey/configs.cc
@@ -321,9 +321,11 @@ Configs::loadClassifiers(const String &args, bool 
blacklist)
  * @brief initializes plugin configuration.
  * @param argc number of plugin parameters
  * @param argv plugin parameters
+ * @param perRemapConfig boolean showing if this is per-remap config (vs 
global config).
+ *
  */
 bool
-Configs::init(int argc, char *argv[])
+Configs::init(int argc, const char *argv[], bool perRemapConfig)
 {
   static const struct option longopt[] = {
     {const_cast<char *>("exclude-params"), optional_argument, nullptr, 'a'},
@@ -351,9 +353,12 @@ Configs::init(int argc, char *argv[])
 
   bool status = true;
 
-  /* argv contains the "to" and "from" URLs. Skip the first so that the second 
one poses as the program name. */
-  argc--;
-  argv++;
+  /* For remap.config: argv contains the "to" and "from" URLs. Skip the first 
so that the second one poses as the program name.
+   * For plugin.config: argv contains the plugin shared object name. Don't 
skip any */
+  if (perRemapConfig) {
+    argc--;
+    argv++;
+  }
 
   for (;;) {
     int opt;
diff --git a/plugins/cachekey/configs.h b/plugins/cachekey/configs.h
index db54da3..b4890d5 100644
--- a/plugins/cachekey/configs.h
+++ b/plugins/cachekey/configs.h
@@ -131,8 +131,9 @@ public:
    * @brief initializes plugin configuration.
    * @param argc number of plugin parameters
    * @param argv plugin parameters
+   * @param perRemapConfig boolean showing if this is per-remap config (vs 
global config).
    */
-  bool init(int argc, char *argv[]);
+  bool init(int argc, const char *argv[], bool perRemapConfig);
 
   /**
    * @brief provides means for post-processing of the plugin parameters to 
finalize the configuration or to "cache" some of the
diff --git a/plugins/cachekey/plugin.cc b/plugins/cachekey/plugin.cc
index c86e65b..cf3d539 100644
--- a/plugins/cachekey/plugin.cc
+++ b/plugins/cachekey/plugin.cc
@@ -26,6 +26,93 @@
 #include "cachekey.h"
 #include "common.h"
 
+/* Configuration only used by the global plugin instance. */
+Configs *globalConfig = nullptr;
+
+/**
+ * @brief Set the cache key called by both global and remap instances.
+ *
+ * @param txn transaction handle
+ * @param config cachekey configuration
+ */
+static void
+setCacheKey(TSHttpTxn txn, Configs *config, TSRemapRequestInfo *rri = nullptr)
+{
+  /* Initial cache key facility from the requested URL. */
+  CacheKey cachekey(txn, config->getSeparator(), config->getUriType(), rri);
+
+  /* Append custom prefix or the host:port */
+  if (!config->prefixToBeRemoved()) {
+    cachekey.appendPrefix(config->_prefix, config->_prefixCapture, 
config->_prefixCaptureUri);
+  }
+  /* Classify User-Agent and append the class name to the cache key if 
matched. */
+  cachekey.appendUaClass(config->_classifier);
+
+  /* Capture from User-Agent header. */
+  cachekey.appendUaCaptures(config->_uaCapture);
+
+  /* Append headers to the cache key. */
+  cachekey.appendHeaders(config->_headers);
+
+  /* Append cookies to the cache key. */
+  cachekey.appendCookies(config->_cookies);
+
+  /* Append the path to the cache key. */
+  if (!config->pathToBeRemoved()) {
+    cachekey.appendPath(config->_pathCapture, config->_pathCaptureUri);
+  }
+  /* Append query parameters to the cache key. */
+  cachekey.appendQuery(config->_query);
+
+  /* Set the cache key */
+  cachekey.finalize();
+}
+
+static int
+contSetCachekey(TSCont contp, TSEvent event, void *edata)
+{
+  TSHttpTxn txn = static_cast<TSHttpTxn>(edata);
+
+  setCacheKey(txn, globalConfig);
+
+  TSHttpTxnReenable(txn, TS_EVENT_HTTP_CONTINUE);
+  return 0;
+}
+
+/**
+ * @brief Global plugin instance initialization.
+ *
+ * Processes the configuration and initializes a global plugin instance.
+ * @param argc plugin arguments number
+ * @param argv plugin arguments
+ */
+void
+TSPluginInit(int argc, const char *argv[])
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name   = PLUGIN_NAME;
+  info.vendor_name   = "Apache Software Foundation";
+  info.support_email = "d...@trafficserver.apache.org";
+
+  if (TSPluginRegister(&info) != TS_SUCCESS) {
+    CacheKeyError("global plugin registration failed");
+  }
+
+  globalConfig = new Configs();
+  if (nullptr != globalConfig && globalConfig->init(argc, argv, /* 
perRemapConfig */ false)) {
+    TSCont cont = TSContCreate(contSetCachekey, nullptr);
+    TSHttpHookAdd(TS_HTTP_POST_REMAP_HOOK, cont);
+
+    CacheKeyDebug("global plugin initialized");
+  } else {
+    globalConfig = nullptr;
+    delete globalConfig;
+
+    CacheKeyError("failed to initialize global plugin");
+  }
+}
+
 /**
  * @brief Plugin initialization.
  * @param apiInfo remap interface info pointer
@@ -54,14 +141,16 @@ TSReturnCode
 TSRemapNewInstance(int argc, char *argv[], void **instance, char *errBuf, int 
errBufSize)
 {
   Configs *config = new Configs();
-  if (nullptr != config && config->init(argc, argv)) {
+  if (nullptr != config && config->init(argc, const_cast<const char **>(argv), 
/* perRemapConfig */ true)) {
     *instance = config;
   } else {
-    CacheKeyError("failed to initialize the " PLUGIN_NAME " plugin");
+    CacheKeyError("failed to initialize the remap plugin");
     *instance = nullptr;
     delete config;
     return TS_ERROR;
   }
+
+  CacheKeyDebug("remap plugin initialized");
   return TS_SUCCESS;
 }
 
@@ -91,65 +180,7 @@ TSRemapDoRemap(void *instance, TSHttpTxn txn, 
TSRemapRequestInfo *rri)
   Configs *config = (Configs *)instance;
 
   if (nullptr != config) {
-    TSMBuffer bufp;
-    TSMLoc urlLoc;
-    TSMLoc hdrLoc;
-
-    /* Get the URI and header to base the cachekey on.
-     * @TODO it might make sense to add more supported URI types */
-    if (PRISTINE == config->getUriType()) {
-      if (TS_SUCCESS != TSHttpTxnPristineUrlGet(txn, &bufp, &urlLoc)) {
-        /* Failing here is unlikely. No action seems the only reasonable thing 
to do from within this plug-in */
-        CacheKeyError("failed to get pristine URI handle");
-        return TSREMAP_NO_REMAP;
-      }
-    } else {
-      bufp   = rri->requestBufp;
-      urlLoc = rri->requestUrl;
-    }
-    hdrLoc = rri->requestHdrp;
-
-    /* Initial cache key facility from the requested URL. */
-    CacheKey cachekey(txn, bufp, urlLoc, hdrLoc, config->getSeparator());
-
-    /* Append custom prefix or the host:port */
-    if (!config->prefixToBeRemoved()) {
-      cachekey.appendPrefix(config->_prefix, config->_prefixCapture, 
config->_prefixCaptureUri);
-    }
-    /* Classify User-Agent and append the class name to the cache key if 
matched. */
-    cachekey.appendUaClass(config->_classifier);
-
-    /* Capture from User-Agent header. */
-    cachekey.appendUaCaptures(config->_uaCapture);
-
-    /* Append headers to the cache key. */
-    cachekey.appendHeaders(config->_headers);
-
-    /* Append cookies to the cache key. */
-    cachekey.appendCookies(config->_cookies);
-
-    /* Append the path to the cache key. */
-    if (!config->pathToBeRemoved()) {
-      cachekey.appendPath(config->_pathCapture, config->_pathCaptureUri);
-    }
-    /* Append query parameters to the cache key. */
-    cachekey.appendQuery(config->_query);
-
-    /* Set the cache key */
-    if (!cachekey.finalize()) {
-      char *url;
-      int len;
-
-      url = TSHttpTxnEffectiveUrlStringGet(txn, &len);
-      CacheKeyError("failed to set cache key for url %.*s", len, url);
-      TSfree(url);
-    }
-
-    if (PRISTINE == config->getUriType()) {
-      if (TS_SUCCESS != TSHandleMLocRelease(bufp, TS_NULL_MLOC, urlLoc)) {
-        CacheKeyError("failed to release pristine URI handle");
-      }
-    }
+    setCacheKey(txn, config, rri);
   }
 
   return TSREMAP_NO_REMAP;

Reply via email to