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

zwoop pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/trafficserver.git

The following commit(s) were added to refs/heads/master by this push:
       new  4546c09   TS-4183: cachekey: URI/prefix/path capture/replacement
4546c09 is described below

commit 4546c09915fec9ea0fb87dd692dde06ea92ad1bf
Author: Gancho Tenev <[email protected]>
AuthorDate: Thu Feb 11 16:29:41 2016 -0800

    TS-4183: cachekey: URI/prefix/path capture/replacement
    
    --capture-prefix-uri=regex
    --capture-prefix-uri=/regex/replacement/
    --capture-path-uri=regex
    --capture-path-uri=/regex/replacement/
    --capture-path=regex
    --capture-path=/regex/replacement/
---
 doc/admin-guide/plugins/cachekey.en.rst            | 237 ++++++++++++++++-----
 plugins/experimental/cachekey/cachekey.cc          | 119 +++++++++--
 plugins/experimental/cachekey/cachekey.h           |   4 +-
 plugins/experimental/cachekey/configs.cc           |  49 +++--
 plugins/experimental/cachekey/configs.h            |  17 +-
 plugins/experimental/cachekey/plugin.cc            |   6 +-
 .../experimental/cachekey/tests/test_cachekey.py   |  99 ++++++++-
 7 files changed, 428 insertions(+), 103 deletions(-)

diff --git a/doc/admin-guide/plugins/cachekey.en.rst 
b/doc/admin-guide/plugins/cachekey.en.rst
index 51310d7..685a395 100644
--- a/doc/admin-guide/plugins/cachekey.en.rst
+++ b/doc/admin-guide/plugins/cachekey.en.rst
@@ -33,44 +33,134 @@ This plugin allows some common cache key manipulations 
based on various HTTP req
 * include headers or cookies by name
 * capture values from the ``User-Agent`` header.
 * classify request using ``User-Agent`` and a list of regular expressions
+* capture and replace strings from the URI and include them in the cache key
+* do more - please find more examples below.
 
-Plugin parameters
-=================
+Cache key structure and related plugin parameters
+=================================================
+
+::
+
+                                hierarchical part                              
 query
+  
┌───────────────────────────────────┴────────────────────────────────────┐┌─────┴──────┐
+  
┌─────────────┬──────────────┬──────────────┬──────────────┬─────────────┬─────────────┐
+  │  Prefix     |  User-Agent  │  Headers     │  Cookies     │  Path       │  
Query      │
+  │  section    |  section     │  section     │  section     │  section    │  
section    │
+  │  (default)  |  (optional)  │  (optional)  │  (optional)  │  (default)  │  
(default)  │
+  
└─────────────┴──────────────┴──────────────┴──────────────┴─────────────┴─────────────┘
+
+* The cache key set by the cachekey plugin can be considered as devided into 
several sections.
+* Every section is manupulated separately by the related plugin parameters 
(more info in each section description below).
+* "User-Agent", "Headers" and "Cookies" sections are optional and will be 
missing from the cache key if no related plugin parameters are used.
+* "Prefix", "Path" and "Query" sections always have default values even if no 
related plugin parameters are used.
+* All cachekey plugin parameters are optional and if missing some of the cache 
key sections will be missing (the optional sections) or their values will be 
left to their defaults.
+
+"Prefix" section
+^^^^^^^^^^^^^^^^
+
+::
+
+  Optional components      | 
┌─────────────────┬──────────────────┬──────────────────────┐
+  (included in this order) | │ --static-prefix | --capture-prefix │ 
--capture-prefix-uri │
+                           | 
├─────────────────┴──────────────────┴──────────────────────┤
+  Default values if no     | │ /host/port                                      
          |
+  optional components      | 
└───────────────────────────────────────────────────────────┘
+  configured               |
+
+* ``--static-prefix=<value>`` (default: empty string) - if specified and not 
an empty string the ``<value>`` will be added to the cache key.
+* ``--capture-prefix=<capture_definition>`` (default: empty string) - if 
specified and not empty then strings are captured from ``host:port`` based on 
the ``<capture_definition>`` and are added to the cache key.
+* ``--capture-prefix-uri=<capture_definition>`` (default: empty string) - if 
specified and not empty then strings are captured from the entire URI based on 
the ``<capture_definition>`` and are added to the cache key.
+* If any of the "Prefix" related plugin parameters are used together in the 
plugin configuration they are added to the cache key in the order shown in the 
diagram.
 
-All parameters are optional, and if not used, their default values are as 
mentioned below. Boolean values default to ``false`` and the rest default to an 
empty list. Examples of each parameter's usage can be found below.
 
-* URI query parameters
-    * If no query related plugin parameters are used, the query is included as 
received from the UA in the cache key.
-    * ``--exclude-params`` (default: empty list) - comma-separated list of 
query params to be black-listed in the cache key. If the list is empty then no 
black-list is applied (no query parameters will be excluded from the cache 
key). The exclude list overrides the include list.
-    * ``--include-params`` (default: empty list) - comma-separated list of 
query params to be white-listed in the cache key. If the list is empty then no 
white-list is applied (all query parameters will be included in the cache key).
-    * ``--include-match-params`` (default: empty list) - regular expression 
matching query parameter names which will be white-listed in the cache key.
-    * ``--exclude-match-params`` (default: empty list) - regular expression 
matching query parameter names which will be black-listed in the cache key.
-    * ``--remove-all-params`` (boolean:``true|false``, ``0|1``, ``yes|no``, 
default: ``false``) - if equals ``true`` then all query parameters are removed 
(the whole query string) and all other URI query parameter related settings (if 
used) will have no effect.
-    * ``--sort-params`` (boolean:``true|false``, ``0|1``, ``yes|no``, default: 
``false``) - if equals ``true`` then all query parameters are sorted in an 
increasing case-sensitive order
-* HTTP headers
-    * ``--include-headers`` (default: empty list) - comma separated list of 
headers to be added to the cache key.
-* HTTP cookies
-    * ``--include-cookies`` (default: empty list) - comma separated list of 
cookies to be added to the cache key.
-
-* Host name, port and custom prefix
-    * Host and port are added to the beginning of the cache key by default 
unless a custom preffix by using ``--static-prefix`` or ``--capture-prefix`` 
plugin parameters is specified.
-    * ``--static-prefix`` (default: empty string) - if specified and not an 
empty string the value will be added to the beginning of the cache key.
-    * ``--capture-prefix=<capture_definition>`` (default: empty string) - if 
specified and not an empty string will capture strings from ``host:port`` based 
on the ``<capture_definition>`` (see below) and add them to the beginning of 
the cache key.
-    * If ``--static-prefix`` and ``--capture-prefix`` are used together then 
the value of ``--static-prefix`` is added first to the cache key, followed by 
the ``--capture-prefix`` capturing/replacement results.
+"User-Agent" section
+^^^^^^^^^^^^^^^^^^^^
+
+::
+
+  Optional components      | ┌────────────┬──────────────┐
+  (included in this order) | │ --ua-class | --ua-capture │
+                           | ├────────────┴──────────────┤
+  Default values if no     | │ (empty)                   |
+  optional components      | └───────────────────────────┘
+  configured               |
 
 * ``User-Agent`` classification
     * ``--ua-whitelist=<classname>:<filename>`` (default: empty string) - 
loads a regex patterns list from a file ``<filename>``, the patterns are 
matched against the ``User-Agent`` header and if matched ``<classname>`` is 
added it to the key.
     * ``--ua-blacklist=<classname>:<filename>`` (default: empty string) - 
loads a regex patterns list from a file ``<filename>``, the patterns are 
matched against the ``User-Agent`` header and if **not** matched 
``<classname>`` is added it to the key.
-
+    * Multiple ``--ua-whitelist`` and ``--ua-blacklist`` can be used and the 
result will be defined by their order in the plugin configuration.
 * ``User-Agent`` regex capturing and replacement
-    * ``--ua-capture=<capture_definition>`` (default: empty string) - if 
specified and not an empty string will capture strings from ``User-Agent`` 
header based on ``<capture_definition>`` (see below) and will add them to the 
cache key.
+    * ``--ua-capture=<capture_definition>`` (default: empty string) - if 
specified and not empty then strings are captured from the ``User-Agent`` 
header based on ``<capture_definition>`` (see below) and are added to the cache 
key.
+* If any ``User-Agent`` classigication and regex capturing and replacement 
plugin parameters are used together they are added to the cache key in the 
order shown in the diagram.
+
+"Headers" section
+^^^^^^^^^^^^^^^^^
+
+::
+
+  Optional components      | ┌───────────────────┐
+                           | │ --include-headers │
+                           | ├───────────────────┤
+  Default values if no     | │ (empty)           |
+  optional components      | └───────────────────┘
+  configured               |
+
+* ``--include-headers`` (default: empty list) - comma separated list of 
headers to be added to the cache key. The list of headers defined by 
``--include-headers`` are always sorted before adding them to the cache  key.
+
+"Cookies" section
+^^^^^^^^^^^^^^^^
+
+::
+
+  Optional components      | ┌───────────────────┐
+                           | │ --include-cookies │
+                           | ├───────────────────┤
+  Default values if no     | │ (empty)           |
+  optional components      | └───────────────────┘
+  configured               |
+
+* ``--include-cookies`` (default: empty list) - comma separated list of 
cookies to be added to the cache key. The list of cookies defined by 
``--include-cookies`` are always sorted before adding them to the cache key.
+
+"Path" section
+^^^^^^^^^^^^^^
+
+::
+
+  Optional components      | ┌────────────────────┬────────────────┐
+  (included in this order) | │ --path-capture-uri | --path-capture │
+                           | ├────────────────────┴────────────────┤
+  Default values if no     | │ URI path                            |
+  optional components      | └─────────────────────────────────────┘
+  configured               |
+
+* if no path related plugin parameters are used, the URI path string is 
included in the cache key.
+* ``--capture-path=<capture_definition>`` (default: empty string) - if 
specified and not empty then strings are captured from URI path based on the 
``<capture_definition>`` and are added to the cache key.
+* ``--capture-path-uri=<capture_definition>`` (default: empty string) - if 
specified and not empty then strings are captured from the entire URI based on 
the ``<capture_definition>`` and are added to the cache key.
+
+"Query" section
+^^^^^^^^^^^^^^^
+
+* If no query related plugin parameters are used, the query string is included 
in the cache key.
+* ``--exclude-params`` (default: empty list) - comma-separated list of query 
params to be black-listed in the cache key. If the list is empty then no 
black-list is applied (no query parameters will be excluded from the cache 
key). The exclude list overrides the include list.
+* ``--include-params`` (default: empty list) - comma-separated list of query 
params to be white-listed in the cache key. If the list is empty then no 
white-list is applied (all query parameters will be included in the cache key).
+* ``--include-match-params`` (default: empty list) - regular expression 
matching query parameter names which will be white-listed in the cache key.
+* ``--exclude-match-params`` (default: empty list) - regular expression 
matching query parameter names which will be black-listed in the cache key.
+* ``--remove-all-params`` (boolean:``true|false``, ``0|1``, ``yes|no``, 
default: ``false``) - if equals ``true`` then all query parameters are removed 
(the whole query string) and all other URI query parameter related settings (if 
used) will have no effect.
+* ``--sort-params`` (boolean:``true|false``, ``0|1``, ``yes|no``, default: 
``false``) - if equals ``true`` then all query parameters are sorted in an 
increasing case-sensitive order
+
+All parameters are optional, and if not used, their default values are as 
mentioned below. Boolean values default to ``false`` and the rest default to an 
empty list. Examples of each parameter's usage can be found below.
+
+
+<capture_definition>
+^^^^^^^^^^^^^^^^^^^^
 
 * ``<capture_definition>`` can be in the following formats
     * ``<regex>`` - ``<regex>`` defines regex capturing groups, up to 10 
captured strings based on ``<regex>`` will be added to the cache key.
     * ``/<regex>/<replacement>/`` - ``<regex>`` defines regex capturing 
groups, ``<replacement>`` defines a pattern where the captured strings 
referenced with ``$0`` ... ``$9`` will be substituted and the result will be 
added to the cache key.
 
-Cache Key Structure
-===================
+
+Detailed examples and troubleshooting
+=====================================
 
 ::
 
@@ -84,21 +174,6 @@ Cache Key Structure
   Cache Key    |     host:port or   UA-class UA-captures   headers     cookies 
      path       query
   components   |     custom prefix           replacement
 
-
-* With the current implementation the following cache key components are 
always present in the cache key:
-    * ``prefix or host:port`` - included at the beginning of the cache key. If 
neither ``--static-prefix`` nor ``--capture-prefix`` are specified or are empty 
strings then ``host:port`` from the request URI are used.
-    * ``path`` - URI path included **as is** (but can be empty)
-* The rest of the cache key components are optional and their presence in the 
cache key depends on the plugin configuration and the HTTP requests handled by 
the plugin:
-    * ``UA-class`` - a single class name, result of UA classification defined 
by ``--ua-whitelist`` and ``--ua-blacklist`` parameters.
-    * ``UA-captures`` - a result of the regex capture (and possibly 
replacement) from the first ``User-Agent`` header.
-    * ``headers`` - always sorted list of headers defined by 
``--include-headers``
-    * ``cookies`` - always sorted list of headers defined by 
``--include-cookies``
-    * ``query`` - the request URI query **as is** or a list of query 
parameters proccessed by this plugin as configured.
-* The following URI components are ignored (not included in the cache key):
-    * ``scheme:``
-    * ``user:password@`` from the ``authority`` URI component
-    * ``#fragment``
-
 The following is an example of how the above sample keys were generated 
(``Sample 1`` and ``Sample 2``).
 
 Traffic server configuration ::
@@ -278,8 +353,9 @@ The following headers ``CookieA`` and ``CookieB`` will be 
used when constructing
   @plugin=cachekey.so @pparam=--include-headers=CookieA,CookieB
 
 
-Host name, port and static prefix
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Prefix (host, port, capture and replace from URI)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 Replacing host:port with a static cache key prefix
 """""""""""""""""""""""""""""""""""""""""""""""""""
 If the plugin is used with the following plugin parameter in the remap rule. ::
@@ -288,22 +364,87 @@ If the plugin is used with the following plugin parameter 
in the remap rule. ::
 
 the cache key will be prefixed with ``/static_prefix`` instead of 
``host:port`` when ``--static-prefix`` is not used.
 
-Capturing from the host:port and adding it to beginning of cache key prefix
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Capturing from the host:port and adding it to the prefix section
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 If the plugin is used with the following plugin parameter in the remap rule. ::
 
-  @plugin=cachekey.so @pparam=--capture-prefix=(test_prefix).*:([^\s\/$]*)
+  @plugin=cachekey.so \
+      @pparam=--capture-prefix=(test_prefix).*:([^\s\/$]*)
 
 the cache key will be prefixed with ``/test_prefix/80`` instead of 
``test_prefix_371.example.com:80`` when ``--capture-prefix`` is not used.
 
-Combining --static-prefix and --capture-prefix
-"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Capturing from the entire URI and adding it to the prefix section
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 If the plugin is used with the following plugin parameter in the remap rule. ::
 
-  @plugin=cachekey.so @pparam=--capture-prefix=(test_prefix).*:([^\s\/$]*) 
@pparam=--static-prefix=static_prefix
+  @plugin=cachekey.so \
+      @pparam=--capture-prefix-uri=/(test_prefix).*:.*(object).*$/$1_$2/
+
+and if the request URI is the following ::
+
+  http://test_prefix_123.example.com/path/to/object?a=1&b=2&c=3
+
+the the cache key will be prefixed with ``/test_prefix_object`` instead of 
``test_prefix_123.example.com:80`` when ``--capture-prefix-uri`` is not used.
+
+Combining prefix plugin parameters, i.e. --static-prefix and --capture-prefix
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+If the plugin is used with the following plugin parameters in the remap rule. 
::
+
+  @plugin=cachekey.so \
+      @pparam=--capture-prefix=(test_prefix).*:([^\s\/$]*) \
+      @pparam=--static-prefix=static_prefix
 
 the cache key will be prefixed with ``/static_prefix/test_prefix/80`` instead 
of ``test_prefix_371.example.com:80`` when neither ``--capture-prefix`` nor 
``--static-prefix`` are used.
 
+
+Path, capture and replace from the path or entire URI
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Capture and replace groups from path for the "Path" section
+"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+If the plugin is used with the following plugin parameter in the remap rule. ::
+
+  @plugin=cachekey.so \
+      @pparam=--capture-path=/.*(object).*/const_path_$1/
+
+and the request URI is the following ::
+
+  http://test_path_123.example.com/path/to/object?a=1&b=2&c=3
+
+then the cache key will have ``/const_path_object`` in the path section of the 
cache key instead of ``/path/to/object`` when neither ``--capture-path`` nor 
``--capture-path-uri`` are used.
+
+
+Capture and replace groups from whole URI for the "Path" section
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+If the plugin is used with the following plugin parameter in the remap rule. ::
+
+  @plugin=cachekey.so \
+      @pparam=--capture-path-uri=/(test_path).*(object).*/$1_$2/
+
+and the request URI is the following ::
+
+  http://test_path_123.example.com/path/to/object?a=1&b=2&c=3
+
+the the cache key will have ``/test_path_object`` in the path section of the 
cache key instead of ``/path/to/object`` when neither ``--capture-path`` nor 
``--capture-path-uri`` are used.
+
+
+Combining path plugin parameters --capture-path and --capture-path-uri
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+If the plugin is used with the following plugin parameters in the remap rule. 
::
+
+  @plugin=cachekey.so \
+      @pparam=--capture-path=/.*(object).*/const_path_$1/ \
+      @pparam=--capture-path-uri=/(test_path).*(object).*/$1_$2/
+
+and the request URI is the following ::
+
+  http://test_path_123.example.com/path/to/object?a=1&b=2&c=3
+
+the the cache key will have ``/test_path_object/const_path_object`` in the 
path section of the cache key instead of ``/path/to/object`` when neither 
``--capture-path`` nor ``--capture-path-uri`` are used.
+
 User-Agent capturing, replacement and classification
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 Let us say we have a request with ``User-Agent`` header: ::
diff --git a/plugins/experimental/cachekey/cachekey.cc 
b/plugins/experimental/cachekey/cachekey.cc
index c2246bd..5bb030e 100644
--- a/plugins/experimental/cachekey/cachekey.cc
+++ b/plugins/experimental/cachekey/cachekey.cc
@@ -229,17 +229,36 @@ 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 (NULL != uriPtr && 0 != uriLen) {
+    uri.assign(uriPtr, uriLen);
+    TSfree((void *)uriPtr);
+  } else {
+    CacheKeyError("failed to get URI");
+  }
+  return uri;
+}
+
 /**
- * @brief Append a custom prefix or the host:port part of the URI to the cache 
key.
+ * @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 the method will append the static prefix 
to the cache key.
- * @param pattern if not empty the method will append the result of regex 
capturing and/or replacement to the cache key.
+ * @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.
+ * @param prefixCaptureUri if not empty will append regex capture/replacement 
from the whole URI.
  * @note if both prefix and pattern are not empty prefix will be added first, 
followed by the results from pattern.
  */
 void
-CacheKey::appendPrefix(const String &prefix, Pattern &pattern)
+CacheKey::appendPrefix(const String &prefix, Pattern &prefixCapture, Pattern 
&prefixCaptureUri)
 {
+  // "true" would mean that the plugin config meant to override the default 
prefix (host:port).
   bool customPrefix = false;
+  String host;
+  int port = 0;
 
   if (!prefix.empty()) {
     customPrefix = true;
@@ -247,48 +266,106 @@ CacheKey::appendPrefix(const String &prefix, Pattern 
&pattern)
     CacheKeyDebug("added static prefix, key: '%s'", _key.c_str());
   }
 
-  int len;
-  const char *ptr = TSUrlHostGet(_buf, _url, &len);
-  int port = TSUrlPortGet(_buf, _url);
+  int hostLen;
+  const char *hostPtr = TSUrlHostGet(_buf, _url, &hostLen);
+  if (NULL != hostPtr && 0 != hostLen) {
+    host.assign(hostPtr, hostLen);
+  } else {
+    CacheKeyError("failed to get host");
+  }
+  port = TSUrlPortGet(_buf, _url);
 
-  if (!pattern.empty()) {
+  if (!prefixCapture.empty()) {
     customPrefix = true;
 
     String hostAndPort;
-    hostAndPort.append(ptr, len).append(":");
+    hostAndPort.append(host).append(":");
     ::append(hostAndPort, port);
 
     StringVector captures;
-    if (pattern.process(hostAndPort, captures)) {
+    if (prefixCapture.process(hostAndPort, captures)) {
       for (StringVector::iterator it = captures.begin(); it != captures.end(); 
it++) {
         append(*it);
       }
-      CacheKeyDebug("added capture prefix, key: '%s'", _key.c_str());
+      CacheKeyDebug("added host:port capture prefix, key: '%s'", _key.c_str());
+    }
+  }
+
+  if (!prefixCaptureUri.empty()) {
+    customPrefix = true;
+
+    String uri = getUri(_buf, _url);
+    if (!uri.empty()) {
+      StringVector captures;
+      if (prefixCaptureUri.process(uri, captures)) {
+        for (StringVector::iterator it = captures.begin(); it != 
captures.end(); it++) {
+          append(*it);
+        }
+        CacheKeyDebug("added URI capture prefix, key: '%s'", _key.c_str());
+      }
     }
   }
 
   if (!customPrefix) {
-    _key.append("/").append(ptr, len).append("/");
-    ::append(_key, port);
+    append(host);
+    append(port);
     CacheKeyDebug("added default prefix, key: '%s'", _key.c_str());
   }
 }
 
 /**
- * @brief Appends the path from the URI to the cache key.
+ * @brief Appends to the cache key the path from the URI (default), regex 
capture/replacement from the URI path,
+ * regex capture/replacement from URI as whole.
  * @note A path is always defined for a URI, though the defined path may be 
empty (zero length) (RFC 3986)
+ * @param pathCapture if not empty will append regex capture/replacement from 
the URI path
+ * @param pathCaptureUri if not empty will append regex capture/replacement 
from the URI as a whole
  * @todo enhance, i.e. /<regex>/<replace>/
  */
 void
-CacheKey::appendPath()
+CacheKey::appendPath(Pattern &pathCapture, Pattern &pathCaptureUri)
 {
-  const char *ptr;
-  int len;
+  // "true" would mean that the plugin config meant to override the default 
path.
+  bool customPath = false;
+  String path;
+
+  int pathLen;
+  const char *pathPtr = TSUrlPathGet(_buf, _url, &pathLen);
+  if (NULL != pathPtr && 0 != pathLen) {
+    path.assign(pathPtr, pathLen);
+  }
+
+  if (!pathCaptureUri.empty()) {
+    customPath = true;
+
+    String uri = getUri(_buf, _url);
+    if (!uri.empty()) {
+      StringVector captures;
+      if (pathCaptureUri.process(uri, captures)) {
+        for (StringVector::iterator it = captures.begin(); it != 
captures.end(); it++) {
+          append(*it);
+        }
+        CacheKeyDebug("added URI capture (path), key: '%s'", _key.c_str());
+      }
+    }
+  }
+
+  if (!pathCapture.empty()) {
+    customPath = true;
+
+    // If path is empty don't even try to capture/replace.
+    if (!path.empty()) {
+      StringVector captures;
+      if (pathCapture.process(path, captures)) {
+        for (StringVector::iterator it = captures.begin(); it != 
captures.end(); it++) {
+          append(*it);
+        }
+        CacheKeyDebug("added path capture, key: '%s'", _key.c_str());
+      }
+    }
+  }
 
-  ptr = TSUrlPathGet(_buf, _url, &len);
-  if (NULL != ptr && 0 != len) {
-    _key.append("/");
-    _key.append(ptr, len);
+  if (!customPath && !path.empty()) {
+    append(path);
   }
 }
 
diff --git a/plugins/experimental/cachekey/cachekey.h 
b/plugins/experimental/cachekey/cachekey.h
index 7e5ddb4..ed156fb 100644
--- a/plugins/experimental/cachekey/cachekey.h
+++ b/plugins/experimental/cachekey/cachekey.h
@@ -55,8 +55,8 @@ public:
   void append(const String &);
   void append(const char *s);
   void append(const char *n, unsigned s);
-  void appendPrefix(const String &prefix, Pattern &pattern);
-  void appendPath();
+  void appendPrefix(const String &prefix, Pattern &prefixCapture, Pattern 
&prefixCaptureUri);
+  void appendPath(Pattern &pathCapture, Pattern &pathCaptureUri);
   void appendHeaders(const ConfigHeaders &config);
   void appendQuery(const ConfigQuery &config);
   void appendCookies(const ConfigCookies &config);
diff --git a/plugins/experimental/cachekey/configs.cc 
b/plugins/experimental/cachekey/configs.cc
index 7a459d1..f82ca29 100644
--- a/plugins/experimental/cachekey/configs.cc
+++ b/plugins/experimental/cachekey/configs.cc
@@ -333,10 +333,13 @@ Configs::init(int argc, char *argv[])
                                           {const_cast<char 
*>("include-headers"), optional_argument, 0, 'g'},
                                           {const_cast<char 
*>("include-cookies"), optional_argument, 0, 'h'},
                                           {const_cast<char *>("ua-capture"), 
optional_argument, 0, 'i'},
-                                          {const_cast<char 
*>("static-prefix"), optional_argument, 0, 'j'},
-                                          {const_cast<char 
*>("capture-prefix"), optional_argument, 0, 'k'},
-                                          {const_cast<char *>("ua-whitelist"), 
optional_argument, 0, 'l'},
-                                          {const_cast<char *>("ua-blacklist"), 
optional_argument, 0, 'm'},
+                                          {const_cast<char *>("ua-whitelist"), 
optional_argument, 0, 'j'},
+                                          {const_cast<char *>("ua-blacklist"), 
optional_argument, 0, 'k'},
+                                          {const_cast<char 
*>("static-prefix"), optional_argument, 0, 'l'},
+                                          {const_cast<char 
*>("capture-prefix"), optional_argument, 0, 'm'},
+                                          {const_cast<char 
*>("capture-prefix-uri"), optional_argument, 0, 'n'},
+                                          {const_cast<char *>("capture-path"), 
optional_argument, 0, 'o'},
+                                          {const_cast<char 
*>("capture-path-uri"), optional_argument, 0, 'p'},
                                           {0, 0, 0, 0}};
 
   bool status = true;
@@ -386,25 +389,43 @@ Configs::init(int argc, char *argv[])
         status = false;
       }
       break;
-    case 'j': /* static-prefix */
+    case 'j': /* ua-whitelist */
+      if (!loadClassifiers(optarg, /* blacklist = */ false)) {
+        CacheKeyError("failed to load User-Agent pattern white-list '%s'", 
optarg);
+        status = false;
+      }
+      break;
+    case 'k': /* ua-blacklist */
+      if (!loadClassifiers(optarg, /* blacklist = */ true)) {
+        CacheKeyError("failed to load User-Agent pattern black-list '%s'", 
optarg);
+        status = false;
+      }
+      break;
+    case 'l': /* static-prefix */
       _prefix.assign(optarg);
       CacheKeyDebug("prefix='%s'", _prefix.c_str());
       break;
-    case 'k': /* capture-prefix */
-      if (!_hostCapture.init(optarg)) {
-        CacheKeyError("failed to initialize URI host:port capture pattern 
'%s'", optarg);
+    case 'm': /* capture-prefix */
+      if (!_prefixCapture.init(optarg)) {
+        CacheKeyError("failed to initialize prefix URI host:port capture 
pattern '%s'", optarg);
         status = false;
       }
       break;
-    case 'l': /* ua-whitelist */
-      if (!loadClassifiers(optarg, /* blacklist = */ false)) {
-        CacheKeyError("failed to load User-Agent pattern white-list '%s'", 
optarg);
+    case 'n': /* capture-prefix-uri */
+      if (!_prefixCaptureUri.init(optarg)) {
+        CacheKeyError("failed to initialize prefix URI capture pattern '%s'", 
optarg);
         status = false;
       }
       break;
-    case 'm': /* ua-blacklist */
-      if (!loadClassifiers(optarg, /* blacklist = */ true)) {
-        CacheKeyError("failed to load User-Agent pattern black-list '%s'", 
optarg);
+    case 'o': /* capture-path */
+      if (!_pathCapture.init(optarg)) {
+        CacheKeyError("failed to initialize path capture pattern '%s'", 
optarg);
+        status = false;
+      }
+      break;
+    case 'p': /* capture-path-uri */
+      if (!_pathCaptureUri.init(optarg)) {
+        CacheKeyError("failed to initialize path URI capture pattern '%s'", 
optarg);
         status = false;
       }
       break;
diff --git a/plugins/experimental/cachekey/configs.h 
b/plugins/experimental/cachekey/configs.h
index c9e2080..3281c78 100644
--- a/plugins/experimental/cachekey/configs.h
+++ b/plugins/experimental/cachekey/configs.h
@@ -140,13 +140,16 @@ public:
   bool finalize();
 
   /* Make the following members public to avoid unnecessary accessors */
-  ConfigQuery _query;     /**< @brief query parameter related configuration */
-  ConfigHeaders _headers; /**< @brief headers related configuration */
-  ConfigCookies _cookies; /**< @brief cookies related configuration */
-  Pattern _uaCapture;     /**< @brief the capture groups and the replacement 
string used for the User-Agent header capture */
-  String _prefix;         /**< @brief cache key prefix string */
-  Pattern _hostCapture;   /**< @brief cache key prefix captured from the URI 
host:port */
-  Classifier _classifier; /**< @brief blacklist and white-list classifier used 
to classify User-Agent header */
+  ConfigQuery _query;        /**< @brief query parameter related configuration 
*/
+  ConfigHeaders _headers;    /**< @brief headers related configuration */
+  ConfigCookies _cookies;    /**< @brief cookies related configuration */
+  Pattern _uaCapture;        /**< @brief the capture groups and the 
replacement string used for the User-Agent header capture */
+  String _prefix;            /**< @brief cache key prefix string */
+  Pattern _prefixCapture;    /**< @brief cache key prefix captured from the 
URI host:port */
+  Pattern _prefixCaptureUri; /**< @brief cache key prefix captured from the 
URI as a whole */
+  Pattern _pathCapture;      /**< @brief cache key element captured from the 
URI path */
+  Pattern _pathCaptureUri;   /**< @brief cache key element captured from the 
URI as a whole */
+  Classifier _classifier;    /**< @brief blacklist and white-list classifier 
used to classify User-Agent header */
 
 private:
   /**
diff --git a/plugins/experimental/cachekey/plugin.cc 
b/plugins/experimental/cachekey/plugin.cc
index 429769f..e86fa5c 100644
--- a/plugins/experimental/cachekey/plugin.cc
+++ b/plugins/experimental/cachekey/plugin.cc
@@ -95,7 +95,7 @@ TSRemapDoRemap(void *instance, TSHttpTxn txn, 
TSRemapRequestInfo *rri)
     CacheKey cachekey(txn, rri->requestBufp, rri->requestUrl, 
rri->requestHdrp);
 
     /* Append custom prefix or the host:port */
-    cachekey.appendPrefix(config->_prefix, config->_hostCapture);
+    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);
@@ -109,8 +109,8 @@ TSRemapDoRemap(void *instance, TSHttpTxn txn, 
TSRemapRequestInfo *rri)
     /* Append cookies to the cache key. */
     cachekey.appendCookies(config->_cookies);
 
-    /* Append the path, @todo enhance */
-    cachekey.appendPath();
+    /* Append the path to the cache key. */
+    cachekey.appendPath(config->_pathCapture, config->_pathCaptureUri);
 
     /* Append query parameters to the cache key. */
     cachekey.appendQuery(config->_query);
diff --git a/plugins/experimental/cachekey/tests/test_cachekey.py 
b/plugins/experimental/cachekey/tests/test_cachekey.py
index 42a5102..a232f2b 100644
--- a/plugins/experimental/cachekey/tests/test_cachekey.py
+++ b/plugins/experimental/cachekey/tests/test_cachekey.py
@@ -191,21 +191,87 @@ prefix_bench = [
               "cookies": [],
               "key": "/test_prefix/{1}/path/to/object?a=1&b=2&c=3"
             },
+            # Testing adding a capture prefix with replacement string defined
+            { "args": 
"@pparam=--capture-prefix=/(test_prefix).*:([^\s\/]*)/$1_$2/",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/test_prefix_{1}/path/to/object?a=1&b=2&c=3"
+            },
+            # Testing adding a capture prefix from URI to the cache key
+            { "args": 
"@pparam=--capture-prefix-uri=(test_prefix).*:.*(object).*$",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/test_prefix/object/path/to/object?a=1&b=2&c=3"
+            },
+            # Testing adding a capture prefix from with replacement string 
defined
+            { "args": 
"@pparam=--capture-prefix-uri=/(test_prefix).*:.*(object).*$/$1_$2/",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/test_prefix_object/path/to/object?a=1&b=2&c=3"
+            },
             # Testing adding both static and capture prefix to the cache key
-            { "args": "@pparam=--static-prefix=static_prefix 
@pparam=--capture-prefix=test_prefix",
+            { "args": "@pparam=--static-prefix=static_prefix 
@pparam=--capture-prefix=(test_prefix).*",
               "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
               "headers": [],
               "cookies": [],
               "key": "/static_prefix/test_prefix/path/to/object?a=1&b=2&c=3"
             },
-            # Testing adding a capture prefix with replacement string defined
-            { "args": 
"@pparam=--capture-prefix=/(test_prefix).*:([^\s\/]*)/$1_$2/",
+            # Testing adding static and capture prefix and capture prefix from 
URI to the cache key
+            { "args": "@pparam=--static-prefix=static_prefix 
@pparam=--capture-prefix=(test_prefix).* 
@pparam=--capture-prefix-uri=(object).*",
               "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
               "headers": [],
               "cookies": [],
-              "key": "/test_prefix_{1}/path/to/object?a=1&b=2&c=3"
+              "key": 
"/static_prefix/test_prefix/object/path/to/object?a=1&b=2&c=3"
             },
         ]
+path_bench = [
+            # Testing adding default path to the cache key
+            { "args": "",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/{0}/{1}/path/to/object?a=1&b=2&c=3"
+            },
+            # Testing adding a path capture to the cache key
+            { "args": "@pparam=--capture-path=.*(object).*",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/{0}/{1}/object?a=1&b=2&c=3"
+            },
+            # Testing adding a path capture/replacement to the cache key
+            { "args": "@pparam=--capture-path=/.*(object).*/const_path_$1/",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/{0}/{1}/const_path_object?a=1&b=2&c=3"
+            },
+            # Testing adding an URI capture to the cache key
+            { "args": "@pparam=--capture-path-uri=(test_path).*(object).*",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/{0}/{1}/test_path/object?a=1&b=2&c=3"
+            },
+            # Testing adding an URI capture/replacement to the cache key
+            { "args": 
"@pparam=--capture-path-uri=/(test_path).*(object).*/$1_$2/",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/{0}/{1}/test_path_object?a=1&b=2&c=3"
+            },
+            # Testing adding an URI and path capture/replacement together to 
the cache key
+            { "args": "@pparam=--capture-path=/.*(object).*/const_path_$1/ 
@pparam=--capture-path-uri=/(test_path).*(object).*/$1_$2/",
+              "uri": "{0}:{1}/path/to/object?a=1&b=2&c=3",
+              "headers": [],
+              "cookies": [],
+              "key": "/{0}/{1}/test_path_object/const_path_object?a=1&b=2&c=3"
+            },
+        ]
+
 
 # User-Agent header capture related tests. Doesn't use the meta_bench.
 ua_captures_bench = [
@@ -431,7 +497,7 @@ class 
StaticEnvironmentCase(tsqa.test_cases.EnvironmentCase):
     '''
     @classmethod
     def getEnv(cls):
-        layout = tsqa.environment.Layout('/opt/apache/trafficserver.cachekey')
+        layout = tsqa.environment.Layout('/opt/apache/trafficserver.TS-4183/')
         env = tsqa.environment.Environment()
         env.clone(layout=layout)
         return env
@@ -449,7 +515,6 @@ class TestCacheKey(tsqa.test_cases.DynamicHTTPEndpointCase, 
StaticEnvironmentCas
 
         cls.configs['records.config']['CONFIG'].update({
             'proxy.config.diags.debug.enabled': 1,
-            'proxy.config.diags.debug.tags': '.*',
             'proxy.config.diags.debug.tags': 'cachekey.*',
             'proxy.config.url_remap.pristine_host_hdr': 1,
         })
@@ -497,6 +562,12 @@ class 
TestCacheKey(tsqa.test_cases.DynamicHTTPEndpointCase, StaticEnvironmentCas
             add_remap_rule("prefix", i, test)
             i+=1
 
+        # Prepare path tests related remap rules.
+        i = 0
+        for test in path_bench:
+            add_remap_rule("path", i, test)
+            i+=1
+
         # Prepare ua-capture tests related remap rules.
         i = 0
         for test in ua_captures_bench:
@@ -577,16 +648,28 @@ class 
TestCacheKey(tsqa.test_cases.DynamicHTTPEndpointCase, StaticEnvironmentCas
 
     def test_cachekey_preffix(self):
         '''
-        Tests --static-prefix plugin option for replacing host:port with a 
static prefix in the cache key.
+        Tests --static-prefix, --capture-prefix, --capture-prefix-uri plugin 
option in the cache key.
         '''
         global prifix_bench
 
-        log.info("Testing replacing host:port with a static prefix in the 
cache key creation.")
+        log.info("Testing --static-prefix, --capture-prefix, 
--capture-prefix-uri plugin option in the cache key.")
         i = 0
         for test in prefix_bench:
             self.verify_key('prefix', i, test)
             i += 1
 
+    def test_cachekey_path(self):
+        '''
+        Tests --path-capture, --path-capture-uri plugin option for replacing 
path in the cache key.
+        '''
+        global path_bench
+
+        log.info("Testing --path-capture, --path-capture-uri plugin option for 
replacing path in the cache key.")
+        i = 0
+        for test in path_bench:
+            self.verify_key('path', i, test)
+            i += 1
+
     def test_cachekey_headers(self):
         '''
         Testing cache key headers handling.

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to