You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2018/03/12 17:55:02 UTC

[trafficserver] branch 7.1.x updated (e7dda2b -> 44c8d52)

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

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


    from e7dda2b  Fix timing error in the tls_hook10 test.
     new 554400a  Coverity CID #1367529 Copy into fixed size buffer
     new 0a14087  Fix logic for loading config file for url_sig plugin.
     new 7fbc358  Add pparam to url_sig plugin to make it authenticate pristine URL, eliminate sheme check, other minor changes.
     new d621a8d  Add path param url signing option and client ipv6 verification to url_sig.
     new bebe771  Remove use of netstat in tests
     new cd39a6b  Log fields for Connection ID and HTTP/2 Stream ID.
     new 871650c  Remove the use of netstat from ccid_ctid test
     new 44c8d52  Change proxy/logging/LogAccessHttp.h from using 'virtual' to 'override'.

The 8 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/logging/formatting.en.rst          |  27 +-
 doc/admin-guide/plugins/url_sig.en.rst             |  25 +-
 plugins/experimental/url_sig/README                |  57 ++-
 plugins/experimental/url_sig/sign.pl               | 171 +++++++-
 plugins/experimental/url_sig/url_sig.c             | 480 +++++++++++++++------
 plugins/experimental/url_sig/url_sig.h             |   1 +
 proxy/ProxyClientTransaction.h                     |   5 +
 proxy/http/Http1ClientTransaction.h                |  10 +
 proxy/http2/Http2Stream.h                          |  32 +-
 proxy/logging/Log.cc                               |  10 +
 proxy/logging/LogAccess.cc                         |  10 +
 proxy/logging/LogAccess.h                          |  14 +-
 proxy/logging/LogAccessHttp.cc                     |  41 ++
 proxy/logging/LogAccessHttp.h                      | 173 ++++----
 tests/gold_tests/logging/ccid_ctid.test.py         | 102 +++++
 .../init.cli.ext => logging/ccid_ctid_observer.py} |  43 +-
 tests/gold_tests/pluginTest/url_sig/run_sign.sh    | 138 ++++++
 tests/gold_tests/pluginTest/url_sig/url_sig.config |  17 +
 tests/gold_tests/pluginTest/url_sig/url_sig.gold   |  24 ++
 .../gold_tests/pluginTest/url_sig/url_sig.test.py  | 256 +++++++++++
 20 files changed, 1340 insertions(+), 296 deletions(-)
 create mode 100644 tests/gold_tests/logging/ccid_ctid.test.py
 copy tests/gold_tests/{autest-site/init.cli.ext => logging/ccid_ctid_observer.py} (53%)
 create mode 100755 tests/gold_tests/pluginTest/url_sig/run_sign.sh
 create mode 100644 tests/gold_tests/pluginTest/url_sig/url_sig.config
 create mode 100644 tests/gold_tests/pluginTest/url_sig/url_sig.gold
 create mode 100644 tests/gold_tests/pluginTest/url_sig/url_sig.test.py

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.

[trafficserver] 04/08: Add path param url signing option and client ipv6 verification to url_sig.

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

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

commit d621a8d135cf176dc270a22aef8b6fd70940fa42
Author: jrushford <jr...@apache.org>
AuthorDate: Mon Dec 11 21:45:34 2017 +0000

    Add path param url signing option and client ipv6 verification to url_sig.
    
    fix missing single quote in url_sig plugin documentation and double free.
    
    (cherry picked from commit ed479e26e2378b5f0ae5c278dcb3b3d25f0976fa)
---
 doc/admin-guide/plugins/url_sig.en.rst |  15 +-
 plugins/experimental/url_sig/README    |  57 +++++--
 plugins/experimental/url_sig/sign.pl   | 167 ++++++++++++++++++---
 plugins/experimental/url_sig/url_sig.c | 261 +++++++++++++++++++++++++++------
 plugins/experimental/url_sig/url_sig.h |   1 +
 5 files changed, 417 insertions(+), 84 deletions(-)

diff --git a/doc/admin-guide/plugins/url_sig.en.rst b/doc/admin-guide/plugins/url_sig.en.rst
index caee1cf..29b2314 100644
--- a/doc/admin-guide/plugins/url_sig.en.rst
+++ b/doc/admin-guide/plugins/url_sig.en.rst
@@ -152,7 +152,7 @@ will hand back to the client for redirection.
 
 Client IP
     The IP address of the client being redirected. This must be their IP as it
-    will appear to your |TS| cache::
+    will appear to your |TS| cache.  Both IP v4 and v6 addresses are supported::
 
         C=<ip address>
 
@@ -242,6 +242,19 @@ Signature
     portal, refer to the file ``sign.pl`` included with the source code of this
     plugin.
 
+Signature query parameters embedded in the URL path.
+
+    Optionally signature query parameters may be embedded in an opaque base64 encoded container
+    embedded in the URL path.  The format is  a semicolon, siganchor string, base64 encoded 
+    string.  ``url_sig`` automatically detects the use of embedded path parameters. The 
+    following example shows how to generate an embedded path parameters with ``sign.pl``::
+
+      ./sign.pl --url "http://test-remap.domain.com/vod/t/prog_index.m3u8?appid=2&t=1" --useparts 1 \
+      --algorithm 1 --duration 86400 --key kSCE1_uBREdGI3TPnr_dXKc9f_J4ZV2f --pathparams --siganchor urlsig
+
+      curl -s -o /dev/null -v --max-redirs 0 'http://test-remap.domain.com/vod/t;urlsig=O0U9MTQ2MzkyOTM4NTtBPTE7Sz0zO1A9MTtTPTIxYzk2YWRiZWZk'
+
+
 Edge Cache Debugging
 ====================
 
diff --git a/plugins/experimental/url_sig/README b/plugins/experimental/url_sig/README
index b5d8792..12b4929 100644
--- a/plugins/experimental/url_sig/README
+++ b/plugins/experimental/url_sig/README
@@ -37,18 +37,9 @@ Edge cache debugging
 		CONFIG proxy.config.diags.debug.enabled INT 1
 		CONFIG proxy.config.diags.debug.tags STRING url_sig
 
-	and do a traffic_ctl config reload; Debug output will go
-	to traffic.out.  Failed transactions (signature check fails
-	that is) will be logged in to error.log.
-
-Application Query Parameters.
-  If a request to be signed has application query parameters, the signing
-  parameters must be concatenated to the end of the requests application
-  query parameters.  The application query parameters will be included in
-  the signing calculation as determined by the 'Parts' signing explained
-  below.  At the edge after verification of the signing by this plugin,
-  the signing parameters are removed and the application query parameters
-  are preserved in the request.
+	and do a traffic_ctl config reload; Debug output will go to traffic.out.
+	Failed transactions (signature check fails that is) will be logged
+	in to error.log.
 
 Signing a URL
 	At the signing portal take the full URL, without any query string, and
@@ -85,6 +76,31 @@ Signing a URL
 		including "S=".
 		S=<signature>
 
+Signing a URL using path parameters instead of using a query string.
+
+  The parameters above may be embedded in the path part of the request
+  url vs using a query string.  When this method is used, the parameters
+  above are inserted after the path but before the file part of the path
+  in the request url.  Any origin application query parameters then follow
+  the file part of the request and are never part of the sign string.
+
+  Path parameters are separated by a ';' in the path.  The complete signature
+  string is base64 encoded as a single path parameter that is assinged to the 
+  'siganchor', and will appear in that path as siganchor=base64string. The 
+  following is an example signed request using the path parameter method and 
+  with an origin application query string:
+
+  http://ds-01.comcast.net/vod/t;urlsig=O0U9MTQ2MzkyOTYxODtBPTE7Sz0zO1A9MTtTPTEyZDlmN2RiNjUyZWI0YmI4MWYyNmVlMjE3MzczZGE5Y2VkYTRmZGY/Frag10Num10.ts?appid=2&t=1
+
+  Note that the signing string is embedded in the path between the last
+  directory part and before the file part of the request.  Using 'parts' in
+  sign.pl, the signature may be signed accordingly up to S= in the above
+  request. To generate a signed url using this method, use the --pathparams
+  option in sign.pl
+
+
+
+
 
 Example
 	Build, install
@@ -119,7 +135,7 @@ Example
 
 		map http://test-remap.domain.com http://google.com @plugin=url_sig.so @pparam=sign_test.config
 
-	Restart traffic server or "traffic_ctl config reload" - verify there are no errors in diags.log
+	Restart traffic server or traffic_ctl config reload  - verify there are no errors in diags.log
 
 	Try the path unsigned:
 
@@ -151,7 +167,8 @@ Example
 		Authorization Denied$
 		$
 
-	Sign the URL and try it again. Run the script with appropriate params, and it will output the curl line to run:
+	Sign the URL and try it again. Run the script with appropriate params, and
+	it will output the curl line to run:
 
 		$ ./sign.pl --url http://test-remap.domain.com/ --useparts 1 --algorithm 1 --duration 60 --keyindex 3 --key DTV4Tcn046eM9BzJMeYrYpm3kbqOtBs7
 		curl -s -o /dev/null -v --max-redirs 0 'http://test-remap.domain.com/?E=1397603088&A=1&K=3&P=1&S=28d822f68ac7265db61a8441e0877a98fe1007cc'
@@ -190,3 +207,15 @@ Example
 		{ [data not shown]
 		* Connection #0 to host localhost left intact
 		$
+
+Generating a signed URL with path parameters:
+
+  $ ./sign.pl --url "http://test-remap.domain.com/vod/t/prog_index.m3u8?appid=2&t=1" --useparts 1 --algorithm 1 --duration 86400 --keyindex 3 --key kSCE1_uBREdGI3TPnr_dXKc9f_J4ZV2f --pathparams --siganchor urlsig
+
+  curl -s -o /dev/null -v --max-redirs 0 'http://test-remap.domain.com/vod/t;urlsig=O0U9MTQ2MzkyOTM4NTtBPTE7Sz0zO1A9MTtTPTIxYzk2YWRiZWZkOGJkMDFhYmM3MmZkMTEzMWVkMGM5ZmU1ZmFiMjE/prog_index.m3u8?appid=2&t=1'
+
+
+Client IP in the Signing Script
+	Below is an example of how to include client ip in the signing script
+	Works for both IPv4 and IPv6
+	--client 10.10.10.10
diff --git a/plugins/experimental/url_sig/sign.pl b/plugins/experimental/url_sig/sign.pl
index 66fa729..6de4cc6 100755
--- a/plugins/experimental/url_sig/sign.pl
+++ b/plugins/experimental/url_sig/sign.pl
@@ -19,6 +19,7 @@
 use Digest::SHA qw(hmac_sha1 hmac_sha1_hex);
 use Digest::HMAC_MD5 qw(hmac_md5 hmac_md5_hex);
 use Getopt::Long;
+use MIME::Base64::URLSafe ();
 use strict;
 use warnings;
 my $key       = undef;
@@ -31,6 +32,10 @@ my $verbose   = 0;
 my $url       = undef;
 my $client    = undef;
 my $algorithm = 1;
+my $pathparams = 0;
+my $sig_anchor = undef;
+my $proxy = undef;
+my $scheme = "http://";
 
 $result = GetOptions(
 	"url=s"       => \$url,
@@ -40,13 +45,28 @@ $result = GetOptions(
 	"client=s"    => \$client,
 	"algorithm=i" => \$algorithm,
 	"keyindex=i"  => \$keyindex,
-	"verbose"     => \$verbose
+	"verbose"     => \$verbose,
+	"pathparams"  => \$pathparams,
+  "proxy=s"     => \$proxy,
+  "siganchor=s"  => \$sig_anchor
 );
 
 if ( !defined($key) || !defined($url) || !defined($duration) || !defined($keyindex) ) {
 	&help();
 	exit(1);
 }
+if ( defined($proxy) ) {
+  if ($proxy  !~ /http\:\/\/.*\:\d\d/) {
+    &help();
+  }
+}
+
+if ($url =~ m/^https/) {
+  $url =~ s/^https:\/\///;
+  $scheme = "https://";
+} else {
+  $url =~ s/^http:\/\///;
+}
 
 my $url_prefix = $url;
 $url_prefix =~ s/^([^:]*:\/\/).*$/$1/;
@@ -55,7 +75,36 @@ my $i              = 0;
 my $part_active    = 0;
 my $j              = 0;
 my @inactive_parts = ();
-foreach my $part ( split( /\//, $url ) ) {
+
+my $query_params = undef;
+my $urlHasParams = index($url,"?");
+my $file = undef;
+
+my @parts = (split(/\//, $url));
+my $parts_size = scalar(@parts);
+
+if ($pathparams) {
+  if (scalar(@parts) > 1) {
+    $file = pop @parts;
+  } else {
+    print STDERR "\nERROR: No file segment in the path when using --pathparams.\n\n";
+    &help();
+    exit 1;
+  }
+  if($urlHasParams) {
+    $file = (split(/\?/, $file))[0];
+  }
+  $parts_size = scalar(@parts);
+}
+if ($urlHasParams > 0) {
+  if ( ! $pathparams) {
+    ($parts[$parts_size -1], $query_params) = (split(/\?/, $parts[$parts_size - 1]));
+  } else {
+    $query_params = (split(/\?/, $url))[1];
+  }
+}
+
+foreach my $part (@parts) {
 	if ( length($useparts) > $i ) {
 		$part_active = substr( $useparts, $i++, 1 );
 	}
@@ -67,28 +116,42 @@ foreach my $part ( split( /\//, $url ) ) {
 	}
 	$j++;
 }
-my $urlHasParams = index($string,"?");
+
+my $signing_signature = undef;
 
 chop($string);
-if ( defined($client) ) {
-  if ($urlHasParams > 0) {
-	  $string .= "&C=" . $client . "&E=" . ( time() + $duration ) . "&A=" . $algorithm . "&K=" . $keyindex . "&P=" . $useparts . "&S=";
+if ($pathparams) {
+  if ( defined($client) ) {
+    $signing_signature = ";C=" . $client . ";E=" . ( time() + $duration ) . ";A=" . $algorithm . ";K=" . $keyindex . ";P=" . $useparts . ";S=";
+    $string .= $signing_signature;
   }
   else {
-	  $string .= "?C=" . $client . "&E=" . ( time() + $duration ) . "&A=" . $algorithm . "&K=" . $keyindex . "&P=" . $useparts . "&S=";
+    $signing_signature = ";E=" . ( time() + $duration ) . ";A=" . $algorithm . ";K=" . $keyindex . ";P=" . $useparts . ";S=";
+    $string .= $signing_signature;
   }
-}
-else {
-  if ($urlHasParams > 0) {
-	  $string .= "&E=" . ( time() + $duration ) . "&A=" . $algorithm . "&K=" . $keyindex . "&P=" . $useparts . "&S=";
+} else {
+  if ( defined($client) ) {
+    if ($urlHasParams > 0) {
+	    $signing_signature = "?$query_params" . "&C=" . $client . "&E=" . ( time() + $duration ) . "&A=" . $algorithm . "&K=" . $keyindex . "&P=" . $useparts . "&S=";
+      $string .= $signing_signature;
+    }
+    else {
+	    $signing_signature = "?C=" . $client . "&E=" . ( time() + $duration ) . "&A=" . $algorithm . "&K=" . $keyindex . "&P=" . $useparts . "&S=";
+      $string .= $signing_signature;
+    }
   }
   else {
-	  $string .= "?E=" . ( time() + $duration ) . "&A=" . $algorithm . "&K=" . $keyindex . "&P=" . $useparts . "&S=";
+    if ($urlHasParams > 0) {
+	    $signing_signature = "?$query_params" . "&E=" . ( time() + $duration ) . "&A=" . $algorithm . "&K=" . $keyindex . "&P=" . $useparts . "&S=";
+      $string .= $signing_signature;
+    }
+    else {
+	    $signing_signature = "?E=" . ( time() + $duration ) . "&A=" . $algorithm . "&K=" . $keyindex . "&P=" . $useparts . "&S=";
+      $string .= $signing_signature;
+    }
   }
 }
 
-$verbose && print "signed string = " . $string . "\n";
-
 my $digest;
 if ( $algorithm == 1 ) {
 	$digest = hmac_sha1_hex( $string, $key );
@@ -96,16 +159,74 @@ if ( $algorithm == 1 ) {
 else {
 	$digest = hmac_md5_hex( $string, $key );
 }
-if ($urlHasParams == -1) {
-  my $qstring = ( split( /\?/, $string ) )[1];
 
-  print "curl -s -o /dev/null -v --max-redirs 0 '" . $url_prefix . $url . "?" . $qstring . $digest . "'\n";
-}
-else {
-  my $url_noparams = ( split( /\?/, $url ) )[0];
-  my $qstring = ( split( /\?/, $string ) )[1];
+$verbose && print "\nSigned String: $string\n\n";
+$verbose && print "\nUrl: $url\n";
+$verbose && print "\nsigning_signature: $signing_signature\n";
+$verbose && print "\ndigest: $digest\n";
 
-  print "curl -s -o /dev/null -v --max-redirs 0 '" . $url_prefix . $url_noparams . "?" . $qstring . $digest . "'\n";
+if ($urlHasParams == -1) { # no application query parameters.
+    if ( ! defined($proxy)) {
+      if ( ! $pathparams) {
+        print "curl -s -o /dev/null -v --max-redirs 0 '$scheme" . $url . $signing_signature . $digest . "'\n\n";
+      } else {
+        my $index = rindex($url, '/');
+        $url = substr($url,0,$index);
+        my $encoded = MIME::Base64::URLSafe::encode($signing_signature . $digest);
+        if (defined($sig_anchor)) {
+          print "curl -s -o /dev/null -v --max-redirs 0 '$scheme" . $url . ";${sig_anchor}=" . $encoded . "/$file" . "'\n\n";
+        } else {
+          print "curl -s -o /dev/null -v --max-redirs 0 '$scheme" . $url . "/" . $encoded . "/$file" . "'\n\n";
+        }
+      }
+    } else {
+      if ( ! $pathparams) {
+        print "curl -s -o /dev/null -v --max-redirs 0 --proxy $proxy '$scheme" . $url . $signing_signature . $digest .
+          "'\n\n";
+      } else {
+        my $index = rindex($url, '/');
+        $url = substr($url,0,$index);
+        my $encoded = MIME::Base64::URLSafe::encode($signing_signature . $digest);
+        if (defined($sig_anchor)) {
+          print "curl -s -o /dev/null -v --max-redirs 0 --proxy $proxy '$scheme" . $url . ";${sig_anchor}=" . $encoded .  "/$file" . "'\n\n";
+        } else {
+          print "curl -s -o /dev/null -v --max-redirs 0 --proxy $proxy '$scheme" . $url . "/" . $encoded .  "/$file" . "'\n\n";
+        }
+      }
+    }
+} else { # has application parameters.
+    $url = (split(/\?/, $url))[0];
+    if ( ! defined($proxy)) {
+      if ( ! $pathparams) {
+        print "curl -s -o /dev/null -v --max-redirs 0 '$scheme" . $url . $signing_signature . $digest . "'\n\n";
+      } else {
+        my $index = rindex($url, '/');
+        $url = substr($url,0,$index);
+        my $encoded = MIME::Base64::URLSafe::encode($signing_signature . $digest);
+        if (defined($sig_anchor)) {
+          print "curl -s -o /dev/null -v --max-redirs 0 '$scheme" . $url . ";${sig_anchor}=" . $encoded  . "/" . $file . "?$query_params"
+          . "'\n\n";
+        } else {
+          print "curl -s -o /dev/null -v --max-redirs 0 '$scheme" . $url . "/" . $encoded  . "/" . $file . "?$query_params"
+          . "'\n\n";
+        }
+      }
+    } else {
+      if ( ! $pathparams) {
+        print "curl -s -o /dev/null -v --max-redirs 0 --proxy $proxy '$scheme" . $url . $signing_signature . $digest .
+         "'\n\n";
+      } else {
+        my $index = rindex($url, '/');
+        $url = substr($url,0,$index);
+        my $encoded = MIME::Base64::URLSafe::encode($signing_signature . $digest);
+        if (defined($sig_anchor)) {
+          print "curl -s -o /dev/null -v --max-redirs 0 --proxy $proxy '$scheme" . $url . ";${sig_anchor}=" . $encoded  . "/" . $file . "?$query_params"
+          . "'\n\n";
+        } else {
+          print "curl -s -o /dev/null -v --max-redirs 0 --proxy $proxy '$scheme" . $url . "/" . $encoded .  "/$file?$query_params" . "'\n\n";
+        }
+      }
+    }
 }
 
 sub help {
@@ -119,5 +240,7 @@ sub help {
 	print "             [--client <value>] \\ \n";
 	print "             --key <value>  \\ \n";
 	print "             [--verbose] \n";
+	print "             [--pathparams] \n";
+	print "             [--proxy <url:port value>] ex value: http://myproxy:80\n";
 	print "\n";
 }
diff --git a/plugins/experimental/url_sig/url_sig.c b/plugins/experimental/url_sig/url_sig.c
index da9be83..cd4ebeb 100644
--- a/plugins/experimental/url_sig/url_sig.c
+++ b/plugins/experimental/url_sig/url_sig.c
@@ -39,6 +39,7 @@
 #include <limits.h>
 #include <ctype.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 #ifdef HAVE_PCRE_PCRE_H
 #include <pcre/pcre.h>
@@ -58,6 +59,7 @@ struct config {
   pcre *regex;
   pcre_extra *regex_extra;
   int pristine_url_flag;
+  char *sig_anchor;
 };
 
 static void
@@ -65,6 +67,7 @@ free_cfg(struct config *cfg)
 {
   TSError("[url_sig] Cleaning up...");
   TSfree(cfg->err_url);
+  TSfree(cfg->sig_anchor);
 
   if (cfg->regex_extra) {
 #ifndef PCRE_STUDY_JIT_COMPILE
@@ -193,6 +196,8 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
       } else {
         cfg->err_url = NULL;
       }
+    } else if (strncmp(line, "sig_anchor", 10) == 0) {
+      cfg->sig_anchor = TSstrndup(value, strlen(value));
     } else if (strncmp(line, "excl_regex", 10) == 0) {
       // compile and study regex
       const char *errptr;
@@ -326,6 +331,129 @@ getAppQueryString(const char *query_string, int query_length)
   }
 }
 
+static char *
+urlParse(char *url, char *anchor, char *new_path_seg, int new_path_seg_len, char *signed_seg, unsigned int signed_seg_len)
+{
+  char *segment[MAX_SEGMENTS];
+  unsigned char decoded_string[2048] = {'\0'};
+  char new_url[8192]                 = {'\0'};
+  char *p = NULL, *sig_anchor = NULL, *saveptr = NULL;
+  int i = 0, numtoks = 0, cp_len = 0, l, decoded_len = 0, sig_anchor_seg = 0;
+
+  char *skip = strchr(url, ':');
+  if (!skip || skip[1] != '/' || skip[2] != '/') {
+    return NULL;
+  }
+  skip += 3;
+  // preserve the scheme in the new_url.
+  strncat(new_url, url, skip - url);
+  TSDebug(PLUGIN_NAME, "%s:%d - new_url: %s\n", __FILE__, __LINE__, new_url);
+
+  // parse the url.
+  if ((p = strtok_r(skip, "/", &saveptr)) != NULL) {
+    segment[numtoks++] = p;
+    do {
+      p = strtok_r(NULL, "/", &saveptr);
+      if (p != NULL) {
+        segment[numtoks] = p;
+        if (anchor != NULL && sig_anchor_seg == 0) {
+          // look for the signed anchor string.
+          if ((sig_anchor = strcasestr(segment[numtoks], anchor)) != NULL) {
+            // null terminate this segment just before he signing anchor, this should be a ';'.
+            *(sig_anchor - 1) = '\0';
+            if ((sig_anchor = strstr(sig_anchor, "=")) != NULL) {
+              *sig_anchor = '\0';
+              sig_anchor++;
+              sig_anchor_seg = numtoks;
+            }
+          }
+        }
+        numtoks++;
+      }
+    } while (p != NULL && numtoks < MAX_SEGMENTS);
+  } else {
+    return NULL;
+  }
+  if ((numtoks >= MAX_SEGMENTS) || (numtoks < 3)) {
+    return NULL;
+  }
+
+  // create a new path string for later use when dealing with query parameters.
+  // this string will not contain the signing parameters.  skips the fqdn by
+  // starting with segment 1.
+  for (i = 1; i < numtoks; i++) {
+    // if no signing anchor is found, skip the signed parameters segment.
+    if (sig_anchor == NULL && i == numtoks - 2) {
+      // the signing parameters when no signature anchor is found, should be in the
+      // last path segment so skip them.
+      continue;
+    }
+    l = strlen(segment[i]);
+    if (l + 1 > new_path_seg_len) {
+      TSError("insuficient space to copy into new_path_seg buffer.");
+      return NULL;
+    } else {
+      strncat(new_path_seg, segment[i], l);
+      if (i != numtoks - 1) {
+        strncat(new_path_seg, "/", 1);
+      }
+      cp_len += l + 1;
+    }
+  }
+  TSDebug(PLUGIN_NAME, "new_path_seg: %s", new_path_seg);
+
+  // save the encoded signing parameter data
+  if (sig_anchor != NULL) { // a signature anchor string was found.
+    if (strlen(sig_anchor) < signed_seg_len) {
+      strncpy(signed_seg, sig_anchor, strlen(sig_anchor));
+    } else {
+      TSError("insuficient space to copy into new_path_seg buffer.");
+    }
+  } else { // no signature anchor string was found, assum it is in the last path segment.
+    if (strlen(segment[numtoks - 2]) < signed_seg_len) {
+      strncpy(signed_seg, segment[numtoks - 2], strlen(segment[numtoks - 2]));
+    } else {
+      TSError("insuficient space to copy into new_path_seg buffer.");
+      return NULL;
+    }
+  }
+  TSDebug(PLUGIN_NAME, "signed_seg: %s", signed_seg);
+
+  // no signature anchor was found so decode and save the signing parameters assumed
+  // to be in the last path segment.
+  if (sig_anchor == NULL) {
+    if (TSBase64Decode(segment[numtoks - 2], strlen(segment[numtoks - 2]), decoded_string, sizeof(decoded_string),
+                       (size_t *)&decoded_len) != TS_SUCCESS) {
+      TSDebug(PLUGIN_NAME, "Unable to decode the  path parameter string.");
+    }
+  } else {
+    if (TSBase64Decode(sig_anchor, strlen(sig_anchor), decoded_string, sizeof(decoded_string), (size_t *)&decoded_len) !=
+        TS_SUCCESS) {
+      TSDebug(PLUGIN_NAME, "Unable to decode the  path parameter string.");
+    }
+  }
+  TSDebug(PLUGIN_NAME, "decoded_string: %s", decoded_string);
+
+  for (i = 0; i < numtoks; i++) {
+    // cp the base64 decoded string.
+    if (i == sig_anchor_seg && sig_anchor != NULL) {
+      strncat(new_url, segment[i], strlen(segment[i]));
+      strncat(new_url, (char *)decoded_string, strlen((char *)decoded_string));
+      strncat(new_url, "/", 1);
+      continue;
+    } else if (i == numtoks - 2 && sig_anchor == NULL) {
+      strncat(new_url, (char *)decoded_string, strlen((char *)decoded_string));
+      strncat(new_url, "/", 1);
+      continue;
+    }
+    strncat(new_url, segment[i], strlen(segment[i]));
+    if (i < numtoks - 1) {
+      strncat(new_url, "/", 1);
+    }
+  }
+  return TSstrndup(new_url, strlen(new_url));
+}
+
 TSRemapStatus
 TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
 {
@@ -341,23 +469,21 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
   unsigned int i       = 0;
   int j                = 0;
   unsigned int sig_len = 0;
+  bool has_path_params = false;
 
   /* all strings are locally allocated except url... about 25k per instance */
-  char *const current_url    = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &current_url_len);
-  const char *url            = current_url;
-  char signed_part[8192]     = {'\0'}; // this initializes the whole array and is needed
-  char urltokstr[8192]       = {'\0'};
-  char client_ip[CIP_STRLEN] = {'\0'};
-  char ipstr[CIP_STRLEN]     = {'\0'};
+  char *const current_url = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &current_url_len);
+  char *url               = current_url;
+  char path_params[8192] = {'\0'}, new_path[8192] = {'\0'};
+  char signed_part[8192]           = {'\0'}; // this initializes the whole array and is needed
+  char urltokstr[8192]             = {'\0'};
+  char client_ip[INET6_ADDRSTRLEN] = {'\0'}; // chose the larger ipv6 size
+  char ipstr[INET6_ADDRSTRLEN]     = {'\0'}; // chose the larger ipv6 size
   unsigned char sig[MAX_SIG_SIZE + 1];
   char sig_string[2 * MAX_SIG_SIZE + 1];
 
-  int retval, sockfd;
-  socklen_t peer_len;
-  struct sockaddr_in peer;
-
   if (current_url_len >= MAX_REQ_LEN - 1) {
-    err_log(current_url, "URL string too long.");
+    err_log(url, "URL string too long");
     goto deny;
   }
 
@@ -400,49 +526,80 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
     }
   }
 
-  if (query == NULL) {
-    err_log(url, "Has no query string.");
-    goto deny;
+  // check for path params.
+  if (query == NULL || strstr(query, "E=") == NULL) {
+    if ((url = urlParse(url, cfg->sig_anchor, new_path, 8192, path_params, 8192)) == NULL) {
+      err_log(url, "Has no signing query string or signing path parameters.");
+      goto deny;
+    }
+    has_path_params = true;
+    query           = strstr(url, ";");
+
+    if (query == NULL) {
+      err_log(url, "Has no signing query string or signing path parameters.");
+      goto deny;
+    }
   }
 
   /* first, parse the query string */
-  query++; /* get rid of the ? */
+  if (!has_path_params) {
+    query++; /* get rid of the ? */
+  }
   TSDebug(PLUGIN_NAME, "Query string is:%s", query);
 
   // Client IP - this one is optional
   const char *cp = strstr(query, CIP_QSTRING "=");
+  const char *pp = NULL;
   if (cp != NULL) {
-    int len_cip_qstring = strlen(CIP_QSTRING);
-    cp += len_cip_qstring - 1;
-    const char *cpp = strchr(cp, '&');
-    if (!cpp) {
-      err_log(url, "All required values after IP address string missing");
-      goto deny;
-    }
-    if (!cpp || (cpp - cp) > CIP_STRLEN - 1 || (cpp - cp) < 4) {
-      err_log(url, "IP address string too long or short");
-      goto deny;
-    }
-    memcpy(client_ip, cp + len_cip_qstring + 1, (cpp - cp - (len_cip_qstring + 1)));
-    client_ip[cpp - cp - (len_cip_qstring + 1)] = '\0';
-    TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ip);
-    retval = TSHttpTxnClientFdGet(txnp, &sockfd);
-    if (retval != TS_SUCCESS) {
-      err_log(url, "Error getting sockfd.");
-      goto deny;
-    }
-    peer_len = sizeof(peer);
-    if (getpeername(sockfd, (struct sockaddr *)&peer, &peer_len) != 0) {
-      perror("Can't get peer address:");
-    }
-    struct sockaddr_in *s = (struct sockaddr_in *)&peer;
-    inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
-    TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr);
-    if (strcmp(ipstr, client_ip) != 0) {
-      err_log(url, "Client IP doesn't match signature.");
+    cp += (strlen(CIP_QSTRING) + 1);
+    struct sockaddr const *ip = TSHttpTxnClientAddrGet(txnp);
+    if (ip == NULL) {
+      TSError("Can't get client ip address.");
       goto deny;
+    } else {
+      switch (ip->sa_family) {
+      case AF_INET:
+        TSDebug(PLUGIN_NAME, "ip->sa_family: AF_INET");
+        has_path_params == false ? (pp = strstr(cp, "&")) : (pp = strstr(cp, ";"));
+        if ((pp - cp) > INET_ADDRSTRLEN - 1 || (pp - cp) < 4) {
+          err_log(url, "IP address string too long or short.");
+          goto deny;
+        }
+        strncpy(client_ip, cp, (pp - cp));
+        client_ip[pp - cp] = '\0';
+        TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ip);
+        inet_ntop(AF_INET, &(((struct sockaddr_in *)ip)->sin_addr), ipstr, sizeof ipstr);
+        TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr);
+        if (strcmp(ipstr, client_ip) != 0) {
+          err_log(url, "Client IP doesn't match signature.");
+          goto deny;
+        }
+        break;
+      case AF_INET6:
+        TSDebug(PLUGIN_NAME, "ip->sa_family: AF_INET6");
+        has_path_params == false ? (pp = strstr(cp, "&")) : (pp = strstr(cp, ";"));
+        if ((pp - cp) > INET6_ADDRSTRLEN - 1 || (pp - cp) < 4) {
+          err_log(url, "IP address string too long or short.");
+          goto deny;
+        }
+        strncpy(client_ip, cp, (pp - cp));
+        client_ip[pp - cp] = '\0';
+        TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ip);
+        inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)ip)->sin6_addr), ipstr, sizeof ipstr);
+        TSDebug(PLUGIN_NAME, "Peer address: -%s-", ipstr);
+        if (strcmp(ipstr, client_ip) != 0) {
+          err_log(url, "Client IP doesn't match signature.");
+          goto deny;
+        }
+        break;
+      default:
+        TSError("%s: Unknown address family %d", PLUGIN_NAME, ip->sa_family);
+        goto deny;
+        break;
+      }
     }
   }
+
   // Expiration
   cp = strstr(query, EXP_QSTRING "=");
   if (cp != NULL) {
@@ -487,7 +644,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
   if (cp != NULL) {
     cp += strlen(PAR_QSTRING) + 1;
     parts = cp; // NOTE parts is not NULL terminated it is terminated by "&" of next param
-    cp    = strchr(parts, '&');
+    has_path_params == false ? (cp = strstr(parts, "&")) : (cp = strstr(parts, ";"));
     if (cp) {
       TSDebug(PLUGIN_NAME, "Parts: %.*s", (int)(cp - parts), parts);
     } else {
@@ -518,7 +675,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
           keyindex, parts, signature);
 
   /* find the string that was signed - cycle through the parts letters, adding the part of the fqdn/path if it is 1 */
-  cp = strchr(url, '?');
+  has_path_params == false ? (cp = strchr(url, '?')) : (cp = strchr(url, ';'));
   // Skip scheme and initial forward slashes.
   const char *skip = strchr(url, ':');
   if (!skip || skip[1] != '/' || skip[2] != '/') {
@@ -540,8 +697,10 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
     part = strtok_r(NULL, "/", &strtok_r_p);
   }
 
-  signed_part[strlen(signed_part) - 1] = '?'; // chop off the last /, replace with '?'
-  cp                                   = strstr(query, SIG_QSTRING "=");
+  // chop off the last /, replace with '?' or ';' as appropriate.
+  has_path_params == false ? (signed_part[strlen(signed_part) - 1] = '?') : (signed_part[strlen(signed_part) - 1] = '\0');
+  cp = strstr(query, SIG_QSTRING "=");
+  TSDebug(PLUGIN_NAME, "cp: %s, query: %s, signed_part: %s", cp, query, signed_part);
   strncat(signed_part, query, (cp - query) + strlen(SIG_QSTRING) + 1);
 
   TSDebug(PLUGIN_NAME, "Signed string=\"%s\"", signed_part);
@@ -627,6 +786,13 @@ allow:
     current_query++;
     app_qry = getAppQueryString(current_query, strlen(current_query));
   }
+  TSDebug(PLUGIN_NAME, "has_path_params: %d", has_path_params);
+  if (has_path_params) {
+    if (*new_path) {
+      TSUrlPathSet(rri->requestBufp, rri->requestUrl, new_path, strlen(new_path));
+    }
+    TSUrlHttpParamsSet(rri->requestBufp, rri->requestUrl, NULL, 0);
+  }
 
   TSfree((void *)current_url);
 
@@ -640,5 +806,6 @@ allow:
   if (rval != TS_SUCCESS) {
     TSError("[url_sig] Error setting the query string: %d.", rval);
   }
+
   return TSREMAP_NO_REMAP;
 }
diff --git a/plugins/experimental/url_sig/url_sig.h b/plugins/experimental/url_sig/url_sig.h
index 46e8e72..d5fbb95 100644
--- a/plugins/experimental/url_sig/url_sig.h
+++ b/plugins/experimental/url_sig/url_sig.h
@@ -35,6 +35,7 @@
 #define EXP_STRLEN 16
 #define PAR_STRLEN 16
 #define MAX_PARTS 32
+#define MAX_SEGMENTS 64
 
 #define MAX_HTTP_REQUEST_SIZE 8192 //
 

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.

[trafficserver] 07/08: Remove the use of netstat from ccid_ctid test

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

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

commit 871650c5d86b681f9f676f41c8f84200b8f60300
Author: Jeffrey Bevill <je...@gmail.com>
AuthorDate: Wed Mar 7 19:24:03 2018 -0700

    Remove the use of netstat from ccid_ctid test
---
 tests/gold_tests/logging/ccid_ctid.test.py | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/tests/gold_tests/logging/ccid_ctid.test.py b/tests/gold_tests/logging/ccid_ctid.test.py
index ef60083..f5b4e20 100644
--- a/tests/gold_tests/logging/ccid_ctid.test.py
+++ b/tests/gold_tests/logging/ccid_ctid.test.py
@@ -69,14 +69,9 @@ log.ascii {
 }'''.split("\n")
 )
 
-# Ask the OS if the port is ready for connect()
-#
-def CheckPort(Port):
-    return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q :{}'.format(Port), shell=True)
-
 tr = Test.AddTestRun()
 # Delay on readiness of ssl port
-tr.Processes.Default.StartBefore(Test.Processes.ts, ready=CheckPort(ts.Variables.ssl_port))
+tr.Processes.Default.StartBefore(Test.Processes.ts, ready=When.PortOpen(ts.Variables.ssl_port))
 #
 tr.Processes.Default.Command = 'curl "http://127.0.0.1:{0}" --verbose'.format(
     ts.Variables.port)

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.

[trafficserver] 05/08: Remove use of netstat in tests

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

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

commit bebe771302b4c33f0ff8163016efb52d88d5011a
Author: Jason Kenny <dr...@live.com>
AuthorDate: Thu Jan 4 17:18:18 2018 -0600

    Remove use of netstat in tests
    
    update autest to 1.4.2 as this has fix for portopen to be like netstat, but portable
    Add to traffic_layout the reporting of brotli as a feature
    update tests to test for brotli
    change test to use dynamic ports
    
    (cherry picked from commit 87a873cbd820634a75c4a6ccece1753d35660bde)
---
 tests/gold_tests/logging/ccid_ctid.test.py          | 13 ++-----------
 tests/gold_tests/pluginTest/url_sig/url_sig.test.py | 13 ++++---------
 2 files changed, 6 insertions(+), 20 deletions(-)

diff --git a/tests/gold_tests/logging/ccid_ctid.test.py b/tests/gold_tests/logging/ccid_ctid.test.py
index 5236313..b990891 100644
--- a/tests/gold_tests/logging/ccid_ctid.test.py
+++ b/tests/gold_tests/logging/ccid_ctid.test.py
@@ -28,8 +28,7 @@ Test.SkipUnless(
         "curl", "Curl need to be installed on system for this test to work"),
     # Condition.IsPlatform("linux"), Don't see the need for this.
     Condition.HasATSFeature('TS_USE_TLS_ALPN'),
-    Condition.HasCurlFeature('http2'),
-    Condition.HasProgram("netstat", "netstat need to be installed on system for this test to work")
+    Condition.HasCurlFeature('http2')
 )
 
 # Define default ATS.  "select_ports=False" needed because SSL port used.
@@ -70,17 +69,9 @@ log.ascii {
 }'''.split("\n")
 )
 
-# Ask the OS if the port is ready for connect()
-#
-
-
-def CheckPort(Port):
-    return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q :{}'.format(Port), shell=True)
-
-
 tr = Test.AddTestRun()
 # Delay on readiness of ssl port
-tr.Processes.Default.StartBefore(Test.Processes.ts, ready=CheckPort(ts.Variables.ssl_port))
+tr.Processes.Default.StartBefore(Test.Processes.ts, ready=When.PortOpen(ts.Variables.ssl_port))
 #
 tr.Processes.Default.Command = 'curl "http://127.0.0.1:{0}" --verbose'.format(
     ts.Variables.port)
diff --git a/tests/gold_tests/pluginTest/url_sig/url_sig.test.py b/tests/gold_tests/pluginTest/url_sig/url_sig.test.py
index 78b0228..26d92d3 100644
--- a/tests/gold_tests/pluginTest/url_sig/url_sig.test.py
+++ b/tests/gold_tests/pluginTest/url_sig/url_sig.test.py
@@ -56,8 +56,8 @@ ts.Variables.ssl_port = 4443
 ts.Disk.records_config.update({
     # 'proxy.config.diags.debug.enabled': 1,
     # 'proxy.config.diags.debug.tags': 'http|url_sig',
-    'proxy.config.http.cache.http': 0, # Make sure each request is forwarded to the origin server.
-    'proxy.config.proxy_name': 'Poxy_Proxy', # This will be the server name.
+    'proxy.config.http.cache.http': 0,  # Make sure each request is forwarded to the origin server.
+    'proxy.config.proxy_name': 'Poxy_Proxy',  # This will be the server name.
     'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
     'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
     'proxy.config.http.server_ports': (
@@ -97,11 +97,6 @@ ts.Disk.remap_config.AddLine(
     ' @plugin=url_sig.so @pparam={}/url_sig.config @pparam=PristineUrl'.format(Test.TestDirectory)
 )
 
-# Ask the OS if the port is ready for connect()
-#
-def CheckPort(Port):
-    return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q :{}'.format(Port), shell=True)
-
 # Validation failure tests.
 
 LogTee = " 2>&1 | tee -a {}/url_sig_long.log".format(Test.RunDirectory)
@@ -109,8 +104,8 @@ LogTee = " 2>&1 | tee -a {}/url_sig_long.log".format(Test.RunDirectory)
 # Bad client / MD5 / P=101 / URL pristine / URL altered.
 #
 tr = Test.AddTestRun()
-tr.Processes.Default.StartBefore(ts, ready=CheckPort(ts.Variables.ssl_port))
-tr.Processes.Default.StartBefore(server, ready=CheckPort(server.Variables.Port))
+tr.Processes.Default.StartBefore(ts, ready=When.PortOpen(ts.Variables.ssl_port))
+tr.Processes.Default.StartBefore(server, ready=When.PortOpen(server.Variables.Port))
 tr.Processes.Default.ReturnCode = 0
 tr.Processes.Default.Command = (
     "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.

[trafficserver] 03/08: Add pparam to url_sig plugin to make it authenticate pristine URL, eliminate sheme check, other minor changes.

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

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

commit 7fbc358e2ae5f9715b19aad1169582f44caf304e
Author: Walt Karas <wk...@yahoo-inc.com>
AuthorDate: Tue Nov 7 17:11:10 2017 +0000

    Add pparam to url_sig plugin to make it authenticate pristine URL, eliminate sheme check, other minor changes.
    
    (cherry picked from commit 5fe7236975506514ed79d9f624c28bb84e60af60)
---
 doc/admin-guide/plugins/url_sig.en.rst             |  10 +-
 plugins/experimental/url_sig/sign.pl               |   8 +-
 plugins/experimental/url_sig/url_sig.c             | 238 +++++++++++--------
 tests/gold_tests/logging/ccid_ctid.test.py         | 111 +++++++++
 tests/gold_tests/pluginTest/url_sig/run_sign.sh    | 138 +++++++++++
 tests/gold_tests/pluginTest/url_sig/url_sig.config |  17 ++
 tests/gold_tests/pluginTest/url_sig/url_sig.gold   |  24 ++
 .../gold_tests/pluginTest/url_sig/url_sig.test.py  | 261 +++++++++++++++++++++
 8 files changed, 703 insertions(+), 104 deletions(-)

diff --git a/doc/admin-guide/plugins/url_sig.en.rst b/doc/admin-guide/plugins/url_sig.en.rst
index cabbcf1..caee1cf 100644
--- a/doc/admin-guide/plugins/url_sig.en.rst
+++ b/doc/admin-guide/plugins/url_sig.en.rst
@@ -110,12 +110,14 @@ To require a valid signature, verified by a key from the list you generated
 earlier, modify your :file:`remap.config` configuration to include this plugin
 for any rules you wish it to affect.
 
-Two parameters for each remap rule are required::
+Two parameters for each remap rule are required, and a third one is optional::
 
-    @plugin=url_sig.so @pparam=<config file>
+    @plugin=url_sig.so @pparam=<config file> @pparam=pristineurl
 
 The first simply enables this plugin for the rule. The second specifies the
-location of the configuration file containing your signing keys.
+location of the configuration file containing your signing keys.  The third one,
+if present, causes authentication to be performed on the original (pristine) URL
+as received from the client. (The value of the parameter is not case sensitive.)
 
 For example, if we wanted to restrict all paths under a ``/download`` directory
 on our website ``foo.com`` we might have a remap line like this::
@@ -184,7 +186,7 @@ Key Index
 
 Parts
     Configures which components of the URL to use for signature verification.
-    The value of this paramerts is a string of ones and zeroes, each enabling
+    The value of this parameter is a string of ones and zeroes, each enabling
     or disabling the use of a URL part for signatures. The URL scheme (e.g.
     ``http://``) is never part of the signature. The first number of this
     parameter's value indicates whether to include the FQDN, and all remaining
diff --git a/plugins/experimental/url_sig/sign.pl b/plugins/experimental/url_sig/sign.pl
index 7f2cc7b..66fa729 100755
--- a/plugins/experimental/url_sig/sign.pl
+++ b/plugins/experimental/url_sig/sign.pl
@@ -48,7 +48,9 @@ if ( !defined($key) || !defined($url) || !defined($duration) || !defined($keyind
 	exit(1);
 }
 
-$url =~ s/^http:\/\///;
+my $url_prefix = $url;
+$url_prefix =~ s/^([^:]*:\/\/).*$/$1/;
+$url =~ s/^[^:]+:\/\///;
 my $i              = 0;
 my $part_active    = 0;
 my $j              = 0;
@@ -97,13 +99,13 @@ else {
 if ($urlHasParams == -1) {
   my $qstring = ( split( /\?/, $string ) )[1];
 
-  print "curl -s -o /dev/null -v --max-redirs 0 'http://" . $url . "?" . $qstring . $digest . "'\n";
+  print "curl -s -o /dev/null -v --max-redirs 0 '" . $url_prefix . $url . "?" . $qstring . $digest . "'\n";
 }
 else {
   my $url_noparams = ( split( /\?/, $url ) )[0];
   my $qstring = ( split( /\?/, $string ) )[1];
 
-  print "curl -s -o /dev/null -v --max-redirs 0 'http://" . $url_noparams . "?" . $qstring . $digest . "'\n";
+  print "curl -s -o /dev/null -v --max-redirs 0 '" . $url_prefix . $url_noparams . "?" . $qstring . $digest . "'\n";
 }
 
 sub help {
diff --git a/plugins/experimental/url_sig/url_sig.c b/plugins/experimental/url_sig/url_sig.c
index 9923693..da9be83 100644
--- a/plugins/experimental/url_sig/url_sig.c
+++ b/plugins/experimental/url_sig/url_sig.c
@@ -38,6 +38,7 @@
 #include <arpa/inet.h>
 #include <limits.h>
 #include <ctype.h>
+#include <stdint.h>
 
 #ifdef HAVE_PCRE_PCRE_H
 #include <pcre/pcre.h>
@@ -48,7 +49,7 @@
 #include <ts/ts.h>
 #include <ts/remap.h>
 
-static const char *PLUGIN_NAME = "url_sig";
+static const char PLUGIN_NAME[] = "url_sig";
 
 struct config {
   TSHttpStatus err_status;
@@ -56,6 +57,7 @@ struct config {
   char keys[MAX_KEY_NUM][MAX_KEY_LEN];
   pcre *regex;
   pcre_extra *regex_extra;
+  int pristine_url_flag;
 };
 
 static void
@@ -83,12 +85,12 @@ TSReturnCode
 TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
 {
   if (!api_info) {
-    strncpy(errbuf, "[tsremap_init] - Invalid TSRemapInterface argument", (size_t)(errbuf_size - 1));
+    snprintf(errbuf, errbuf_size, "[tsremap_init] - Invalid TSRemapInterface argument");
     return TS_ERROR;
   }
 
   if (api_info->tsremap_version < TSREMAP_VERSION) {
-    snprintf(errbuf, errbuf_size - 1, "[TSRemapInit] - Incorrect API version %ld.%ld", api_info->tsremap_version >> 16,
+    snprintf(errbuf, errbuf_size, "[TSRemapInit] - Incorrect API version %ld.%ld", api_info->tsremap_version >> 16,
              (api_info->tsremap_version & 0xffff));
     return TS_ERROR;
   }
@@ -104,9 +106,11 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
   char config_filepath_buf[PATH_MAX], *config_file;
   struct config *cfg;
 
-  if (argc != 3) {
-    snprintf(errbuf, errbuf_size - 1,
-             "[TSRemapNewKeyInstance] - Argument count wrong (%d)... Need exactly two pparam= (config file name).", argc);
+  if ((argc < 3) || (argc > 4)) {
+    snprintf(errbuf, errbuf_size,
+             "[TSRemapNewInstance] - Argument count wrong (%d)... config file path is required first pparam, \"pristineurl\" is"
+             "optional second pparam.",
+             argc);
     return TS_ERROR;
   }
   TSDebug(PLUGIN_NAME, "Initializing remap function of %s -> %s with config from %s", argv[0], argv[1], argv[2]);
@@ -120,7 +124,7 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
   TSDebug(PLUGIN_NAME, "config file name: %s", config_file);
   FILE *file = fopen(config_file, "r");
   if (file == NULL) {
-    snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Error opening file %s.", config_file);
+    snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Error opening file %s", config_file);
     return TS_ERROR;
   }
 
@@ -170,13 +174,12 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
       }
       TSDebug(PLUGIN_NAME, "key number %d == %s", keynum, value);
       if (keynum >= MAX_KEY_NUM || keynum < 0) {
-        snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Key number (%d) >= MAX_KEY_NUM (%d) or NaN.", keynum,
-                 MAX_KEY_NUM);
+        snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Key number (%d) >= MAX_KEY_NUM (%d) or NaN", keynum, MAX_KEY_NUM);
         fclose(file);
         free_cfg(cfg);
         return TS_ERROR;
       }
-      strncpy(&cfg->keys[keynum][0], value, MAX_KEY_LEN - 1);
+      snprintf(&cfg->keys[keynum][0], MAX_KEY_LEN, "%s", value);
     } else if (strncmp(line, "error_url", 9) == 0) {
       if (atoi(value)) {
         cfg->err_status = atoi(value);
@@ -215,32 +218,40 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
     }
   }
 
+  fclose(file);
+
+  if (argc > 3) {
+    if (strcasecmp(argv[3], "pristineurl") == 0) {
+      cfg->pristine_url_flag = 1;
+
+    } else {
+      snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - second pparam (if present) must be pristineurl");
+      free_cfg(cfg);
+      return TS_ERROR;
+    }
+  }
+
   switch (cfg->err_status) {
   case TS_HTTP_STATUS_MOVED_TEMPORARILY:
     if (cfg->err_url == NULL) {
-      snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Invalid config, err_status == 302, but err_url == NULL");
-      fclose(file);
+      snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Invalid config, err_status == 302, but err_url == NULL");
       free_cfg(cfg);
       return TS_ERROR;
     }
     break;
   case TS_HTTP_STATUS_FORBIDDEN:
     if (cfg->err_url != NULL) {
-      snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Invalid config, err_status == 403, but err_url != NULL");
-      fclose(file);
+      snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Invalid config, err_status == 403, but err_url != NULL");
       free_cfg(cfg);
       return TS_ERROR;
     }
     break;
   default:
-    snprintf(errbuf, errbuf_size - 1, "[TSRemapNewInstance] - Return code %d not supported.", cfg->err_status);
-    fclose(file);
+    snprintf(errbuf, errbuf_size, "[TSRemapNewInstance] - Return code %d not supported", cfg->err_status);
     free_cfg(cfg);
     return TS_ERROR;
   }
 
-  fclose(file);
-
   *ih = (void *)cfg;
   return TS_SUCCESS;
 }
@@ -252,7 +263,7 @@ TSRemapDeleteInstance(void *ih)
 }
 
 static void
-err_log(char *url, char *msg)
+err_log(const char *url, const char *msg)
 {
   if (msg && url) {
     TSDebug(PLUGIN_NAME, "[URL=%s]: %s", url, msg);
@@ -265,18 +276,18 @@ err_log(char *url, char *msg)
 // See the README.  All Signing parameters must be concatenated to the end
 // of the url and any application query parameters.
 static char *
-getAppQueryString(char *query_string, unsigned int query_length)
+getAppQueryString(const char *query_string, int query_length)
 {
   int done = 0;
   char *p;
-  char buf[MAX_QUERY_LEN];
+  char buf[MAX_QUERY_LEN + 1];
 
-  if (query_length >= sizeof(buf)) {
+  if (query_length > MAX_QUERY_LEN) {
     TSDebug(PLUGIN_NAME, "Cannot process the query string as the length exceeds %d bytes", MAX_QUERY_LEN);
     return NULL;
   }
-  memset(buf, 0, MAX_QUERY_LEN);
-  strncpy(buf, query_string, min(query_length, sizeof(buf) - 1));
+  memset(buf, 0, sizeof(buf));
+  strncpy(buf, query_string, query_length);
   p = buf;
 
   TSDebug(PLUGIN_NAME, "query_string: %s, query_length: %d", query_string, query_length);
@@ -290,7 +301,7 @@ getAppQueryString(char *query_string, unsigned int query_length)
     case 'P':
     case 'S':
       done = 1;
-      if (*(p - 1) == '&') {
+      if ((p > buf) && (*(p - 1) == '&')) {
         *(p - 1) = '\0';
       } else {
         (*p = '\0');
@@ -318,13 +329,13 @@ getAppQueryString(char *query_string, unsigned int query_length)
 TSRemapStatus
 TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
 {
-  struct config *cfg;
-  cfg = (struct config *)ih;
+  const struct config *cfg = (const struct config *)ih;
 
-  int url_len       = 0;
-  time_t expiration = 0;
-  int algorithm     = -1;
-  int keyindex      = -1;
+  int url_len         = 0;
+  int current_url_len = 0;
+  uint64_t expiration = 0;
+  int algorithm       = -1;
+  int keyindex        = -1;
   int cmp_res;
   int rval;
   unsigned int i       = 0;
@@ -332,7 +343,8 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
   unsigned int sig_len = 0;
 
   /* all strings are locally allocated except url... about 25k per instance */
-  char *url;
+  char *const current_url    = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &current_url_len);
+  const char *url            = current_url;
   char signed_part[8192]     = {'\0'}; // this initializes the whole array and is needed
   char urltokstr[8192]       = {'\0'};
   char client_ip[CIP_STRLEN] = {'\0'};
@@ -340,33 +352,42 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
   unsigned char sig[MAX_SIG_SIZE + 1];
   char sig_string[2 * MAX_SIG_SIZE + 1];
 
-  /* these are just pointers into other allocations */
-  char *signature = NULL;
-  char *parts     = NULL;
-  char *part      = NULL;
-  char *p = NULL, *pp = NULL;
-  char *query = NULL, *app_qry = NULL;
-
   int retval, sockfd;
   socklen_t peer_len;
   struct sockaddr_in peer;
 
-  url = TSUrlStringGet(rri->requestBufp, rri->requestUrl, &url_len);
-
-  if (url_len >= MAX_REQ_LEN - 1) {
-    err_log(url, "URL string too long.");
+  if (current_url_len >= MAX_REQ_LEN - 1) {
+    err_log(current_url, "URL string too long.");
     goto deny;
   }
 
+  if (cfg->pristine_url_flag) {
+    TSMBuffer mbuf;
+    TSMLoc ul;
+    TSReturnCode rc = TSHttpTxnPristineUrlGet(txnp, &mbuf, &ul);
+    if (rc != TS_SUCCESS) {
+      TSError("[url_sig] Failed call to TSHttpTxnPristineUrlGet()");
+      goto deny;
+    }
+    url = TSUrlStringGet(mbuf, ul, &url_len);
+    if (url_len >= MAX_REQ_LEN - 1) {
+      err_log(url, "Pristine URL string too long.");
+      goto deny;
+    }
+
+  } else {
+    url_len = current_url_len;
+  }
+
   TSDebug(PLUGIN_NAME, "%s", url);
 
-  query = strstr(url, "?");
+  const char *query = strchr(url, '?');
 
   if (cfg->regex) {
     int offset = 0, options = 0;
     int ovector[30];
-    int len      = url_len;
-    char *anchor = strstr(url, "#");
+    int len            = url_len;
+    const char *anchor = strchr(url, '#');
     if (query && !anchor) {
       len -= (query - url);
     } else if (anchor && !query) {
@@ -384,26 +405,26 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
     goto deny;
   }
 
-  if (strncmp(url, "http://", strlen("http://")) != 0) {
-    err_log(url, "Invalid URL scheme - only http supported.");
-    goto deny;
-  }
-
   /* first, parse the query string */
   query++; /* get rid of the ? */
   TSDebug(PLUGIN_NAME, "Query string is:%s", query);
 
   // Client IP - this one is optional
-  p = strstr(query, CIP_QSTRING "=");
-  if (p != NULL) {
-    p += strlen(CIP_QSTRING + 1);
-    pp = strstr(p, "&");
-    if ((pp - p) > CIP_STRLEN - 1 || (pp - p) < 4) {
-      err_log(url, "IP address string too long or short.");
+  const char *cp = strstr(query, CIP_QSTRING "=");
+  if (cp != NULL) {
+    int len_cip_qstring = strlen(CIP_QSTRING);
+    cp += len_cip_qstring - 1;
+    const char *cpp = strchr(cp, '&');
+    if (!cpp) {
+      err_log(url, "All required values after IP address string missing");
+      goto deny;
+    }
+    if (!cpp || (cpp - cp) > CIP_STRLEN - 1 || (cpp - cp) < 4) {
+      err_log(url, "IP address string too long or short");
       goto deny;
     }
-    strncpy(client_ip, p + strlen(CIP_QSTRING) + 1, min((pp - p - (strlen(CIP_QSTRING) + 1)), sizeof(client_ip) - 1));
-    client_ip[pp - p - (strlen(CIP_QSTRING) + 1)] = '\0';
+    memcpy(client_ip, cp + len_cip_qstring + 1, (cpp - cp - (len_cip_qstring + 1)));
+    client_ip[cpp - cp - (len_cip_qstring + 1)] = '\0';
     TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ip);
     retval = TSHttpTxnClientFdGet(txnp, &sockfd);
     if (retval != TS_SUCCESS) {
@@ -423,24 +444,23 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
     }
   }
   // Expiration
-  p = strstr(query, EXP_QSTRING "=");
-  if (p != NULL) {
-    p += strlen(EXP_QSTRING) + 1;
-    expiration = atoi(p);
-    if (expiration == 0 || expiration < time(NULL)) {
-      err_log(url, "Invalid expiration, or expired.");
+  cp = strstr(query, EXP_QSTRING "=");
+  if (cp != NULL) {
+    cp += strlen(EXP_QSTRING) + 1;
+    if (sscanf(cp, "%" SCNu64, &expiration) != 1 || (time_t)expiration < time(NULL)) {
+      err_log(url, "Invalid expiration, or expired");
       goto deny;
     }
-    TSDebug(PLUGIN_NAME, "Exp: %d", (int)expiration);
+    TSDebug(PLUGIN_NAME, "Exp: %" PRIu64, expiration);
   } else {
     err_log(url, "Expiration query string not found.");
     goto deny;
   }
   // Algorithm
-  p = strstr(query, ALG_QSTRING "=");
-  if (p != NULL) {
-    p += strlen(ALG_QSTRING) + 1;
-    algorithm = atoi(p);
+  cp = strstr(query, ALG_QSTRING "=");
+  if (cp != NULL) {
+    cp += strlen(ALG_QSTRING) + 1;
+    algorithm = atoi(cp);
     // The check for a valid algorithm is later.
     TSDebug(PLUGIN_NAME, "Algorithm: %d", algorithm);
   } else {
@@ -448,10 +468,10 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
     goto deny;
   }
   // Key index
-  p = strstr(query, KIN_QSTRING "=");
-  if (p != NULL) {
-    p += strlen(KIN_QSTRING) + 1;
-    keyindex = atoi(p);
+  cp = strstr(query, KIN_QSTRING "=");
+  if (cp != NULL) {
+    cp += strlen(KIN_QSTRING) + 1;
+    keyindex = atoi(cp);
     if (keyindex < 0 || keyindex >= MAX_KEY_NUM || 0 == cfg->keys[keyindex][0]) {
       err_log(url, "Invalid key index.");
       goto deny;
@@ -462,21 +482,27 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
     goto deny;
   }
   // Parts
-  p = strstr(query, PAR_QSTRING "=");
-  if (p != NULL) {
-    p += strlen(PAR_QSTRING) + 1;
-    parts = p; // NOTE parts is not NULL terminated it is terminated by "&" of next param
-    p     = strstr(parts, "&");
-    TSDebug(PLUGIN_NAME, "Parts: %.*s", (int)(p - parts), parts);
+  const char *parts = NULL;
+  cp                = strstr(query, PAR_QSTRING "=");
+  if (cp != NULL) {
+    cp += strlen(PAR_QSTRING) + 1;
+    parts = cp; // NOTE parts is not NULL terminated it is terminated by "&" of next param
+    cp    = strchr(parts, '&');
+    if (cp) {
+      TSDebug(PLUGIN_NAME, "Parts: %.*s", (int)(cp - parts), parts);
+    } else {
+      TSDebug(PLUGIN_NAME, "Parts: %s", parts);
+    }
   } else {
     err_log(url, "PartsSigned query string not found.");
     goto deny;
   }
   // And finally, the sig (has to be last)
-  p = strstr(query, SIG_QSTRING "=");
-  if (p != NULL) {
-    p += strlen(SIG_QSTRING) + 1;
-    signature = p; // NOTE sig is not NULL terminated, it has to be 20 chars
+  const char *signature = NULL;
+  cp                    = strstr(query, SIG_QSTRING "=");
+  if (cp != NULL) {
+    cp += strlen(SIG_QSTRING) + 1;
+    signature = cp;
     if ((algorithm == USIG_HMAC_SHA1 && strlen(signature) < SHA1_SIG_SIZE) ||
         (algorithm == USIG_HMAC_MD5 && strlen(signature) < MD5_SIG_SIZE)) {
       err_log(url, "Signature query string too short (< 20).");
@@ -488,13 +514,20 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
   }
 
   /* have the query string, and parameters passed initial checks */
-  TSDebug(PLUGIN_NAME, "Found all needed parameters: C=%s E=%d A=%d K=%d P=%s S=%s", client_ip, (int)expiration, algorithm,
+  TSDebug(PLUGIN_NAME, "Found all needed parameters: C=%s E=%" PRIu64 " A=%d K=%d P=%s S=%s", client_ip, expiration, algorithm,
           keyindex, parts, signature);
 
   /* find the string that was signed - cycle through the parts letters, adding the part of the fqdn/path if it is 1 */
-  p = strstr(url, "?");
-  memcpy(urltokstr, &url[strlen("http://")], p - url - strlen("http://"));
-  part = strtok_r(urltokstr, "/", &p);
+  cp = strchr(url, '?');
+  // Skip scheme and initial forward slashes.
+  const char *skip = strchr(url, ':');
+  if (!skip || skip[1] != '/' || skip[2] != '/') {
+    goto deny;
+  }
+  skip += 3;
+  memcpy(urltokstr, skip, cp - skip);
+  char *strtok_r_p;
+  const char *part = strtok_r(urltokstr, "/", &strtok_r_p);
   while (part != NULL) {
     if (parts[j] == '1') {
       strncat(signed_part, part, sizeof(signed_part) - strlen(signed_part) - 1);
@@ -504,12 +537,12 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
         parts[j + 1] == '1') { // This remembers the last part, meaning, if there are no more valid letters in parts
       j++;                     // will keep repeating the value of the last one
     }
-    part = strtok_r(NULL, "/", &p);
+    part = strtok_r(NULL, "/", &strtok_r_p);
   }
 
   signed_part[strlen(signed_part) - 1] = '?'; // chop off the last /, replace with '?'
-  p                                    = strstr(query, SIG_QSTRING "=");
-  strncat(signed_part, query, min((p - query) + strlen(SIG_QSTRING) + 1, sizeof(signed_part) - strlen(signed_part) - 1));
+  cp                                   = strstr(query, SIG_QSTRING "=");
+  strncat(signed_part, query, (cp - query) + strlen(SIG_QSTRING) + 1);
 
   TSDebug(PLUGIN_NAME, "Signed string=\"%s\"", signed_part);
 
@@ -557,7 +590,10 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
 
 /* ********* Deny ********* */
 deny:
-  TSfree(url);
+  if (url != current_url) {
+    TSfree((void *)url);
+  }
+  TSfree((void *)current_url);
 
   switch (cfg->err_status) {
   case TS_HTTP_STATUS_MOVED_TEMPORARILY:
@@ -571,7 +607,7 @@ deny:
     rri->redirect = 1;
     break;
   default:
-    TSHttpTxnErrorBodySet(txnp, TSstrdup("Authorization Denied"), strlen("Authorization Denied") - 1, TSstrdup("text/plain"));
+    TSHttpTxnErrorBodySet(txnp, TSstrdup("Authorization Denied"), sizeof("Authorization Denied") - 1, TSstrdup("text/plain"));
     break;
   }
   /* Always set the return status */
@@ -581,15 +617,23 @@ deny:
 
 /* ********* Allow ********* */
 allow:
-  if (query != NULL) {
-    app_qry = getAppQueryString(query, strlen(query));
+  if (url != current_url) {
+    TSfree((void *)url);
+  }
+
+  const char *current_query = strchr(current_url, '?');
+  const char *app_qry       = NULL;
+  if (current_query != NULL) {
+    current_query++;
+    app_qry = getAppQueryString(current_query, strlen(current_query));
   }
 
-  TSfree(url);
+  TSfree((void *)current_url);
+
   /* drop the query string so we can cache-hit */
   if (app_qry != NULL) {
     rval = TSUrlHttpQuerySet(rri->requestBufp, rri->requestUrl, app_qry, strlen(app_qry));
-    TSfree(app_qry);
+    TSfree((void *)app_qry);
   } else {
     rval = TSUrlHttpQuerySet(rri->requestBufp, rri->requestUrl, NULL, 0);
   }
diff --git a/tests/gold_tests/logging/ccid_ctid.test.py b/tests/gold_tests/logging/ccid_ctid.test.py
new file mode 100644
index 0000000..5236313
--- /dev/null
+++ b/tests/gold_tests/logging/ccid_ctid.test.py
@@ -0,0 +1,111 @@
+'''
+'''
+#  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.
+
+import os
+import subprocess
+
+Test.Summary = '''
+Test new ccid and ctid log fields
+'''
+# need Curl
+Test.SkipUnless(
+    Condition.HasProgram(
+        "curl", "Curl need to be installed on system for this test to work"),
+    # Condition.IsPlatform("linux"), Don't see the need for this.
+    Condition.HasATSFeature('TS_USE_TLS_ALPN'),
+    Condition.HasCurlFeature('http2'),
+    Condition.HasProgram("netstat", "netstat need to be installed on system for this test to work")
+)
+
+# Define default ATS.  "select_ports=False" needed because SSL port used.
+#
+ts = Test.MakeATSProcess("ts", select_ports=False)
+
+ts.addSSLfile("../remap/ssl/server.pem")
+ts.addSSLfile("../remap/ssl/server.key")
+
+ts.Variables.ssl_port = 4443
+ts.Disk.records_config.update({
+    # 'proxy.config.diags.debug.enabled': 1,
+    'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
+    'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
+    'proxy.config.http.server_ports': 'ipv4:{0} ipv4:{1}:proto=http2;http:ssl'.format(ts.Variables.port, ts.Variables.ssl_port)
+})
+
+ts.Disk.remap_config.AddLine(
+    'map http://127.0.0.1:{0} http://httpbin.org/ip'.format(ts.Variables.port)
+)
+
+ts.Disk.remap_config.AddLine(
+    'map https://127.0.0.1:{0} https://httpbin.org/ip'.format(ts.Variables.ssl_port)
+)
+
+ts.Disk.ssl_multicert_config.AddLine(
+    'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
+)
+
+ts.Disk.logging_config.AddLines(
+    '''custom = format {
+  Format = "%<ccid> %<ctid>"
+}
+
+log.ascii {
+  Format = custom,
+  Filename = 'test_ccid_ctid'
+}'''.split("\n")
+)
+
+# Ask the OS if the port is ready for connect()
+#
+
+
+def CheckPort(Port):
+    return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q :{}'.format(Port), shell=True)
+
+
+tr = Test.AddTestRun()
+# Delay on readiness of ssl port
+tr.Processes.Default.StartBefore(Test.Processes.ts, ready=CheckPort(ts.Variables.ssl_port))
+#
+tr.Processes.Default.Command = 'curl "http://127.0.0.1:{0}" --verbose'.format(
+    ts.Variables.port)
+tr.Processes.Default.ReturnCode = 0
+
+tr = Test.AddTestRun()
+tr.Processes.Default.Command = 'curl "http://127.0.0.1:{0}" --verbose'.format(
+    ts.Variables.port)
+tr.Processes.Default.ReturnCode = 0
+
+tr = Test.AddTestRun()
+tr.Processes.Default.Command = 'curl "http://127.0.0.1:{0}" "http://127.0.0.1:{0}" --http1.1 --verbose'.format(
+    ts.Variables.port)
+tr.Processes.Default.ReturnCode = 0
+
+tr = Test.AddTestRun()
+tr.Processes.Default.Command = 'curl "https://127.0.0.1:{0}" "https://127.0.0.1:{0}" --http2 --insecure --verbose'.format(
+    ts.Variables.ssl_port)
+tr.Processes.Default.ReturnCode = 0
+
+# Delay to allow TS to flush report to disk, then validate generated log.
+#
+tr = Test.AddTestRun()
+tr.DelayStart = 10
+tr.Processes.Default.Command = 'python {0} < {1}'.format(
+    os.path.join(Test.TestDirectory, 'ccid_ctid_observer.py'),
+    os.path.join(ts.Variables.LOGDIR, 'test_ccid_ctid.log'))
+tr.Processes.Default.ReturnCode = 0
diff --git a/tests/gold_tests/pluginTest/url_sig/run_sign.sh b/tests/gold_tests/pluginTest/url_sig/run_sign.sh
new file mode 100755
index 0000000..fcc404c
--- /dev/null
+++ b/tests/gold_tests/pluginTest/url_sig/run_sign.sh
@@ -0,0 +1,138 @@
+# Script to run sign.pl script.  Single parameter is number 1 or greater selecting a set of script parameters.
+
+#  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.
+
+# Generate one or more sets of arguments for the sign.pl perl script.
+#
+cmd_args ()
+{
+if [[ "$1" = "" ]] ; then
+    SELECT=1
+else
+    SELECT="$1"
+fi
+
+FOREVER="$((60 * 60 * 24 * 365 * 1000))"
+
+case "$SELECT" in
+1)
+    echo "--url http://one.two.three/foo/abcde/qrstuvwxyz"
+    echo "--useparts 1"
+    echo "--algorithm 1"
+    echo "--duration $FOREVER"
+    echo "--keyindex 7"
+    echo "--key dqsgopTSM_doT6iAysasQVUKaPykyb6e"
+    ;;
+2)
+    echo "--client 127.0.0.1"
+    echo "--url http://four.five.six/foo/abcde/qrstuvwxyz"
+    echo "--useparts 1"
+    echo "--algorithm 1"
+    echo "--duration $FOREVER"
+    echo "--keyindex 15"
+    echo "--key 9MuXIiZ70HPi_qhqfSgdu9oJHpcj9yaO"
+    ;;
+3)
+    echo "--url http://seven.eight.nine/foo/abcde/qrstuvwxyz"
+    echo "--useparts 1"
+    echo "--algorithm 2"
+    echo "--duration $FOREVER"
+    echo "--keyindex 0"
+    echo "--key hV3wqyq1QxJeF76JkzHf93tuLYv_abw5"
+    ;;
+4)
+    echo "--client 127.0.0.1"
+    echo "--url http://seven.eight.nine/foo/abcde/qrstuvwxyz"
+    echo "--useparts 010"
+    echo "--algorithm 2"
+    echo "--duration $FOREVER"
+    echo "--keyindex 13"
+    echo "--key CGRDwMO96_vRjFCfks6oxkeV7IdTnA6f"
+    ;;
+5)
+    echo "--client 127.0.0.1"
+    echo "--url http://seven.eight.nine/foo/abcde/qrstuvwxyz"
+    echo "--useparts 101"
+    echo "--algorithm 2"
+    echo "--duration $FOREVER"
+    echo "--keyindex 13"
+    echo "--key CGRDwMO96_vRjFCfks6oxkeV7IdTnA6f"
+    ;;
+*h*)
+    ;;
+*)
+    echo "run_sign.sh: bad seletion parameter" 1>&2
+    exit 1
+    ;;
+esac
+}
+
+# Find the path to the sign.pl script in the url_sig (source) directory.
+#
+find_cmd ()
+{
+local D T='..'
+while [[ ! -d $T/.git ]]
+do
+  if [[ ! -d $T/.. ]] ; then
+    echo "Working directory not in a git repo" 1>&2
+    exit 1
+  fi
+  T="$T/.."
+done
+
+for D in $( find $T -name url_sig -type d )
+do
+    if [[ -x $D/sign.pl ]] ; then
+        echo "$D/sign.pl"
+        return 0
+    fi
+done
+
+echo "cannot find sign.pl script" 1>&2
+exit 1
+}
+
+FOUND=N
+echo "$PERL5LIB" | tr ':' ' ' | while read D
+do
+    if [[ -f $D/Digest/HMAC_MD5.pm ]] ; then
+        FOUND=Y
+        break
+    fi
+done
+
+if [[ $FOUND = N ]] ; then
+    P=$( find / 2>/dev/null | grep -F Digest/HMAC_MD5.pm | head -1 )
+    if [[ ! -f $P ]] ; then
+        echo "Cannot find HMAC_MD5.pm" 1>&2
+        exit 1
+    fi
+    export PERL5LIB="$PERL5LIB:$( dirname $( dirname $P ) )"
+fi
+
+CMD=$( find_cmd )
+if [[ "$?" != 0 ]] ; then
+    exit 1
+fi
+
+ARGS=$( cmd_args "$1" )
+if [[ "$?" != 0 ]] ; then
+    exit 1
+fi
+
+$CMD $ARGS | tr ' ' '\n' | tail -1
diff --git a/tests/gold_tests/pluginTest/url_sig/url_sig.config b/tests/gold_tests/pluginTest/url_sig/url_sig.config
new file mode 100644
index 0000000..7c10a6b
--- /dev/null
+++ b/tests/gold_tests/pluginTest/url_sig/url_sig.config
@@ -0,0 +1,17 @@
+key0 = hV3wqyq1QxJeF76JkzHf93tuLYv_abw5
+key1 = nIpyXbVqPFVN7y8yMlfgFBLnOqDSufMy
+key2 = 4UED1ELmHkEcXrS_7yEYPKtgUZdGWaP2
+key3 = mv2vPGJpq2iFDbiV3dJG4ZqCAzRTIpTD
+key4 = 2cnob1tuGEiYhwJLYRLa5bfyuZH1zI0S
+key5 = poC7zK9IrDl3rljvuZ0bbMP3e5f0woKt
+key6 = _k8diypYMebSCEEjYNszZbG906JZI6Bx
+key7 = dqsgopTSM_doT6iAysasQVUKaPykyb6e
+key8 = AzM3mhTDEkyJjyqQctv0NVxCL3FmXDzW
+key9 = iRHQE9ucS44oAhdXmM148wMTJAO4XAVV
+key10 = b1OMb39dGhMSg_wArQnvqGIBgQGFjnNl
+key11 = YpA8qBkvohdamogQ4zTuoPw50PbezdL0
+key12 = 4Q4OCnY_gmcDuw5756Wk1XG7PEi24g1_
+key13 = CGRDwMO96_vRjFCfks6oxkeV7IdTnA6f
+key14 = sXTWfNyHkN2SJ9eKifetPzfcg0_rNhXM
+key15 = 9MuXIiZ70HPi_qhqfSgdu9oJHpcj9yaO
+error_url = 403
diff --git a/tests/gold_tests/pluginTest/url_sig/url_sig.gold b/tests/gold_tests/pluginTest/url_sig/url_sig.gold
new file mode 100644
index 0000000..35f62da
--- /dev/null
+++ b/tests/gold_tests/pluginTest/url_sig/url_sig.gold
@@ -0,0 +1,24 @@
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 403 Forbidden
+Authorization Denied*   Trying 127.0.0.1...
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
+< HTTP/1.1 200 OK
diff --git a/tests/gold_tests/pluginTest/url_sig/url_sig.test.py b/tests/gold_tests/pluginTest/url_sig/url_sig.test.py
new file mode 100644
index 0000000..78b0228
--- /dev/null
+++ b/tests/gold_tests/pluginTest/url_sig/url_sig.test.py
@@ -0,0 +1,261 @@
+'''
+'''
+#  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.
+
+import os
+import subprocess
+Test.Summary = '''
+Test url_sig plugin
+'''
+
+Test.SkipUnless(
+    Condition.HasATSFeature('TS_USE_TLS_ALPN'),
+)
+
+# Skip if plugins not present.
+Test.SkipUnless(Condition.PluginExists('url_sig.so'))
+Test.SkipUnless(Condition.PluginExists('balancer.so'))
+
+# Set up to check the output after the tests have run.
+#
+url_sig_log_id = Test.Disk.File("url_sig_short.log")
+url_sig_log_id.Content = "url_sig.gold"
+
+server = Test.MakeOriginServer("server")
+
+request_header = {
+    "headers": "GET /foo/abcde/qrstuvwxyz HTTP/1.1\r\nHost: just.any.thing\r\n\r\n", "timestamp": "1469733493.993", "body": ""
+}
+# expected response from the origin server
+response_header = {"headers": "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n", "timestamp": "1469733493.993", "body": ""}
+# add response to the server dictionary
+server.addResponse("sessionfile.log", request_header, response_header)
+
+# Define default ATS
+ts = Test.MakeATSProcess("ts", select_ports=False)
+
+ts.addSSLfile("../../remap/ssl/server.pem")
+ts.addSSLfile("../../remap/ssl/server.key")
+
+ts.Variables.ssl_port = 4443
+
+ts.Disk.records_config.update({
+    # 'proxy.config.diags.debug.enabled': 1,
+    # 'proxy.config.diags.debug.tags': 'http|url_sig',
+    'proxy.config.http.cache.http': 0, # Make sure each request is forwarded to the origin server.
+    'proxy.config.proxy_name': 'Poxy_Proxy', # This will be the server name.
+    'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
+    'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
+    'proxy.config.http.server_ports': (
+        'ipv4:{0} ipv4:{1}:proto=http:ssl'.format(ts.Variables.port, ts.Variables.ssl_port))
+})
+
+ts.Disk.ssl_multicert_config.AddLine(
+    'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
+)
+
+# Use unchanged incoming URL.
+#
+ts.Disk.remap_config.AddLine(
+    'map http://one.two.three/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+    ' @plugin=url_sig.so @pparam={}/url_sig.config'.format(Test.TestDirectory)
+)
+
+# Use unchanged incoming HTTPS URL.
+#
+ts.Disk.remap_config.AddLine(
+    'map https://one.two.three/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+    ' @plugin=url_sig.so @pparam={}/url_sig.config'.format(Test.TestDirectory)
+)
+
+# Use pristine URL, incoming URL unchanged.
+#
+ts.Disk.remap_config.AddLine(
+    'map http://four.five.six/ http://127.0.0.1:{}/'.format(server.Variables.Port) +
+    ' @plugin=url_sig.so @pparam={}/url_sig.config @pparam=pristineurl'.format(Test.TestDirectory)
+)
+
+# Use pristine URL, incoming URL changed.
+#
+ts.Disk.remap_config.AddLine(
+    'map http://seven.eight.nine/ http://dummy' +
+    ' @plugin=balancer.so @pparam=--policy=hash,url @pparam=127.0.0.1:{}'.format(server.Variables.Port) +
+    ' @plugin=url_sig.so @pparam={}/url_sig.config @pparam=PristineUrl'.format(Test.TestDirectory)
+)
+
+# Ask the OS if the port is ready for connect()
+#
+def CheckPort(Port):
+    return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q :{}'.format(Port), shell=True)
+
+# Validation failure tests.
+
+LogTee = " 2>&1 | tee -a {}/url_sig_long.log".format(Test.RunDirectory)
+
+# Bad client / MD5 / P=101 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.StartBefore(ts, ready=CheckPort(ts.Variables.ssl_port))
+tr.Processes.Default.StartBefore(server, ready=CheckPort(server.Variables.Port))
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.2&E=33046620008&A=2&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8'" +
+    LogTee
+)
+
+# With client / MD5 / P=010 / URL pristine / URL altered -- Expired.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=1&A=2&K=13&P=010&S=f237aad1fa010234d7bf8108a0e36387'" +
+    LogTee
+)
+
+# With client / No algorithm / P=101 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8'" +
+    LogTee
+)
+
+# With client / Bad algorithm / P=101 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=3&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8'" +
+    LogTee
+)
+
+# With client / MD5 / No parts / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&S=d1f352d4f1d931ad2f441013402d93f8'" +
+    LogTee
+)
+
+# With client / MD5 / P=10 (bad) / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&P=10&S=d1f352d4f1d931ad2f441013402d93f8'" +
+    LogTee
+)
+
+# With client / MD5 / P=101 / URL pristine / URL altered -- No signature.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&P=101'" +
+    LogTee
+)
+
+# With client / MD5 / P=101 / URL pristine / URL altered  -- Bad signature.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&P=101&S=d1f452d4f1d931ad2f441013402d93f8'" +
+    LogTee
+)
+
+# With client / MD5 / P=101 / URL pristine / URL altered -- Spurious &.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8#'" +
+    LogTee
+)
+
+# Success tests.
+
+# No client / SHA1 / P=1 / URL not pristine / URL not altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://one.two.three/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?E=33046618506&A=1&K=7&P=1&S=acae22b0e1ba6ea6fbb5d26018dbf152558e98cb'" +
+    LogTee
+)
+
+# With client / SHA1 / P=1 / URL pristine / URL not altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://four.five.six/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046618556&A=1&K=15&P=1&S=f4103561a23adab7723a89b9831d77e0afb61d92'" +
+    LogTee
+)
+
+# No client / MD5 / P=1 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?E=33046618586&A=2&K=0&P=1&S=0364efa28afe345544596705b92d20ac'" +
+    LogTee
+)
+
+# With client / MD5 / P=010 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046619717&A=2&K=13&P=010&S=f237aad1fa010234d7bf8108a0e36387'" +
+    LogTee
+)
+
+# With client / MD5 / P=101 / URL pristine / URL altered.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --proxy http://127.0.0.1:{} 'http://seven.eight.nine/".format(ts.Variables.port) +
+    "foo/abcde/qrstuvwxyz?C=127.0.0.1&E=33046620008&A=2&K=13&P=101&S=d1f352d4f1d931ad2f441013402d93f8'" +
+    LogTee
+)
+
+# No client / SHA1 / P=1 / URL not pristine / URL not altered -- HTTPS.
+#
+tr = Test.AddTestRun()
+tr.Processes.Default.ReturnCode = 0
+tr.Processes.Default.Command = (
+    "curl --verbose --http1.1 --insecure --header 'Host: one.two.three' 'https://127.0.0.1:{}/".format(ts.Variables.ssl_port) +
+    "foo/abcde/qrstuvwxyz?E=33046618506&A=1&K=7&P=1&S=acae22b0e1ba6ea6fbb5d26018dbf152558e98cb'" +
+    LogTee + " ; grep -F -e '< HTTP' -e Authorization {0}/url_sig_long.log > {0}/url_sig_short.log ".format(ts.RunDirectory)
+)

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.

[trafficserver] 06/08: Log fields for Connection ID and HTTP/2 Stream ID.

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

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

commit cd39a6b01a20cc298cc03c0a430f3061b8003e07
Author: Walt Karas <wk...@yahoo-inc.com>
AuthorDate: Wed Sep 6 15:50:41 2017 +0000

    Log fields for Connection ID and HTTP/2 Stream ID.
    
    (cherry picked from commit ff2c84732d96963c01d35d78892edc623a1b92d1)
    
     Conflicts:
    	proxy/logging/LogAccessHttp.h
    	tests/gold_tests/logging/ccid_ctid.test.py
---
 doc/admin-guide/logging/formatting.en.rst      | 27 ++++++++-----
 proxy/ProxyClientTransaction.h                 |  5 +++
 proxy/http/Http1ClientTransaction.h            | 10 +++++
 proxy/http2/Http2Stream.h                      |  6 +++
 proxy/logging/Log.cc                           | 10 +++++
 proxy/logging/LogAccess.cc                     | 10 +++++
 proxy/logging/LogAccess.h                      | 14 ++++---
 proxy/logging/LogAccessHttp.cc                 | 41 ++++++++++++++++++++
 proxy/logging/LogAccessHttp.h                  | 14 ++++---
 tests/gold_tests/logging/ccid_ctid.test.py     |  9 ++++-
 tests/gold_tests/logging/ccid_ctid_observer.py | 53 ++++++++++++++++++++++++++
 11 files changed, 176 insertions(+), 23 deletions(-)

diff --git a/doc/admin-guide/logging/formatting.en.rst b/doc/admin-guide/logging/formatting.en.rst
index 4e4cc0b..bbb3150 100644
--- a/doc/admin-guide/logging/formatting.en.rst
+++ b/doc/admin-guide/logging/formatting.en.rst
@@ -179,19 +179,28 @@ Connections and Transactions
 
 .. _sca:
 .. _sstc:
+.. _ccid:
+.. _ctid:
 
 The following log fields are used to list various details of connections and
 transactions between |TS| proxies and origin servers.
 
-===== ====== ==================================================================
-Field Source Description
-===== ====== ==================================================================
-sca   Proxy  Number of attempts within the current transaction by |TS|
-             in connecting to the origin server.
-sstc  Proxy  Number of transactions between the |TS| proxy and the origin
-             server from a single session. Any value greater than zero
-             indicates connection reuse.
-===== ====== ==================================================================
+===== ============== ==================================================================
+Field Source         Description
+===== ============== ==================================================================
+sca   Proxy          Number of attempts within the current transaction by |TS|
+                     in connecting to the origin server.
+sstc  Proxy          Number of transactions between the |TS| proxy and the origin
+                     server from a single session. Any value greater than zero
+                     indicates connection reuse.
+ccid  Client Request Client Connection ID, a non-negative number for a connection,
+                     which is different for all currently-active connections to
+                     clients.
+ctid  Client Request Client Transaction ID, a non-negative number for a transaction,
+                     which is different for all currently-active transactions on the
+                     same client connection.  For client HTTP/2 transactions, this
+                     value is the stream ID for the transaction.
+===== ============== ==================================================================
 
 .. _admin-logging-fields-content-type:
 
diff --git a/proxy/ProxyClientTransaction.h b/proxy/ProxyClientTransaction.h
index f0004f6..522e9da 100644
--- a/proxy/ProxyClientTransaction.h
+++ b/proxy/ProxyClientTransaction.h
@@ -251,6 +251,11 @@ public:
     return parent ? parent->protocol_contains(tag_prefix) : nullptr;
   }
 
+  // This function must return a non-negative number that is different for two in-progress transactions with the same parent
+  // session.
+  //
+  virtual int get_transaction_id() const = 0;
+
 protected:
 protected:
   ProxyClientSession *parent;
diff --git a/proxy/http/Http1ClientTransaction.h b/proxy/http/Http1ClientTransaction.h
index 7547f6b..fb23bc7 100644
--- a/proxy/http/Http1ClientTransaction.h
+++ b/proxy/http/Http1ClientTransaction.h
@@ -169,6 +169,16 @@ public:
   }
   void transaction_done() override;
 
+  int
+  get_transaction_id() const override
+  {
+    // For HTTP/1 there is only one on-going transaction at a time per session/connection.  Therefore, the transaction count can be
+    // presumed not to increase during the lifetime of a transaction, thus this function will return a consistent unique transaction
+    // identifier.
+    //
+    return get_transact_count();
+  }
+
 protected:
   uint16_t outbound_port;
   IpAddr outbound_ip4;
diff --git a/proxy/http2/Http2Stream.h b/proxy/http2/Http2Stream.h
index 3bc1dab..48043ee 100644
--- a/proxy/http2/Http2Stream.h
+++ b/proxy/http2/Http2Stream.h
@@ -122,6 +122,12 @@ public:
     return _id;
   }
 
+  int
+  get_transaction_id() const override
+  {
+    return _id;
+  }
+
   Http2StreamState
   get_state() const
   {
diff --git a/proxy/logging/Log.cc b/proxy/logging/Log.cc
index 4cddd99..9e06443 100644
--- a/proxy/logging/Log.cc
+++ b/proxy/logging/Log.cc
@@ -838,6 +838,16 @@ Log::init_fields()
   global_field_list.add(field, false);
   ink_hash_table_insert(field_symbol_hash, "fsiz", field);
 
+  field = new LogField("client_connection_id", "ccid", LogField::sINT, &LogAccess::marshal_client_http_connection_id,
+                       &LogAccess::unmarshal_int_to_str);
+  global_field_list.add(field, false);
+  ink_hash_table_insert(field_symbol_hash, "ccid", field);
+
+  field = new LogField("client_transaction_id", "ctid", LogField::sINT, &LogAccess::marshal_client_http_transaction_id,
+                       &LogAccess::unmarshal_int_to_str);
+  global_field_list.add(field, false);
+  ink_hash_table_insert(field_symbol_hash, "ctid", field);
+
   Ptr<LogFieldAliasTable> entry_type_map = make_ptr(new LogFieldAliasTable);
   entry_type_map->init(N_LOG_ENTRY_TYPES, LOG_ENTRY_HTTP, "LOG_ENTRY_HTTP", LOG_ENTRY_ICP, "LOG_ENTRY_ICP");
   field = new LogField("log_entry_type", "etype", LogField::sINT, &LogAccess::marshal_entry_type, &LogAccess::unmarshal_entry_type,
diff --git a/proxy/logging/LogAccess.cc b/proxy/logging/LogAccess.cc
index 2af4915..144d82a 100644
--- a/proxy/logging/LogAccess.cc
+++ b/proxy/logging/LogAccess.cc
@@ -489,6 +489,16 @@ LogAccess::marshal_process_uuid(char *buf)
 /*-------------------------------------------------------------------------
   -------------------------------------------------------------------------*/
 
+LOG_ACCESS_DEFAULT_FIELD(marshal_client_http_connection_id, DEFAULT_INT_FIELD)
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+LOG_ACCESS_DEFAULT_FIELD(marshal_client_http_transaction_id, DEFAULT_INT_FIELD)
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
 int
 LogAccess::marshal_config_int_var(char *config_var, char *buf)
 {
diff --git a/proxy/logging/LogAccess.h b/proxy/logging/LogAccess.h
index a17454b..ad41247 100644
--- a/proxy/logging/LogAccess.h
+++ b/proxy/logging/LogAccess.h
@@ -268,12 +268,14 @@ public:
 
   // other fields
   //
-  inkcoreapi virtual int marshal_transfer_time_ms(char *);    // INT
-  inkcoreapi virtual int marshal_transfer_time_s(char *);     // INT
-  inkcoreapi virtual int marshal_file_size(char *);           // INT
-  inkcoreapi virtual int marshal_plugin_identity_id(char *);  // INT
-  inkcoreapi virtual int marshal_plugin_identity_tag(char *); // STR
-  inkcoreapi virtual int marshal_process_uuid(char *);        // STR
+  inkcoreapi virtual int marshal_transfer_time_ms(char *);           // INT
+  inkcoreapi virtual int marshal_transfer_time_s(char *);            // INT
+  inkcoreapi virtual int marshal_file_size(char *);                  // INT
+  inkcoreapi virtual int marshal_plugin_identity_id(char *);         // INT
+  inkcoreapi virtual int marshal_plugin_identity_tag(char *);        // STR
+  inkcoreapi virtual int marshal_process_uuid(char *);               // STR
+  inkcoreapi virtual int marshal_client_http_connection_id(char *);  // INT
+  inkcoreapi virtual int marshal_client_http_transaction_id(char *); // INT
 
   // These two are special, in that they are shared for all log types / implementations
   inkcoreapi int marshal_entry_type(char *);                     // INT
diff --git a/proxy/logging/LogAccessHttp.cc b/proxy/logging/LogAccessHttp.cc
index d9a58a1..bb7381a 100644
--- a/proxy/logging/LogAccessHttp.cc
+++ b/proxy/logging/LogAccessHttp.cc
@@ -1480,6 +1480,47 @@ LogAccessHttp::marshal_file_size(char *buf)
   -------------------------------------------------------------------------*/
 
 int
+LogAccessHttp::marshal_client_http_connection_id(char *buf)
+{
+  if (buf) {
+    int64_t id = 0;
+    if (m_http_sm) {
+      auto p = m_http_sm->ua_session;
+      if (p) {
+        auto p2 = p->get_parent();
+        if (p2) {
+          id = p2->connection_id();
+        }
+      }
+    }
+    marshal_int(buf, id);
+  }
+  return INK_MIN_ALIGN;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+int
+LogAccessHttp::marshal_client_http_transaction_id(char *buf)
+{
+  if (buf) {
+    int64_t id = 0;
+    if (m_http_sm) {
+      auto p = m_http_sm->ua_session;
+      if (p) {
+        id = p->get_transaction_id();
+      }
+    }
+    marshal_int(buf, id);
+  }
+  return INK_MIN_ALIGN;
+}
+
+/*-------------------------------------------------------------------------
+  -------------------------------------------------------------------------*/
+
+int
 LogAccessHttp::marshal_http_header_field(LogField::Container container, char *field, char *buf)
 {
   char *str        = nullptr;
diff --git a/proxy/logging/LogAccessHttp.h b/proxy/logging/LogAccessHttp.h
index 830e5d2..6d4632f 100644
--- a/proxy/logging/LogAccessHttp.h
+++ b/proxy/logging/LogAccessHttp.h
@@ -147,12 +147,14 @@ public:
   //
   // other fields
   //
-  virtual int marshal_transfer_time_ms(char *);       // INT
-  virtual int marshal_transfer_time_s(char *);        // INT
-  virtual int marshal_file_size(char *);              // INT
-  virtual int marshal_plugin_identity_id(char *);     // INT
-  virtual int marshal_plugin_identity_tag(char *);    // STR
-  virtual int marshal_cache_lookup_url_canon(char *); // STR
+  int marshal_transfer_time_ms(char *) override;           // INT
+  int marshal_transfer_time_s(char *) override;            // INT
+  int marshal_file_size(char *) override;                  // INT
+  int marshal_plugin_identity_id(char *) override;         // INT
+  int marshal_plugin_identity_tag(char *) override;        // STR
+  int marshal_cache_lookup_url_canon(char *) override;     // STR
+  int marshal_client_http_connection_id(char *) override;  // INT
+  int marshal_client_http_transaction_id(char *) override; // INT
 
   //
   // named fields from within a http header
diff --git a/tests/gold_tests/logging/ccid_ctid.test.py b/tests/gold_tests/logging/ccid_ctid.test.py
index b990891..ef60083 100644
--- a/tests/gold_tests/logging/ccid_ctid.test.py
+++ b/tests/gold_tests/logging/ccid_ctid.test.py
@@ -40,7 +40,7 @@ ts.addSSLfile("../remap/ssl/server.key")
 
 ts.Variables.ssl_port = 4443
 ts.Disk.records_config.update({
-    # 'proxy.config.diags.debug.enabled': 1,
+    # 'proxy.config.diags.debug.enabled': '1',
     'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
     'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
     'proxy.config.http.server_ports': 'ipv4:{0} ipv4:{1}:proto=http2;http:ssl'.format(ts.Variables.port, ts.Variables.ssl_port)
@@ -69,9 +69,14 @@ log.ascii {
 }'''.split("\n")
 )
 
+# Ask the OS if the port is ready for connect()
+#
+def CheckPort(Port):
+    return lambda: 0 == subprocess.call('netstat --listen --tcp -n | grep -q :{}'.format(Port), shell=True)
+
 tr = Test.AddTestRun()
 # Delay on readiness of ssl port
-tr.Processes.Default.StartBefore(Test.Processes.ts, ready=When.PortOpen(ts.Variables.ssl_port))
+tr.Processes.Default.StartBefore(Test.Processes.ts, ready=CheckPort(ts.Variables.ssl_port))
 #
 tr.Processes.Default.Command = 'curl "http://127.0.0.1:{0}" --verbose'.format(
     ts.Variables.port)
diff --git a/tests/gold_tests/logging/ccid_ctid_observer.py b/tests/gold_tests/logging/ccid_ctid_observer.py
new file mode 100644
index 0000000..1b4cee5
--- /dev/null
+++ b/tests/gold_tests/logging/ccid_ctid_observer.py
@@ -0,0 +1,53 @@
+'''
+Examines log generated by ccid_ctid.test.py, returns 0 if valid, 1 if not.
+'''
+#  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.
+
+import sys
+import csv
+
+ccid = []
+ctid = []
+
+# Read in ccid and ctid fields from each line of the generated report.
+#
+for ln in csv.reader(sys.stdin, delimiter=' '):
+    if len(ln) != 2:
+        exit(code=1)
+    i = int(ln[0])
+    if i < 0:
+        exit(code=1)
+    ccid.append(i)
+    i = int(ln[1])
+    if i < 0:
+        exit(code=1)
+    ctid.append(i)
+
+# Validate contents of report.
+#
+if (ccid[0] != ccid[1] and
+    ccid[1] != ccid[2] and
+    ccid[2] == ccid[3] and
+    ctid[2] != ctid[3] and
+    ccid[3] != ccid[4] and
+    ccid[4] == ccid[5] and
+    ctid[4] != ctid[5]):
+    exit(code=0)
+
+# Failure exit if report was not valid.
+#
+exit(code=1)

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.

[trafficserver] 02/08: Fix logic for loading config file for url_sig plugin.

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

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

commit 0a1408751e83e953c980471a0bdaf4af0c56fc71
Author: Walt Karas <wk...@yahoo-inc.com>
AuthorDate: Fri Nov 3 17:12:11 2017 +0000

    Fix logic for loading config file for url_sig plugin.
    
    (cherry picked from commit ecb2655ccdc6088c5bac8ef3d7b8e31c05595c5a)
---
 plugins/experimental/url_sig/url_sig.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/plugins/experimental/url_sig/url_sig.c b/plugins/experimental/url_sig/url_sig.c
index 3dc0de1..9923693 100644
--- a/plugins/experimental/url_sig/url_sig.c
+++ b/plugins/experimental/url_sig/url_sig.c
@@ -101,7 +101,7 @@ TSRemapInit(TSRemapInterface *api_info, char *errbuf, int errbuf_size)
 TSReturnCode
 TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_size)
 {
-  char config_file[PATH_MAX];
+  char config_filepath_buf[PATH_MAX], *config_file;
   struct config *cfg;
 
   if (argc != 3) {
@@ -111,8 +111,12 @@ TSRemapNewInstance(int argc, char *argv[], void **ih, char *errbuf, int errbuf_s
   }
   TSDebug(PLUGIN_NAME, "Initializing remap function of %s -> %s with config from %s", argv[0], argv[1], argv[2]);
 
-  const char *install_dir = TSInstallDirGet();
-  snprintf(config_file, sizeof(config_file), "%s/%s/%s", install_dir, "etc/trafficserver", argv[2]);
+  if (argv[2][0] == '/') {
+    config_file = argv[2];
+  } else {
+    snprintf(config_filepath_buf, sizeof(config_filepath_buf), "%s/%s", TSConfigDirGet(), argv[2]);
+    config_file = config_filepath_buf;
+  }
   TSDebug(PLUGIN_NAME, "config file name: %s", config_file);
   FILE *file = fopen(config_file, "r");
   if (file == NULL) {

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.

[trafficserver] 08/08: Change proxy/logging/LogAccessHttp.h from using 'virtual' to 'override'.

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

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

commit 44c8d525648acd3818649b5e02b35b854f27e14a
Author: Jeffrey Bevill <je...@comcast.com>
AuthorDate: Sat Mar 10 20:52:21 2018 +0000

    Change proxy/logging/LogAccessHttp.h from using 'virtual' to 'override'.
    
    (cherry picked from commit 6cdc1147a1bbf4290c735176cbc779a78d7dbcb3)
    
     Conflicts:
    	proxy/http2/Http2Stream.h
    	proxy/logging/LogAccessHttp.h
    
    (cherry picked from commit e2dfa5ac870348ebeb024b99da2dfd6549e99e06)
---
 proxy/http2/Http2Stream.h     |  26 +++----
 proxy/logging/LogAccessHttp.h | 159 +++++++++++++++++++++---------------------
 2 files changed, 93 insertions(+), 92 deletions(-)

diff --git a/proxy/http2/Http2Stream.h b/proxy/http2/Http2Stream.h
index 48043ee..f8afc11 100644
--- a/proxy/http2/Http2Stream.h
+++ b/proxy/http2/Http2Stream.h
@@ -90,7 +90,7 @@ public:
   ~Http2Stream() { this->destroy(); }
   int main_event_handler(int event, void *edata);
 
-  void destroy();
+  void destroy() override;
 
   bool
   is_body_done() const
@@ -176,17 +176,17 @@ public:
 
   Http2ErrorCode decode_header_blocks(HpackHandle &hpack_handle, uint32_t maximum_table_size);
   void send_request(Http2ConnectionState &cstate);
-  VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf);
-  VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *abuffer, bool owner = false);
-  void do_io_close(int lerrno = -1);
+  VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override;
+  VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *abuffer, bool owner = false) override;
+  void do_io_close(int lerrno = -1) override;
   void initiating_close();
   void terminate_if_possible();
-  void do_io_shutdown(ShutdownHowTo_t) {}
+  void do_io_shutdown(ShutdownHowTo_t) override {}
   void update_read_request(int64_t read_len, bool send_update);
   void update_write_request(IOBufferReader *buf_reader, int64_t write_len, bool send_update);
   void signal_write_event(bool call_update);
-  void reenable(VIO *vio);
-  virtual void transaction_done();
+  void reenable(VIO *vio) override;
+  virtual void transaction_done() override;
 
   void restart_sending();
   void push_promise(URL &url, const MIMEField *accept_encoding);
@@ -226,17 +226,17 @@ public:
     return chunked;
   }
 
-  void release(IOBufferReader *r);
+  void release(IOBufferReader *r) override;
 
   virtual bool
-  allow_half_open() const
+  allow_half_open() const override
   {
     return false;
   }
 
-  virtual void set_active_timeout(ink_hrtime timeout_in);
-  virtual void set_inactivity_timeout(ink_hrtime timeout_in);
-  virtual void cancel_inactivity_timeout();
+  virtual void set_active_timeout(ink_hrtime timeout_in) override;
+  virtual void set_inactivity_timeout(ink_hrtime timeout_in) override;
+  virtual void cancel_inactivity_timeout() override;
   void clear_inactive_timer();
   void clear_active_timer();
   void clear_timers();
@@ -256,7 +256,7 @@ public:
   }
 
   bool
-  is_first_transaction() const
+  is_first_transaction() const override
   {
     return is_first_transaction_flag;
   }
diff --git a/proxy/logging/LogAccessHttp.h b/proxy/logging/LogAccessHttp.h
index 6d4632f..a411bfc 100644
--- a/proxy/logging/LogAccessHttp.h
+++ b/proxy/logging/LogAccessHttp.h
@@ -42,12 +42,12 @@ class LogAccessHttp : public LogAccess
 {
 public:
   LogAccessHttp(HttpSM *sm);
-  virtual ~LogAccessHttp();
+  ~LogAccessHttp() override;
 
-  void init();
+  void init() override;
 
   LogEntryType
-  entry_type() const
+  entry_type() const override
   {
     return LOG_ENTRY_HTTP;
   }
@@ -55,94 +55,94 @@ public:
   //
   // client -> proxy fields
   //
-  virtual int marshal_client_host_ip(char *);                // STR
-  virtual int marshal_host_interface_ip(char *);             // STR
-  virtual int marshal_client_host_port(char *);              // INT
-  virtual int marshal_client_auth_user_name(char *);         // STR
-  virtual int marshal_client_req_text(char *);               // STR
-  virtual int marshal_client_req_http_method(char *);        // INT
-  virtual int marshal_client_req_url(char *);                // STR
-  virtual int marshal_client_req_url_canon(char *);          // STR
-  virtual int marshal_client_req_unmapped_url_canon(char *); // STR
-  virtual int marshal_client_req_unmapped_url_path(char *);  // STR
-  virtual int marshal_client_req_unmapped_url_host(char *);  // STR
-  virtual int marshal_client_req_url_path(char *);           // STR
-  virtual int marshal_client_req_url_scheme(char *);         // STR
-  virtual int marshal_client_req_http_version(char *);       // INT
-  virtual int marshal_client_req_protocol_version(char *);   // STR
-  virtual int marshal_client_req_header_len(char *);         // INT
-  virtual int marshal_client_req_content_len(char *);        // INT
-  virtual int marshal_client_req_squid_len(char *);          // INT
-  virtual int marshal_client_req_tcp_reused(char *);         // INT
-  virtual int marshal_client_req_is_ssl(char *);             // INT
-  virtual int marshal_client_req_ssl_reused(char *);         // INT
-  virtual int marshal_client_req_timestamp_sec(char *);      // INT
-  virtual int marshal_client_req_timestamp_ms(char *);       // INT
-  virtual int marshal_client_security_protocol(char *);      // STR
-  virtual int marshal_client_security_cipher_suite(char *);  // STR
-  virtual int marshal_client_finish_status_code(char *);     // INT
-  virtual int marshal_client_req_id(char *);                 // INT
-  virtual int marshal_client_req_uuid(char *);               // STR
+  int marshal_client_host_ip(char *) override;                // STR
+  int marshal_host_interface_ip(char *) override;             // STR
+  int marshal_client_host_port(char *) override;              // INT
+  int marshal_client_auth_user_name(char *) override;         // STR
+  int marshal_client_req_text(char *) override;               // STR
+  int marshal_client_req_http_method(char *) override;        // INT
+  int marshal_client_req_url(char *) override;                // STR
+  int marshal_client_req_url_canon(char *) override;          // STR
+  int marshal_client_req_unmapped_url_canon(char *) override; // STR
+  int marshal_client_req_unmapped_url_path(char *) override;  // STR
+  int marshal_client_req_unmapped_url_host(char *) override;  // STR
+  int marshal_client_req_url_path(char *) override;           // STR
+  int marshal_client_req_url_scheme(char *) override;         // STR
+  int marshal_client_req_http_version(char *) override;       // INT
+  int marshal_client_req_protocol_version(char *) override;   // STR
+  int marshal_client_req_header_len(char *) override;         // INT
+  int marshal_client_req_content_len(char *) override;        // INT
+  int marshal_client_req_squid_len(char *) override;          // INT
+  int marshal_client_req_tcp_reused(char *) override;         // INT
+  int marshal_client_req_is_ssl(char *) override;             // INT
+  int marshal_client_req_ssl_reused(char *) override;         // INT
+  int marshal_client_req_timestamp_sec(char *) override;      // INT
+  int marshal_client_req_timestamp_ms(char *) override;       // INT
+  int marshal_client_security_protocol(char *) override;      // STR
+  int marshal_client_security_cipher_suite(char *) override;  // STR
+  int marshal_client_finish_status_code(char *) override;     // INT
+  int marshal_client_req_id(char *) override;                 // INT
+  int marshal_client_req_uuid(char *) override;               // STR
 
   //
   // proxy -> client fields
   //
-  virtual int marshal_proxy_resp_content_type(char *);  // STR
-  virtual int marshal_proxy_resp_header_len(char *);    // INT
-  virtual int marshal_proxy_resp_content_len(char *);   // INT
-  virtual int marshal_proxy_resp_squid_len(char *);     // INT
-  virtual int marshal_proxy_resp_status_code(char *);   // INT
-  virtual int marshal_proxy_finish_status_code(char *); // INT
-  virtual int marshal_cache_result_code(char *);        // INT
-  virtual int marshal_cache_hit_miss(char *);           // INT
+  int marshal_proxy_resp_content_type(char *) override;  // STR
+  int marshal_proxy_resp_header_len(char *) override;    // INT
+  int marshal_proxy_resp_content_len(char *) override;   // INT
+  int marshal_proxy_resp_squid_len(char *) override;     // INT
+  int marshal_proxy_resp_status_code(char *) override;   // INT
+  int marshal_proxy_finish_status_code(char *) override; // INT
+  int marshal_cache_result_code(char *) override;        // INT
+  int marshal_cache_hit_miss(char *) override;           // INT
 
   //
   // proxy -> server fields
   //
-  virtual int marshal_proxy_req_header_len(char *);  // INT
-  virtual int marshal_proxy_req_content_len(char *); // INT
-  virtual int marshal_proxy_req_squid_len(char *);   // INT
-  virtual int marshal_proxy_req_server_name(char *); // STR
-  virtual int marshal_proxy_req_server_ip(char *);   // INT
-  virtual int marshal_proxy_req_server_port(char *); // INT
-  virtual int marshal_proxy_hierarchy_route(char *); // INT
-  virtual int marshal_proxy_host_port(char *);       // INT
-  virtual int marshal_proxy_req_is_ssl(char *);      // INT
+  int marshal_proxy_req_header_len(char *) override;  // INT
+  int marshal_proxy_req_content_len(char *) override; // INT
+  int marshal_proxy_req_squid_len(char *) override;   // INT
+  int marshal_proxy_req_server_name(char *) override; // STR
+  int marshal_proxy_req_server_ip(char *) override;   // INT
+  int marshal_proxy_req_server_port(char *) override; // INT
+  int marshal_proxy_hierarchy_route(char *) override; // INT
+  int marshal_proxy_host_port(char *) override;       // INT
+  int marshal_proxy_req_is_ssl(char *) override;      // INT
 
   //
   // server -> proxy fields
   //
-  virtual int marshal_server_host_ip(char *);           // INT
-  virtual int marshal_server_host_name(char *);         // STR
-  virtual int marshal_server_resp_status_code(char *);  // INT
-  virtual int marshal_server_resp_header_len(char *);   // INT
-  virtual int marshal_server_resp_content_len(char *);  // INT
-  virtual int marshal_server_resp_squid_len(char *);    // INT
-  virtual int marshal_server_resp_http_version(char *); // INT
-  virtual int marshal_server_resp_time_ms(char *);      // INT
-  virtual int marshal_server_resp_time_s(char *);       // INT
-  virtual int marshal_server_transact_count(char *);    // INT
-  virtual int marshal_server_connect_attempts(char *);  // INT
+  int marshal_server_host_ip(char *) override;           // INT
+  int marshal_server_host_name(char *) override;         // STR
+  int marshal_server_resp_status_code(char *) override;  // INT
+  int marshal_server_resp_header_len(char *) override;   // INT
+  int marshal_server_resp_content_len(char *) override;  // INT
+  int marshal_server_resp_squid_len(char *) override;    // INT
+  int marshal_server_resp_http_version(char *) override; // INT
+  int marshal_server_resp_time_ms(char *) override;      // INT
+  int marshal_server_resp_time_s(char *) override;       // INT
+  int marshal_server_transact_count(char *) override;    // INT
+  int marshal_server_connect_attempts(char *) override;  // INT
 
   //
   // cache -> client fields
   //
-  virtual int marshal_cache_resp_status_code(char *);  // INT
-  virtual int marshal_cache_resp_header_len(char *);   // INT
-  virtual int marshal_cache_resp_content_len(char *);  // INT
-  virtual int marshal_cache_resp_squid_len(char *);    // INT
-  virtual int marshal_cache_resp_http_version(char *); // INT
+  int marshal_cache_resp_status_code(char *) override;  // INT
+  int marshal_cache_resp_header_len(char *) override;   // INT
+  int marshal_cache_resp_content_len(char *) override;  // INT
+  int marshal_cache_resp_squid_len(char *) override;    // INT
+  int marshal_cache_resp_http_version(char *) override; // INT
 
   //
   // congestion control client_retry_after_time
   //
-  virtual int marshal_client_retry_after_time(char *); // INT
+  int marshal_client_retry_after_time(char *) override; // INT
 
   //
   // cache write fields
   //
-  virtual int marshal_cache_write_code(char *);           // INT
-  virtual int marshal_cache_write_transform_code(char *); // INT
+  int marshal_cache_write_code(char *) override;           // INT
+  int marshal_cache_write_transform_code(char *) override; // INT
 
   //
   // other fields
@@ -159,20 +159,21 @@ public:
   //
   // named fields from within a http header
   //
-  virtual int marshal_http_header_field(LogField::Container container, char *field, char *buf);
-  virtual int marshal_http_header_field_escapify(LogField::Container container, char *field, char *buf);
+  int marshal_http_header_field(LogField::Container container, char *field, char *buf) override;
+  int marshal_http_header_field_escapify(LogField::Container container, char *field, char *buf) override;
 
-  virtual int marshal_milestone(TSMilestonesType ms, char *buf);
-  virtual int marshal_milestone_fmt_sec(TSMilestonesType ms, char *buf);
-  virtual int marshal_milestone_fmt_ms(TSMilestonesType ms, char *buf);
-  virtual int marshal_milestone_diff(TSMilestonesType ms1, TSMilestonesType ms2, char *buf);
+  int marshal_milestone(TSMilestonesType ms, char *buf) override;
+  int marshal_milestone_fmt_sec(TSMilestonesType ms, char *buf) override;
+  int marshal_milestone_diff(TSMilestonesType ms1, TSMilestonesType ms2, char *buf) override;
 
-  virtual void set_client_req_url(char *, int);                // STR
-  virtual void set_client_req_url_canon(char *, int);          // STR
-  virtual void set_client_req_unmapped_url_canon(char *, int); // STR
-  virtual void set_client_req_unmapped_url_path(char *, int);  // STR
-  virtual void set_client_req_unmapped_url_host(char *, int);  // STR
-  virtual void set_client_req_url_path(char *, int);           // STR
+  int marshal_milestone_fmt_ms(TSMilestonesType ms, char *buf);
+
+  void set_client_req_url(char *, int) override;                // STR
+  void set_client_req_url_canon(char *, int) override;          // STR
+  void set_client_req_unmapped_url_canon(char *, int) override; // STR
+  void set_client_req_unmapped_url_path(char *, int) override;  // STR
+  void set_client_req_unmapped_url_host(char *, int) override;  // STR
+  void set_client_req_url_path(char *, int) override;           // STR
 
 private:
   HttpSM *m_http_sm;

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.

[trafficserver] 01/08: Coverity CID #1367529 Copy into fixed size buffer

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

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

commit 554400a4d6433f5260204fd08a034eecc919ee83
Author: Phil Sorber <so...@apache.org>
AuthorDate: Tue May 16 13:56:11 2017 -0600

    Coverity CID #1367529 Copy into fixed size buffer
    
    (cherry picked from commit ba7066870c21736758c041b0315e8da90afd55d8)
---
 plugins/experimental/url_sig/url_sig.c | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/plugins/experimental/url_sig/url_sig.c b/plugins/experimental/url_sig/url_sig.c
index 240c9a5..3dc0de1 100644
--- a/plugins/experimental/url_sig/url_sig.c
+++ b/plugins/experimental/url_sig/url_sig.c
@@ -16,6 +16,13 @@
   limitations under the License.
  */
 
+#define min(a, b)           \
+  ({                        \
+    __typeof__(a) _a = (a); \
+    __typeof__(b) _b = (b); \
+    _a < _b ? _a : _b;      \
+  })
+
 #include "ts/ink_defs.h"
 #include "url_sig.h"
 
@@ -254,18 +261,18 @@ err_log(char *url, char *msg)
 // See the README.  All Signing parameters must be concatenated to the end
 // of the url and any application query parameters.
 static char *
-getAppQueryString(char *query_string, int query_length)
+getAppQueryString(char *query_string, unsigned int query_length)
 {
   int done = 0;
   char *p;
   char buf[MAX_QUERY_LEN];
 
-  if (query_length > MAX_QUERY_LEN) {
-    TSDebug(PLUGIN_NAME, "Cannot process the query string as the length exceeds %d bytes.", MAX_QUERY_LEN);
+  if (query_length >= sizeof(buf)) {
+    TSDebug(PLUGIN_NAME, "Cannot process the query string as the length exceeds %d bytes", MAX_QUERY_LEN);
     return NULL;
   }
   memset(buf, 0, MAX_QUERY_LEN);
-  strncpy(buf, query_string, query_length);
+  strncpy(buf, query_string, min(query_length, sizeof(buf) - 1));
   p = buf;
 
   TSDebug(PLUGIN_NAME, "query_string: %s, query_length: %d", query_string, query_length);
@@ -391,7 +398,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
       err_log(url, "IP address string too long or short.");
       goto deny;
     }
-    strncpy(client_ip, p + strlen(CIP_QSTRING) + 1, (pp - p - (strlen(CIP_QSTRING) + 1)));
+    strncpy(client_ip, p + strlen(CIP_QSTRING) + 1, min((pp - p - (strlen(CIP_QSTRING) + 1)), sizeof(client_ip) - 1));
     client_ip[pp - p - (strlen(CIP_QSTRING) + 1)] = '\0';
     TSDebug(PLUGIN_NAME, "CIP: -%s-", client_ip);
     retval = TSHttpTxnClientFdGet(txnp, &sockfd);
@@ -486,8 +493,8 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
   part = strtok_r(urltokstr, "/", &p);
   while (part != NULL) {
     if (parts[j] == '1') {
-      strcpy(signed_part + strlen(signed_part), part);
-      strcpy(signed_part + strlen(signed_part), "/");
+      strncat(signed_part, part, sizeof(signed_part) - strlen(signed_part) - 1);
+      strncat(signed_part, "/", sizeof(signed_part) - strlen(signed_part) - 1);
     }
     if (parts[j + 1] == '0' ||
         parts[j + 1] == '1') { // This remembers the last part, meaning, if there are no more valid letters in parts
@@ -498,7 +505,7 @@ TSRemapDoRemap(void *ih, TSHttpTxn txnp, TSRemapRequestInfo *rri)
 
   signed_part[strlen(signed_part) - 1] = '?'; // chop off the last /, replace with '?'
   p                                    = strstr(query, SIG_QSTRING "=");
-  strncat(signed_part, query, (p - query) + strlen(SIG_QSTRING) + 1);
+  strncat(signed_part, query, min((p - query) + strlen(SIG_QSTRING) + 1, sizeof(signed_part) - strlen(signed_part) - 1));
 
   TSDebug(PLUGIN_NAME, "Signed string=\"%s\"", signed_part);
 

-- 
To stop receiving notification emails like this one, please contact
zwoop@apache.org.