Repository: trafficserver
Updated Branches:
  refs/heads/master 030a15d59 -> 63757db53


TS-3149: add traffic_via command

Move Via header decoding from traffic_line to a new command,
traffic_via. This closes #133.


Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/63757db5
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/63757db5
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/63757db5

Branch: refs/heads/master
Commit: 63757db53eed5d16a2ae2ee1b24c8d568bda0c80
Parents: 030a15d
Author: Meera Mosale Nataraja <[email protected]>
Authored: Wed Oct 29 15:40:42 2014 -0700
Committer: James Peach <[email protected]>
Committed: Thu Oct 30 12:31:00 2014 -0700

----------------------------------------------------------------------
 CHANGES                                    |   3 +
 cmd/Makefile.am                            |   3 +-
 cmd/traffic_line/traffic_line.cc           | 220 ---------------
 cmd/traffic_via/Makefile.am                |  34 +++
 cmd/traffic_via/traffic_via.cc             | 348 ++++++++++++++++++++++++
 configure.ac                               |   1 +
 doc/manpages.py                            |   1 +
 doc/reference/commands/index.en.rst        |   1 +
 doc/reference/commands/traffic_line.en.rst |   5 -
 doc/reference/commands/traffic_via.en.rst  |  90 ++++++
 lib/ts/ink_args.cc                         |  33 ++-
 11 files changed, 504 insertions(+), 235 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 0f44cc4..73b576d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache Traffic Server 5.2.0
 
+  *) [TS-3149] Move Via decode out of traffic_line and make a separate tool.
+   Author: Meera Mosale Nataraja <[email protected]>
+
   *) [TS-3151] Added an extra check for background fills to avoid crash.
 
   *) [TS-3119] Add SO_LINGER socket option support.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/cmd/Makefile.am
----------------------------------------------------------------------
diff --git a/cmd/Makefile.am b/cmd/Makefile.am
index 764e18b..80a13e2 100644
--- a/cmd/Makefile.am
+++ b/cmd/Makefile.am
@@ -20,4 +20,5 @@ SUBDIRS = \
   traffic_layout \
   traffic_line \
   traffic_manager \
-  traffic_top
+  traffic_top \
+  traffic_via

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/cmd/traffic_line/traffic_line.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_line/traffic_line.cc b/cmd/traffic_line/traffic_line.cc
index 73ef29b..f998730 100644
--- a/cmd/traffic_line/traffic_line.cc
+++ b/cmd/traffic_line/traffic_line.cc
@@ -52,220 +52,6 @@ static int ShowAlarms;
 static int ShowStatus;
 static int ShowBacktrace;
 static char ClearAlarms[1024];
-static char viaHeader[1024];
-
-struct VIA
-{
-  VIA() : title(NULL), next(NULL) { }
-  VIA(const char * t) : title(t), next(NULL) { }
-
-  ~VIA() {
-    delete next;
-  }
-
-  const char * title;
-  const char * viaData[128];
-  VIA * next;
-};
-
-//Function to get via header table for every field/category in the via header
-static VIA *
-detailViaLookup(char flag)
-{
-  VIA * viaTable = NULL;
-
-  //Detailed via codes after ":"
-  switch (flag) {
-  case 't':
-    viaTable = new VIA("Tunnel info");
-    viaTable->viaData[(unsigned char) ' '] = "no tunneling";
-    viaTable->viaData[(unsigned char) 'U'] = "tunneling because of url (url 
suggests dynamic content)";
-    viaTable->viaData[(unsigned char) 'M'] = "tunneling due to a method (e.g. 
CONNECT)";
-    viaTable->viaData[(unsigned char) 'O'] = "tunneling because cache is 
turned off";
-    viaTable->viaData[(unsigned char) 'F'] = "tunneling due to a header field 
(such as presence of If-Range header)";
-    break;
-  case 'c':
-    //Cache type
-    viaTable = new VIA( "Cache Type");
-    viaTable->viaData[(unsigned char) 'C'] = "cache";
-    viaTable->viaData[(unsigned char) 'L'] = "cluster, (not used)";
-    viaTable->viaData[(unsigned char) 'I'] = "icp";
-    viaTable->viaData[(unsigned char) ' '] = "unknown";
-
-    //Cache Lookup Result
-    viaTable->next = new VIA("Cache Lookup Result");
-    viaTable->next->viaData[(unsigned char) 'C'] = "cache hit but config 
forces revalidate";
-    viaTable->next->viaData[(unsigned char) 'I'] = "conditional miss (client 
sent conditional, fresh in cache, returned 412)";
-    viaTable->next->viaData[(unsigned char) ' '] = "cache miss or no cache 
lookup";
-    viaTable->next->viaData[(unsigned char) 'U'] = "cache hit, but client 
forces revalidate (e.g. Pragma: no-cache)";
-    viaTable->next->viaData[(unsigned char) 'D'] = "cache hit, but method 
forces revalidated (e.g. ftp, not anonymous)";
-    viaTable->next->viaData[(unsigned char) 'M'] = "cache miss (url not in 
cache)";
-    viaTable->next->viaData[(unsigned char) 'N'] = "conditional hit (client 
sent conditional, doc fresh in cache, returned 304)";
-    viaTable->next->viaData[(unsigned char) 'H'] = "cache hit";
-    viaTable->next->viaData[(unsigned char) 'S'] = "cache hit, but expired";
-    break;
-  case 'i':
-    viaTable = new VIA("ICP status");
-    viaTable->viaData[(unsigned char) ' '] = "no icp";
-    viaTable->viaData[(unsigned char) 'S'] = "connection opened successfully";
-    viaTable->viaData[(unsigned char) 'F'] = "connection open failed";
-    break;
-  case 'p':
-    viaTable = new VIA("Parent proxy connection status");
-    viaTable->viaData[(unsigned char) ' '] = "no parent proxy or unknown";
-    viaTable->viaData[(unsigned char) 'S'] = "connection opened successfully";
-    viaTable->viaData[(unsigned char) 'F'] = "connection open failed";
-    break;
-  case 's':
-    viaTable = new VIA("Origin server connection status");
-    viaTable->viaData[(unsigned char) ' '] = "no server connection needed";
-    viaTable->viaData[(unsigned char) 'S'] = "connection opened successfully";
-    viaTable->viaData[(unsigned char) 'F'] = "connection open failed";
-    break;
-  default:
-    fprintf(stderr, "%s: %s: %c\n", program_name, "Invalid VIA header 
character",flag);
-    break;
-  }
-  return viaTable;
-}
-
-//Function to get via header table for every field/category in the via header
-static VIA *
-standardViaLookup(char flag)
-{
-  VIA * viaTable;
-
-  //Via codes before ":"
-  switch (flag) {
-    case 'u':
-      viaTable = new VIA("Request headers received from client");
-      viaTable->viaData[(unsigned char) 'C'] = "cookie";
-      viaTable->viaData[(unsigned char) 'E'] = "error in request";
-      viaTable->viaData[(unsigned char) 'S'] = "simple request (not 
conditional)";
-      viaTable->viaData[(unsigned char) 'N'] = "no-cache";
-      viaTable->viaData[(unsigned char) 'I'] = "IMS";
-      viaTable->viaData[(unsigned char) ' '] = "unknown";
-      break;
-    case 'c':
-      viaTable = new VIA( "Result of Traffic Server cache lookup for URL");
-      viaTable->viaData[(unsigned char) 'A'] = "in cache, not acceptable (a 
cache \"MISS\")";
-      viaTable->viaData[(unsigned char) 'H'] = "in cache, fresh (a cache 
\"HIT\")";
-      viaTable->viaData[(unsigned char) 'S'] = "in cache, stale (a cache 
\"MISS\")";
-      viaTable->viaData[(unsigned char) 'R'] = "in cache, fresh Ram hit (a 
cache \"HIT\")";
-      viaTable->viaData[(unsigned char) 'M'] = "miss (a cache \"MISS\")";
-      viaTable->viaData[(unsigned char) ' '] = "no cache lookup";
-      break;
-    case 's':
-      viaTable = new VIA("Response information received from origin server");
-      viaTable->viaData[(unsigned char) 'E'] = "error in response";
-      viaTable->viaData[(unsigned char) 'S'] = "connection opened 
successfully";
-      viaTable->viaData[(unsigned char) 'N'] = "not-modified";
-      viaTable->viaData[(unsigned char) ' '] = "no server connection needed";
-      break;
-    case 'f':
-      viaTable = new VIA("Result of document write-to-cache:");
-      viaTable->viaData[(unsigned char) 'U'] = "updated old cache copy";
-      viaTable->viaData[(unsigned char) 'D'] = "cached copy deleted";
-      viaTable->viaData[(unsigned char) 'W'] = "written into cache (new copy)";
-      viaTable->viaData[(unsigned char) ' '] = "no cache write performed";
-      break;
-    case 'p':
-      viaTable = new VIA("Proxy operation result");
-      viaTable->viaData[(unsigned char) 'R'] = "origin server revalidated";
-      viaTable->viaData[(unsigned char) ' '] = "unknown";
-      viaTable->viaData[(unsigned char) 'S'] = "served or connection opened 
successfully";
-      viaTable->viaData[(unsigned char) 'N'] = "not-modified";
-      break;
-    case 'e':
-      viaTable = new VIA("Error codes (if any)");
-      viaTable->viaData[(unsigned char) 'A'] = "authorization failure";
-      viaTable->viaData[(unsigned char) 'H'] = "header syntax unacceptable";
-      viaTable->viaData[(unsigned char) 'C'] = "connection to server failed";
-      viaTable->viaData[(unsigned char) 'T'] = "connection timed out";
-      viaTable->viaData[(unsigned char) 'S'] = "server related error";
-      viaTable->viaData[(unsigned char) 'D'] = "dns failure";
-      viaTable->viaData[(unsigned char) 'N'] = "no error";
-      viaTable->viaData[(unsigned char) 'F'] = "request forbidden";
-      viaTable->viaData[(unsigned char) ' '] = "unknown";
-      break;
-    default:
-      viaTable = new VIA();
-      fprintf(stderr, "%s: %s: %c\n", program_name, "Invalid VIA header 
character",flag);
-      break;
-  }
-  return viaTable;
-}
-
-//Function to print via header
-static void
-printViaHeader(const char * header)
-{
-  VIA * viaTable = NULL;
-  VIA * viaEntry = NULL;
-  bool isDetail = false;
-
-  printf("Via Header Details:\n");
-
-  //Loop through input via header flags
-  for (const char * c = header; *c; ++c) {
-
-    if (*c == ':') {
-      isDetail = true;
-      continue;
-    }
-
-    if (islower(*c)) {
-      //Get the via header table
-      delete viaTable;
-      viaEntry = viaTable = isDetail ? detailViaLookup(*c) : 
standardViaLookup(*c);
-    } else {
-      // This is a one of the sequence of (uppercase) VIA codes.
-      if (viaEntry) {
-        printf("%-55s:", viaEntry->title);
-        printf("%s\n", viaEntry->viaData[(unsigned char)*c]);
-        viaEntry = viaEntry->next;
-      }
-    }
-  }
-
-  delete viaTable;
-}
-
-//Check validity of via header and then decode it
-static TSMgmtError
-decodeViaHeader(char * Via)
-{
-  size_t viaHdrLength = strlen(Via);
-
-#ifdef DEBUG
-  printf("Via header is %s, Length is %zu\n",Via, viaHdrLength);
-#endif
-
-  // Via header inside square brackets ...
-  if (viaHdrLength > 2 && Via[0] == '[' && Via[viaHdrLength - 1] == ']') {
-    viaHdrLength = viaHdrLength - 2;
-    Via++;
-    Via[viaHdrLength] = '\0'; //null terminate the string after trimming
-  }
-
-  if (viaHdrLength == 24 || viaHdrLength == 6) {
-    //Decode via header
-    printViaHeader(Via);
-    return TS_ERR_OKAY;
-  }
-
-  // Be kind to people who did not quote the via argument correctly
-  // by appending one space character before decoding via header.
-  if (viaHdrLength == 23 || viaHdrLength == 5) {
-    Via = strcat(Via, " ");
-    printViaHeader(Via);
-    return TS_ERR_OKAY;
-  }
-
-  printf("\nInvalid VIA header. VIA header length should be 6 or 24 
characters\n");
-  printf("Valid via header format is 
[u<client-stuff>c<cache-lookup-stuff>s<server-stuff>f<cache-fill-stuff>p<proxy-stuff>]e<error-codes>:t<tunneling-info>c<cache
 
type><cache-lookup-result>i<icp-conn-info>p<parent-proxy-conn-info>s<server-conn-info>]");
-  return TS_ERR_FAIL;
-}
 
 static TSMgmtError
 handleArgInvocation()
@@ -507,10 +293,6 @@ handleArgInvocation()
   } else if (*VarValue != '\0') {       // We have a value but no variable to 
set
     fprintf(stderr, "%s: Must specify variable to set with -s when using 
-v\n", program_name);
     return TS_ERR_FAIL;
-  } else if (*viaHeader != '\0') {        // Read via header and decode
-    TSMgmtError rc;
-    rc = decodeViaHeader(viaHeader);
-    return rc;
   }
 
   fprintf(stderr, "%s: No arguments specified\n", program_name);
@@ -548,7 +330,6 @@ main(int /* argc ATS_UNUSED */, char **argv)
   ShowAlarms = 0;
   ShowStatus = 0;
   ClearAlarms[0] = '\0';
-  viaHeader[0] = '\0';
 
 /* Argument description table used to describe how to parse command line args, 
*/
 /* see 'ink_args.h' for meanings of the various fields */
@@ -574,7 +355,6 @@ main(int /* argc ATS_UNUSED */, char **argv)
     {"clear_alarms", '-', "Clear specified, or all,  alarms", "S1024", 
&ClearAlarms, NULL, NULL},
     {"status", '-', "Show proxy server status", "F", &ShowStatus, NULL, NULL},
     {"backtrace", '-', "Show proxy stack backtrace", "F", &ShowBacktrace, 
NULL, NULL},
-    {"decode_via", '-', "Decode Via Header", "S1024", &viaHeader, NULL, NULL},
     HELP_ARGUMENT_DESCRIPTION(),
     VERSION_ARGUMENT_DESCRIPTION()
   };

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/cmd/traffic_via/Makefile.am
----------------------------------------------------------------------
diff --git a/cmd/traffic_via/Makefile.am b/cmd/traffic_via/Makefile.am
new file mode 100644
index 0000000..c9482e2
--- /dev/null
+++ b/cmd/traffic_via/Makefile.am
@@ -0,0 +1,34 @@
+#
+# Makefile.am for the Enterprise Management module.
+#
+#  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.
+
+AM_CPPFLAGS = \
+  $(iocore_include_dirs) \
+  -I$(top_srcdir)/lib \
+  -I$(top_srcdir)/lib/ts \
+  -I$(top_srcdir)/mgmt/api/include
+
+bin_PROGRAMS = traffic_via
+
+traffic_via_SOURCES = \
+  traffic_via.cc
+
+traffic_via_LDFLAGS = @EXTRA_CXX_LDFLAGS@ @LIBTOOL_LINK_FLAGS@
+traffic_via_LDADD = \
+  $(top_builddir)/lib/ts/libtsutil.la \
+  @LIBTCL@

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/cmd/traffic_via/traffic_via.cc
----------------------------------------------------------------------
diff --git a/cmd/traffic_via/traffic_via.cc b/cmd/traffic_via/traffic_via.cc
new file mode 100644
index 0000000..1321f1e
--- /dev/null
+++ b/cmd/traffic_via/traffic_via.cc
@@ -0,0 +1,348 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include "libts.h"
+
+#include "ink_args.h"
+#include "I_Version.h"
+#include "Tokenizer.h"
+#include "TextBuffer.h"
+#include "mgmtapi.h"
+#include <stdio.h>
+#include <string.h>
+#include "Regex.h"
+
+/// XXX Use DFA or Regex wrappers?
+#ifdef HAVE_PCRE_PCRE_H
+#include <pcre/pcre.h>
+#else
+#include <pcre.h>
+#endif
+
+#define SUBSTRING_VECTOR_COUNT 30 //Should be multiple of 3
+
+static AppVersionInfo appVersionInfo;
+
+struct VIA
+{
+  VIA() : title(NULL), next(NULL) { }
+  VIA(const char * t) : title(t), next(NULL) { }
+
+  ~VIA() {
+    delete next;
+  }
+
+  const char * title;
+  const char * viaData[128];
+  VIA * next;
+};
+
+//Function to get via header table for every field/category in the via header
+static VIA *
+detailViaLookup(char flag)
+{
+  VIA * viaTable = new VIA();
+
+  //Detailed via codes after ":"
+  switch (flag) {
+  case 't':
+    viaTable = new VIA("Tunnel info");
+    viaTable->viaData[(unsigned char) ' '] = "no tunneling";
+    viaTable->viaData[(unsigned char) 'U'] = "tunneling because of url (url 
suggests dynamic content)";
+    viaTable->viaData[(unsigned char) 'M'] = "tunneling due to a method (e.g. 
CONNECT)";
+    viaTable->viaData[(unsigned char) 'O'] = "tunneling because cache is 
turned off";
+    viaTable->viaData[(unsigned char) 'F'] = "tunneling due to a header field 
(such as presence of If-Range header)";
+    viaTable->viaData[(unsigned char) 'N'] = "tunneling due to no forward";
+    viaTable->viaData[(unsigned char) 'A'] = "tunnel authorization";
+    break;
+  case 'c':
+    //Cache type
+    viaTable = new VIA( "Cache Type");
+    viaTable->viaData[(unsigned char) 'C'] = "cache";
+    viaTable->viaData[(unsigned char) 'L'] = "cluster, (not used)";
+    viaTable->viaData[(unsigned char) 'I'] = "icp";
+    viaTable->viaData[(unsigned char) 'P'] = "parent";
+    viaTable->viaData[(unsigned char) 'S'] = "server";
+    viaTable->viaData[(unsigned char) ' '] = "unknown";
+
+    //Cache Lookup Result
+    viaTable->next = new VIA("Cache Lookup Result");
+    viaTable->next->viaData[(unsigned char) 'C'] = "cache hit but config 
forces revalidate";
+    viaTable->next->viaData[(unsigned char) 'I'] = "conditional miss (client 
sent conditional, fresh in cache, returned 412)";
+    viaTable->next->viaData[(unsigned char) ' '] = "cache miss or no cache 
lookup";
+    viaTable->next->viaData[(unsigned char) 'U'] = "cache hit, but client 
forces revalidate (e.g. Pragma: no-cache)";
+    viaTable->next->viaData[(unsigned char) 'D'] = "cache hit, but method 
forces revalidated (e.g. ftp, not anonymous)";
+    viaTable->next->viaData[(unsigned char) 'M'] = "cache miss (url not in 
cache)";
+    viaTable->next->viaData[(unsigned char) 'N'] = "conditional hit (client 
sent conditional, doc fresh in cache, returned 304)";
+    viaTable->next->viaData[(unsigned char) 'H'] = "cache hit";
+    viaTable->next->viaData[(unsigned char) 'S'] = "cache hit, but expired";
+    viaTable->next->viaData[(unsigned char) 'K'] = "cookie miss";
+    break;
+  case 'i':
+    viaTable = new VIA("ICP status");
+    viaTable->viaData[(unsigned char) ' '] = "no icp";
+    viaTable->viaData[(unsigned char) 'S'] = "connection opened successfully";
+    viaTable->viaData[(unsigned char) 'F'] = "connection open failed";
+    break;
+  case 'p':
+    viaTable = new VIA("Parent proxy connection status");
+    viaTable->viaData[(unsigned char) ' '] = "no parent proxy or unknown";
+    viaTable->viaData[(unsigned char) 'S'] = "connection opened successfully";
+    viaTable->viaData[(unsigned char) 'F'] = "connection open failed";
+    break;
+  case 's':
+    viaTable = new VIA("Origin server connection status");
+    viaTable->viaData[(unsigned char) ' '] = "no server connection needed";
+    viaTable->viaData[(unsigned char) 'S'] = "connection opened successfully";
+    viaTable->viaData[(unsigned char) 'F'] = "connection open failed";
+    break;
+  default:
+    fprintf(stderr, "%s: %s: %c\n", appVersionInfo.AppStr, "Invalid VIA header 
character",flag);
+    break;
+  }
+  return viaTable;
+}
+
+//Function to get via header table for every field/category in the via header
+static VIA *
+standardViaLookup(char flag)
+{
+  VIA * viaTable;
+
+  viaTable = new VIA();
+
+  //Via codes before ":"
+  switch (flag) {
+    case 'u':
+      viaTable = new VIA("Request headers received from client");
+      viaTable->viaData[(unsigned char) 'C'] = "cookie";
+      viaTable->viaData[(unsigned char) 'E'] = "error in request";
+      viaTable->viaData[(unsigned char) 'S'] = "simple request (not 
conditional)";
+      viaTable->viaData[(unsigned char) 'N'] = "no-cache";
+      viaTable->viaData[(unsigned char) 'I'] = "IMS";
+      viaTable->viaData[(unsigned char) ' '] = "unknown";
+      break;
+    case 'c':
+      viaTable = new VIA( "Result of Traffic Server cache lookup for URL");
+      viaTable->viaData[(unsigned char) 'A'] = "in cache, not acceptable (a 
cache \"MISS\")";
+      viaTable->viaData[(unsigned char) 'H'] = "in cache, fresh (a cache 
\"HIT\")";
+      viaTable->viaData[(unsigned char) 'S'] = "in cache, stale (a cache 
\"MISS\")";
+      viaTable->viaData[(unsigned char) 'R'] = "in cache, fresh Ram hit (a 
cache \"HIT\")";
+      viaTable->viaData[(unsigned char) 'M'] = "miss (a cache \"MISS\")";
+      viaTable->viaData[(unsigned char) ' '] = "no cache lookup";
+      break;
+    case 's':
+      viaTable = new VIA("Response information received from origin server");
+      viaTable->viaData[(unsigned char) 'E'] = "error in response";
+      viaTable->viaData[(unsigned char) 'S'] = "connection opened 
successfully";
+      viaTable->viaData[(unsigned char) 'N'] = "not-modified";
+      viaTable->viaData[(unsigned char) ' '] = "no server connection needed";
+      break;
+    case 'f':
+      viaTable = new VIA("Result of document write-to-cache:");
+      viaTable->viaData[(unsigned char) 'U'] = "updated old cache copy";
+      viaTable->viaData[(unsigned char) 'D'] = "cached copy deleted";
+      viaTable->viaData[(unsigned char) 'W'] = "written into cache (new copy)";
+      viaTable->viaData[(unsigned char) ' '] = "no cache write performed";
+      break;
+    case 'p':
+      viaTable = new VIA("Proxy operation result");
+      viaTable->viaData[(unsigned char) 'R'] = "origin server revalidated";
+      viaTable->viaData[(unsigned char) ' '] = "unknown";
+      viaTable->viaData[(unsigned char) 'S'] = "served or connection opened 
successfully";
+      viaTable->viaData[(unsigned char) 'N'] = "not-modified";
+      break;
+    case 'e':
+      viaTable = new VIA("Error codes (if any)");
+      viaTable->viaData[(unsigned char) 'A'] = "authorization failure";
+      viaTable->viaData[(unsigned char) 'H'] = "header syntax unacceptable";
+      viaTable->viaData[(unsigned char) 'C'] = "connection to server failed";
+      viaTable->viaData[(unsigned char) 'T'] = "connection timed out";
+      viaTable->viaData[(unsigned char) 'S'] = "server related error";
+      viaTable->viaData[(unsigned char) 'D'] = "dns failure";
+      viaTable->viaData[(unsigned char) 'N'] = "no error";
+      viaTable->viaData[(unsigned char) 'F'] = "request forbidden";
+      viaTable->viaData[(unsigned char) 'R'] = "cache read error";
+      viaTable->viaData[(unsigned char) ' '] = "unknown";
+      break;
+    default:
+      fprintf(stderr, "%s: %s: %c\n", appVersionInfo.AppStr, "Invalid VIA 
header character",flag);
+      break;
+  }
+  return viaTable;
+}
+
+//Function to print via header
+static void
+printViaHeader(const char * header)
+{
+  VIA * viaTable = NULL;
+  VIA * viaEntry = NULL;
+  bool isDetail = false;
+
+  printf("Via Header Details:\n");
+
+  //Loop through input via header flags
+  for (const char * c = header; *c; ++c) {
+    if (*c == ':') {
+      isDetail = true;
+      continue;
+    }
+
+    if (islower(*c)) {
+      //Get the via header table
+      delete viaTable;
+      viaEntry = viaTable = isDetail ? detailViaLookup(*c) : 
standardViaLookup(*c);
+    } else {
+      // This is a one of the sequence of (uppercase) VIA codes.
+      if (viaEntry) {
+        printf("%-55s:", viaEntry->title);
+        printf("%s\n", viaEntry->viaData[(unsigned char)*c]);
+        viaEntry = viaEntry->next;
+      }
+    }
+  }
+  delete viaTable;
+}
+
+//Check validity of via header and then decode it
+static TSMgmtError
+decodeViaHeader(const char * str)
+{
+  size_t viaHdrLength;
+  ats_scoped_str tmp(strdup(str));
+  char * Via = &tmp[0];
+
+  viaHdrLength = strlen(Via);
+  printf("Via header is %s, Length is %zu\n",Via, viaHdrLength);
+
+  //Via header inside square brackets
+  if (Via[0] == '[' && Via[viaHdrLength-1] == ']') {
+    viaHdrLength = viaHdrLength - 2;
+    Via++;
+    Via[viaHdrLength] = '\0'; //null terminate the string after trimming
+  }
+
+  if (viaHdrLength == 24 || viaHdrLength == 6) {
+    //Decode via header
+    printViaHeader(Via);
+    return TS_ERR_OKAY;
+  } else if(viaHdrLength == 5) {
+    Via = strcat(Via," "); //Add one space character before decoding via header
+    printViaHeader(Via);
+    return TS_ERR_OKAY;
+  }
+  //Invalid header size, come out.
+  printf("\nInvalid VIA header. VIA header length should be 6 or 24 
characters\n");
+  printf("Valid via header format is 
[u<client-stuff>c<cache-lookup-stuff>s<server-stuff>f<cache-fill-stuff>p<proxy-stuff>]e<error-codes>:t<tunneling-info>c<cache
 
type><cache-lookup-result>i<icp-conn-info>p<parent-proxy-conn-info>s<server-conn-info>]");
+  return TS_ERR_FAIL;
+}
+
+//Read user input from stdin
+static TSMgmtError
+filterViaHeader()
+{
+  const pcre *compiledReg;
+  const pcre_extra *extraReg = NULL;
+  int subStringVector[SUBSTRING_VECTOR_COUNT];
+  const char *err;
+  int errOffset;
+  int pcreExecCode;
+  int i;
+  const char *viaPattern = "\\[([ucsfpe]+[^\\]]+)\\]"; //Regex to match via 
header with in [] which can start with character class ucsfpe
+  char *viaHeaderString;
+  char viaHeader[1024];
+
+  //Compile PCRE via header pattern
+  compiledReg = pcre_compile(viaPattern, 0, &err, &errOffset, NULL);
+
+  if (compiledReg == NULL) {
+    printf("PCRE regex compilation failed with error %s at offset %d\n", err, 
errOffset);
+    return TS_ERR_FAIL;
+  }
+
+  //Read all lines from stdin
+  while (fgets(viaHeader, sizeof(viaHeader), stdin)) {
+    //Trim new line character and null terminate it
+    char* newLinePtr = strchr(viaHeader, '\n');
+    if (newLinePtr) {
+      *newLinePtr = '\0';
+    }
+    //Match for via header pattern
+    pcreExecCode = pcre_exec(compiledReg, extraReg, viaHeader, 
(int)sizeof(viaHeader), 0, 0, subStringVector, SUBSTRING_VECTOR_COUNT);
+
+    //Match failed, don't worry. Continue to next line.
+    if (pcreExecCode < 0) continue;
+
+    //Match successful, but too many substrings
+    if (pcreExecCode == 0) {
+      pcreExecCode = SUBSTRING_VECTOR_COUNT/3;
+      printf("Too many substrings were found. %d substrings couldn't fit into 
subStringVector\n", pcreExecCode - 1);
+    }
+
+    //Loop based on number of matches found
+    for (i = 1; i < pcreExecCode; i++) {
+      //Point to beginning of matched substring
+      char *subStringBegin = viaHeader + subStringVector[2*i];
+      //Get length of matched substring
+      int subStringLen = subStringVector[2*i+1] - subStringVector[2*i];
+      viaHeaderString = subStringBegin;
+      sprintf(viaHeaderString, "%.*s", subStringLen, subStringBegin);
+      //Decode matched substring
+      decodeViaHeader(viaHeaderString);
+    }
+  }
+  return TS_ERR_OKAY;
+}
+
+int
+main(int /* argc ATS_UNUSED */, char **argv)
+{
+  TSMgmtError status;
+
+  // build the application information structure
+  appVersionInfo.setup(PACKAGE_NAME, "traffic_via", PACKAGE_VERSION, __DATE__, 
__TIME__, BUILD_MACHINE, BUILD_PERSON, "");
+
+  /* see 'ink_args.h' for meanings of the various fields */
+  ArgumentDescription argument_descriptions[] = {
+    VERSION_ARGUMENT_DESCRIPTION(),
+    HELP_ARGUMENT_DESCRIPTION(),
+  };
+
+  process_args(&appVersionInfo, argument_descriptions, 
countof(argument_descriptions), argv);
+
+  for (unsigned i = 0; i < n_file_arguments; ++i) {
+    if (strcmp(file_arguments[i], "-") == 0) {
+      // Filter arguments provided from stdin
+      status = filterViaHeader();
+    } else {
+      status = decodeViaHeader(file_arguments[i]);
+    }
+
+    if (status != TS_ERR_OKAY) {
+      return 1;
+    }
+  }
+
+  return 0;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/configure.ac
----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 7bf4b6f..770d7f1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1856,6 +1856,7 @@ AC_CONFIG_FILES([
   cmd/traffic_line/Makefile
   cmd/traffic_manager/Makefile
   cmd/traffic_top/Makefile
+  cmd/traffic_via/Makefile
   doc/Makefile
   example/Makefile
   iocore/Makefile

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/doc/manpages.py
----------------------------------------------------------------------
diff --git a/doc/manpages.py b/doc/manpages.py
index bbaabf0..ca6b6e8 100644
--- a/doc/manpages.py
+++ b/doc/manpages.py
@@ -31,6 +31,7 @@ man_pages = [
   ('reference/commands/tspush.en', 'tspush', u'Push objects into the Traffic 
Server cache', None, '1'),
   ('reference/commands/traffic_top.en','traffic_top', u'Display Traffic Server 
statistics', None, '1'),
   ('reference/commands/tsxs.en', 'tsxs', u'Traffic Server plugin tool', None, 
'1'),
+  ('reference/commands/traffic_via.en', 'traffic_via', u'Traffic Server Via 
header decoder', None, '1'),
 
   ('reference/configuration/cache.config.en', 'cache.config', u'Traffic Server 
cache configuration file', None, '5'),
   ('reference/configuration/congestion.config.en', 'congestion.config', 
u'Traffic Server congestion control configuration file', None, '5'),

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/doc/reference/commands/index.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/commands/index.en.rst 
b/doc/reference/commands/index.en.rst
index f8681cf..6f42d65 100644
--- a/doc/reference/commands/index.en.rst
+++ b/doc/reference/commands/index.en.rst
@@ -28,5 +28,6 @@ Command Reference
    traffic_manager.en
    traffic_server.en
    traffic_top.en
+   traffic_via.en
    tspush.en
    tsxs.en

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/doc/reference/commands/traffic_line.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/commands/traffic_line.en.rst 
b/doc/reference/commands/traffic_line.en.rst
index 18238e8..2b6791e 100644
--- a/doc/reference/commands/traffic_line.en.rst
+++ b/doc/reference/commands/traffic_line.en.rst
@@ -139,11 +139,6 @@ Options
 
    Show the current proxy server status, indicating if we're running or not.
 
-.. option:: --decode_via VAR
-
-   Decode Via Header and provide detailed explaination of the fields. The 
value of Via header is given by variable VAR.
-   Via header can be given within [] or without []
-
 .. _traffic-line-performance-statistics:
 
 Performance Statistics

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/doc/reference/commands/traffic_via.en.rst
----------------------------------------------------------------------
diff --git a/doc/reference/commands/traffic_via.en.rst 
b/doc/reference/commands/traffic_via.en.rst
new file mode 100644
index 0000000..94a82fd
--- /dev/null
+++ b/doc/reference/commands/traffic_via.en.rst
@@ -0,0 +1,90 @@
+.. 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.
+
+.. _traffic_via:
+
+============
+traffic_via
+============
+
+Synopsis
+========
+
+:program:`traffic_via` [OPTIONS] [VIA ...]
+
+.. program:: traffic_via
+
+Description
+===========
+
+:program:`traffic_via` decodes the Traffic Server Via header codes.
+Via header strings are passed as command-line options. The enclosing
+square brackets are optional.
+
+If the argument is '-', :program:`traffic_via` will filter standard
+input for Via headers. This modes supports only supports Via headers
+taht are enclosed by square brackets.
+
+Options
+=======
+
+.. option:: -h, --help
+
+    Print usage information and exit.
+
+.. option:: -V, --version
+
+    Print version.
+
+Examples
+========
+
+Decode the Via header from command-line arguments::
+
+    $ traffic_via "[uScMsEf p eC:t cCMi p sF]"
+    Via header is uScMsEf p eC:t cCMi p sF, Length is 24
+    Via Header Details:
+    Request headers received from client                   :simple request 
(not conditional)
+    Result of Traffic Server cache lookup for URL          :miss (a cache 
"MISS")
+    Response information received from origin server       :error in response
+    Result of document write-to-cache:                     :no cache write 
performed
+    Proxy operation result                                 :unknown
+    Error codes (if any)                                   :connection to 
server failed
+    Tunnel info                                            :no tunneling
+    Cache Type                                             :cache
+    Cache Lookup Result                                    :cache miss (url 
not in cache)
+    ICP status                                             :no icp
+    Parent proxy connection status                         :no parent proxy or 
unknown
+    Origin server connection status                        :connection open 
failed
+
+Decode the Via header from a curl request, using the :ref:`X-Debug 
<_xdebug_plugin>` plugin::
+
+    $ curl -H  "X-Debug: Via" -I http://test.example.com | traffic_via -
+    Via header is uScMsSf pSeN:t cCMi p sS, Length is 24
+    Via Header Details:
+    Request headers received from client                   :simple request 
(not conditional)
+    Result of Traffic Server cache lookup for URL          :miss (a cache 
"MISS")
+    Response information received from origin server       :connection opened 
successfully
+    Result of document write-to-cache:                     :no cache write 
performed
+    Proxy operation result                                 :served or 
connection opened successfully
+    Error codes (if any)                                   :no error
+    Tunnel info                                            :no tunneling
+    Cache Type                                             :cache
+    Cache Lookup Result                                    :cache miss (url 
not in cache)
+    ICP status                                             :no icp
+    Parent proxy connection status                         :no parent proxy or 
unknown
+    Origin server connection status                        :connection opened 
successfully

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/63757db5/lib/ts/ink_args.cc
----------------------------------------------------------------------
diff --git a/lib/ts/ink_args.cc b/lib/ts/ink_args.cc
index 97f5f1b..cf2caf0 100644
--- a/lib/ts/ink_args.cc
+++ b/lib/ts/ink_args.cc
@@ -63,6 +63,16 @@ arg_is_version_flag(const ArgumentDescription * arg)
 }
 
 static void
+append_file_argument(const char * arg)
+{
+    if (n_file_arguments >= countof(file_arguments)) {
+      ink_fatal(1, "too many files");
+    }
+    file_arguments[n_file_arguments++] = arg;
+    file_arguments[n_file_arguments] = NULL;
+}
+
+static void
 process_arg(const AppVersionInfo * appinfo, const ArgumentDescription * 
argument_descriptions,
             unsigned n_argument_descriptions, int i, char ***argv, const char 
*usage_string)
 {
@@ -193,22 +203,27 @@ process_args(const AppVersionInfo * appinfo, const 
ArgumentDescription * argumen
         if (i >= n_argument_descriptions)
           usage(argument_descriptions, n_argument_descriptions, usage_string);
       } else {
-        while (*++(*argv))
-          for (i = 0; i < n_argument_descriptions; i++)
+        // Hack for supporting '-' as a file argument.
+        if (strcmp(*argv, "-") == 0) {
+          append_file_argument(*argv);
+        }
+
+        while (*++(*argv)) {
+          for (i = 0; i < n_argument_descriptions; i++) {
+            printf("i=%d **argv=%c\n", i, **argv);
             if (argument_descriptions[i].key == **argv) {
               process_arg(appinfo, argument_descriptions, 
n_argument_descriptions, i, &argv, usage_string);
               break;
             }
-        if (i >= n_argument_descriptions) {
-          usage(argument_descriptions, n_argument_descriptions, usage_string);
+          }
+
+          if (i >= n_argument_descriptions) {
+            usage(argument_descriptions, n_argument_descriptions, 
usage_string);
+          }
         }
       }
     } else {
-      if (n_file_arguments >= countof(file_arguments)) {
-        ink_fatal(1, "too many files");
-      }
-      file_arguments[n_file_arguments++] = *argv;
-      file_arguments[n_file_arguments] = NULL;
+      append_file_argument(*argv);
     }
   }
 }

Reply via email to