trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a..@apache.org
Subject [trafficserver] branch master updated: Via: Enable detail level in VIA protocol stack.
Date Thu, 01 Jun 2017 21:14:51 GMT
This is an automated email from the ASF dual-hosted git repository.

amc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

The following commit(s) were added to refs/heads/master by this push:
       new  68022cc   Via: Enable detail level in VIA protocol stack.
68022cc is described below

commit 68022cc31af1d0451802e50206be3b9349390503
Author: Alan M. Carroll <amc@apache.org>
AuthorDate: Thu May 25 22:41:32 2017 -0500

    Via: Enable detail level in VIA protocol stack.
---
 doc/admin-guide/files/records.config.en.rst        |  49 +++++++
 .../api/functions/TSClientProtocolStack.en.rst     |   2 +
 lib/records/I_RecCore.h                            |   1 +
 lib/records/RecCore.cc                             |  19 +++
 lib/ts/apidefs.h.in                                |   9 ++
 mgmt/RecordsConfig.cc                              |   9 +-
 plugins/experimental/ts_lua/ts_lua_http_config.c   |   4 +
 proxy/InkAPI.cc                                    |  28 ++++
 proxy/InkAPITest.cc                                |   2 +
 proxy/http/HttpConfig.cc                           | 141 +++++++++++++++++++--
 proxy/http/HttpConfig.h                            |  25 ++++
 proxy/http/HttpProxyAPIEnums.h                     |  27 ++++
 proxy/http/HttpServerSession.h                     |  14 ++
 proxy/http/HttpTransactHeaders.cc                  |  88 ++++++++++---
 tests/gold_tests/headers/via-compact.gold          |   4 +
 .../headers/{via.test.py => via-compact.test.py}   |  16 ++-
 tests/gold_tests/headers/via.gold                  |   2 +
 tests/gold_tests/headers/via.test.py               |  28 +++-
 18 files changed, 428 insertions(+), 40 deletions(-)

diff --git a/doc/admin-guide/files/records.config.en.rst b/doc/admin-guide/files/records.config.en.rst
index efb3492..372fd46 100644
--- a/doc/admin-guide/files/records.config.en.rst
+++ b/doc/admin-guide/files/records.config.en.rst
@@ -867,6 +867,29 @@ ip-resolve
 
    Set the server and version string in the ``Via`` request header to the origin server which
is inserted when the value of :ts:cv:`proxy.config.http.insert_request_via_str` is not ``0``.
 Note that the actual default value is defined with ``"ApacheTrafficServer/" PACKAGE_VERSION``
in a C++ source code, and you must write such as ``ApacheTrafficServer/6.0.0`` if you really
set a value with the version in :file:`records.config` file. If you want to hide the version,
you can set this value [...]
 
+.. ts:cv:: CONFIG proxy.config.http.request_via_transport STRING compact
+   :reloadable:
+   :overridable:
+
+   The ``Via`` string set by |TS| on an upstream request to the origin server can contain
a
+   description of the transport protocols used by the user agent to
+   connect to |TS|. This configuration controls the level of detail for the ``Via`` string
placed in
+   the outbound request.
+
+   ======= =================================================================
+   Value   Effect
+   ======= =================================================================
+   None    No details about the transport protocol.
+   Compact Only the top level protocol plus a TLS indicator.
+   Full    The entire protocol stack of :ref:`protocol_tags <protocol_tags>`
+           as a dash separated list.
+   ======= =================================================================
+
+   The full protocol stack will be a list of :ref:`protocol tags <protocol_tags>` separated
by a '-' character. The set of tags will vary but not the number of white space separated
tokens in the ``Via`` header. The tags are ordered left to right from top most protocol to
lowest level protocol.
+
+   The compact form always starts with ``http``. If the connection is TLS an ``s`` is added.
The
+   HTTP version is a ``/`` followed by one of ``1.0``, ``1.1``, ``2``. E.g. ``http/1.1``
for just HTTP, or ``https/2`` for HTTP/2 over TLS.
+
 .. ts:cv:: CONFIG proxy.config.http.insert_response_via_str INT 0
    :reloadable:
    :overridable:
@@ -892,6 +915,32 @@ ip-resolve
 
    Set the server and version string in the ``Via`` response header to the client which is
inserted when the value of :ts:cv:`proxy.config.http.insert_response_via_str` is not ``0``.
 Note that the actual default value is defined with ``"ApacheTrafficServer/" PACKAGE_VERSION``
in a C++ source code, and you must write such as ``ApacheTrafficServer/6.0.0`` if you really
set a value with the version in :file:`records.config` file. If you want to hide the version,
you can set this value to ` [...]
 
+.. ts:cv:: CONFIG proxy.config.http.response_via_transport STRING compact
+   :reloadable:
+   :overridable:
+
+   The ``Via`` string set by |TS| in the response to the client can contain a description
of the
+   transport protocols used by |TS| to connect to the origin server. This configuration controls
+   the level of detail for the ``Via`` string placed in the response.
+
+   ======= =================================================================
+   Value   Effect
+   ======= =================================================================
+   None    No details about the transport protocol.
+   Compact Only the top level protocol plus a TLS indicator.
+   Full    The entire protocol stack of :ref:`protocol_tags <protocol_tags>`
+           as a dash separated list.
+   ======= =================================================================
+
+   The full protocol stack will be a list of :ref:`protocol tags <protocol_tags>` separated
by a '-'
+   character. The set of tags will vary but not the number of white space separated tokens
in the
+   ``Via`` header. The tags are ordered left to right from top most protocol to lowest level
+   protocol. Note this list may not have more detail even when set to ``Full`` if |TS| does
not
+   connect upstream (e.g., the request is a cache hit).
+
+   The compact form always starts with ``http``. If the connection is TLS an ``s`` is added.
The
+   HTTP version is a ``/`` followed by one of ``1.0``, ``1.1``, ``2``. E.g. ``http/1.1``
for just HTTP, or ``https/2`` for HTTP/2 over TLS.
+
 .. ts:cv:: CONFIG proxy.config.http.send_100_continue_response INT 0
    :reloadable:
 
diff --git a/doc/developer-guide/api/functions/TSClientProtocolStack.en.rst b/doc/developer-guide/api/functions/TSClientProtocolStack.en.rst
index d84ca03..d5953f1 100644
--- a/doc/developer-guide/api/functions/TSClientProtocolStack.en.rst
+++ b/doc/developer-guide/api/functions/TSClientProtocolStack.en.rst
@@ -77,6 +77,8 @@ matched with an anchor prefix search, as with debug tags. For instance if
:arg:`
 will match "tls/1.2" or "tls/1.3". This makes checking for TLS or IP more convenient. If
more precision
 is required the entire protocol stack can be retrieved and processed more thoroughly.
 
+.. _protocol_tags:
+
 The protocol tags defined by |TS|.
 
 =========== =========
diff --git a/lib/records/I_RecCore.h b/lib/records/I_RecCore.h
index da904c7..358ffd9 100644
--- a/lib/records/I_RecCore.h
+++ b/lib/records/I_RecCore.h
@@ -176,6 +176,7 @@ int RecGetRecordBool(const char *name, RecBool *rec_byte, bool lock =
true);
 typedef void (*RecLookupCallback)(const RecRecord *, void *);
 
 int RecLookupRecord(const char *name, RecLookupCallback callback, void *data, bool lock =
true);
+int RecLookupRecord(const char *name, std::function<void(const RecRecord *)> &&f,
bool lock = true);
 int RecLookupMatchingRecords(unsigned rec_type, const char *match, RecLookupCallback callback,
void *data, bool lock = true);
 
 int RecGetRecordType(const char *name, RecT *rec_type, bool lock = true);
diff --git a/lib/records/RecCore.cc b/lib/records/RecCore.cc
index ed8632e..4ef1652 100644
--- a/lib/records/RecCore.cc
+++ b/lib/records/RecCore.cc
@@ -484,6 +484,25 @@ RecLookupRecord(const char *name, void (*callback)(const RecRecord *,
void *), v
   return err;
 }
 
+namespace
+{
+// Shim to enable using functors for @c RecLookupRecord.
+// This function is passed to @c RecLookupRecord with a @a data argument that is a pointer
to the functor.
+// When this is called, cast @a data back to the functor and invoke it.
+void
+RecLookupRecordForward(const RecRecord *r, void *data)
+{
+  (*static_cast<std::function<void(const RecRecord *)> *>(data))(r);
+}
+}
+
+/// Overload that takes a functor.
+int
+RecLookupRecord(const char *name, std::function<void(const RecRecord *)> &&callback,
bool lock)
+{
+  return RecLookupRecord(name, &RecLookupRecordForward, &callback, lock);
+}
+
 int
 RecLookupMatchingRecords(unsigned rec_type, const char *match, void (*callback)(const RecRecord
*, void *), void *data, bool lock)
 {
diff --git a/lib/ts/apidefs.h.in b/lib/ts/apidefs.h.in
index ac0a802..6e2888e 100644
--- a/lib/ts/apidefs.h.in
+++ b/lib/ts/apidefs.h.in
@@ -567,6 +567,13 @@ typedef enum {
   TS_SERVER_SESSION_SHARING_POOL_GLOBAL,
   TS_SERVER_SESSION_SHARING_POOL_THREAD,
 } TSServerSessionSharingPoolType;
+
+/// The verbosity of the transport protocol stack in a VIA header.
+typedef enum {
+  TS_VIA_TRANSPORT_NONE = 0,
+  TS_VIA_TRANSPORT_COMPACT = 1,
+  TS_VIA_TRANSPORT_FULL = 2
+} TSViaTransportVerbosity;
 #endif
 
 /* librecords types */
@@ -751,6 +758,8 @@ typedef enum {
   TS_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_LANGUAGE_MISMATCH,
   TS_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_ENCODING_MISMATCH,
   TS_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_CHARSET_MISMATCH,
+  TS_CONFIG_HTTP_REQUEST_VIA_TRANSPORT,
+  TS_CONFIG_HTTP_RESPONSE_VIA_TRANSPORT,
   TS_CONFIG_LAST_ENTRY
 } TSOverridableConfigKey;
 
diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc
index 762029a..f7d331a 100644
--- a/mgmt/RecordsConfig.cc
+++ b/mgmt/RecordsConfig.cc
@@ -365,12 +365,17 @@ static const RecordElement RecordsConfig[] =
   //        # verbose via string
   //        #
   //        # 0 - no extra info added to string
-  //        # 1 - all extra information added
-  //        # 2 - some extra info added
+  //        # 1 - minimal information.
+  //        # 2 - more information
+  //        # 3 - maximum information.
   {RECT_CONFIG, "proxy.config.http.request_via_str", RECD_STRING, "ApacheTrafficServer/"
PACKAGE_VERSION, RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
   ,
   {RECT_CONFIG, "proxy.config.http.response_via_str", RECD_STRING, "ApacheTrafficServer/"
PACKAGE_VERSION, RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
   ,
+  {RECT_CONFIG, "proxy.config.http.request_via_transport", RECD_STRING, "compact", RECU_DYNAMIC,
RR_NULL, RECC_NULL, nullptr, RECA_NULL}
+  ,
+  {RECT_CONFIG, "proxy.config.http.response_via_transport", RECD_STRING, "compact", RECU_DYNAMIC,
RR_NULL, RECC_NULL, nullptr, RECA_NULL}
+  ,
   {RECT_CONFIG, "proxy.config.http.response_server_enabled", RECD_INT, "1", RECU_DYNAMIC,
RR_NULL, RECC_NULL, "[0-2]", RECA_NULL}
   ,
   {RECT_CONFIG, "proxy.config.http.response_server_str", RECD_STRING, "ATS/" PACKAGE_VERSION,
RECU_DYNAMIC, RR_NULL, RECC_NULL, ".*", RECA_NULL}
diff --git a/plugins/experimental/ts_lua/ts_lua_http_config.c b/plugins/experimental/ts_lua/ts_lua_http_config.c
index 00d1e04..36d0dcd 100644
--- a/plugins/experimental/ts_lua/ts_lua_http_config.c
+++ b/plugins/experimental/ts_lua/ts_lua_http_config.c
@@ -128,6 +128,8 @@ typedef enum {
   TS_LUA_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_LANGUAGE_MISMATCH    = TS_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_LANGUAGE_MISMATCH,
   TS_LUA_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_ENCODING_MISMATCH    = TS_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_ENCODING_MISMATCH,
   TS_LUA_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_CHARSET_MISMATCH     = TS_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_CHARSET_MISMATCH,
+  TS_LUA_CONFIG_HTTP_REQUEST_VIA_TRANSPORT                    = TS_CONFIG_HTTP_REQUEST_VIA_TRANSPORT,
+  TS_LUA_CONFIG_HTTP_RESPONSE_VIA_TRANSPORT                   = TS_CONFIG_HTTP_RESPONSE_VIA_TRANSPORT,
   TS_LUA_CONFIG_LAST_ENTRY                                    = TS_CONFIG_LAST_ENTRY,
 } TSLuaOverridableConfigKey;
 
@@ -248,6 +250,8 @@ ts_lua_var_item ts_lua_http_config_vars[] = {
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_LANGUAGE_MISMATCH),
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_ENCODING_MISMATCH),
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_CACHE_IGNORE_ACCEPT_CHARSET_MISMATCH),
+  TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_REQUEST_VIA_TRANSPORT),
+  TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_HTTP_RESPONSE_VIA_TRANSPORT),
   TS_LUA_MAKE_VAR_ITEM(TS_LUA_CONFIG_LAST_ENTRY),
 };
 
diff --git a/proxy/InkAPI.cc b/proxy/InkAPI.cc
index 33436b4..93ab100 100644
--- a/proxy/InkAPI.cc
+++ b/proxy/InkAPI.cc
@@ -7882,6 +7882,12 @@ _conf_to_memberp(TSOverridableConfigKey conf, OverridableHttpConfigParams
*overr
   case TS_CONFIG_HTTP_INSERT_RESPONSE_VIA_STR:
     ret = _memberp_to_generic(&overridableHttpConfig->insert_response_via_string,
typep);
     break;
+  case TS_CONFIG_HTTP_REQUEST_VIA_TRANSPORT:
+    ret = _memberp_to_generic(&overridableHttpConfig->request_via_transport, typep);
+    break;
+  case TS_CONFIG_HTTP_RESPONSE_VIA_TRANSPORT:
+    ret = _memberp_to_generic(&overridableHttpConfig->response_via_transport, typep);
+    break;
   case TS_CONFIG_HTTP_CACHE_HEURISTIC_MIN_LIFETIME:
     ret = _memberp_to_generic(&overridableHttpConfig->cache_heuristic_min_lifetime,
typep);
     break;
@@ -8210,6 +8216,9 @@ TSHttpTxnConfigFloatGet(TSHttpTxn txnp, TSOverridableConfigKey conf,
TSMgmtFloat
 TSReturnCode
 TSHttpTxnConfigStringSet(TSHttpTxn txnp, TSOverridableConfigKey conf, const char *value,
int length)
 {
+  extern MgmtByteEnumConversion ViaTransportVerbosityConversion;
+  RecEnumData data;
+
   sdk_assert(sdk_sanity_check_txn(txnp) == TS_SUCCESS);
 
   if (length == -1) {
@@ -8257,6 +8266,17 @@ TSHttpTxnConfigStringSet(TSHttpTxn txnp, TSOverridableConfigKey conf,
const char
     if (value && length > 0) {
       s->t_state.txn_conf->client_cert_filepath = const_cast<char *>(value);
     }
+  case TS_CONFIG_HTTP_RESPONSE_VIA_TRANSPORT:
+    data._s.setView(value, length);
+    if (ViaTransportVerbosityConversion(s->t_state.txn_conf->response_via_transport,
"proxy.config.http.response_via_tranport",
+                                        RECD_STRING, data)) {
+    }
+    break;
+  case TS_CONFIG_HTTP_REQUEST_VIA_TRANSPORT:
+    data._s.setView(value, length);
+    if (ViaTransportVerbosityConversion(s->t_state.txn_conf->request_via_transport,
"proxy.config.http.request_via_tranport",
+                                        RECD_STRING, data)) {
+    }
   default:
     return TS_ERROR;
     break;
@@ -8466,6 +8486,11 @@ TSHttpTxnConfigFind(const char *name, int length, TSOverridableConfigKey
*conf,
         cnf = TS_CONFIG_HTTP_DOC_IN_CACHE_SKIP_DNS;
       }
       break;
+    case 't':
+      if (!strncmp(name, "proxy.config.http.request_via_transport", length)) {
+        cnf = TS_CONFIG_HTTP_REQUEST_VIA_TRANSPORT;
+        typ = TS_RECORDDATATYPE_STRING;
+      }
     }
     break;
 
@@ -8506,6 +8531,9 @@ TSHttpTxnConfigFind(const char *name, int length, TSOverridableConfigKey
*conf,
     case 't':
       if (!strncmp(name, "proxy.config.http.keep_alive_enabled_out", length)) {
         cnf = TS_CONFIG_HTTP_KEEP_ALIVE_ENABLED_OUT;
+      } else if (!strncmp(name, "proxy.config.http.response_via_transport", length)) {
+        cnf = TS_CONFIG_HTTP_RESPONSE_VIA_TRANSPORT;
+        typ = TS_RECORDDATATYPE_STRING;
       }
       break;
     }
diff --git a/proxy/InkAPITest.cc b/proxy/InkAPITest.cc
index dcd246e..8d5d20f 100644
--- a/proxy/InkAPITest.cc
+++ b/proxy/InkAPITest.cc
@@ -7608,6 +7608,8 @@ const char *SDK_Overridable_Configs[TS_CONFIG_LAST_ENTRY] = {
   "proxy.config.http.cache.ignore_accept_language_mismatch",
   "proxy.config.http.cache.ignore_accept_encoding_mismatch",
   "proxy.config.http.cache.ignore_accept_charset_mismatch",
+  "proxy.config.http.request_via_transport",
+  "proxy.config.http.response_via_transport",
 };
 REGRESSION_TEST(SDK_API_OVERRIDABLE_CONFIGS)(RegressionTest *test, int /* atype ATS_UNUSED
*/, int *pstatus)
 {
diff --git a/proxy/http/HttpConfig.cc b/proxy/http/HttpConfig.cc
index 52b8674..dfe6d53 100644
--- a/proxy/http/HttpConfig.cc
+++ b/proxy/http/HttpConfig.cc
@@ -31,6 +31,8 @@
 #include "P_Net.h"
 #include "P_RecUtils.h"
 #include <records/I_RecHttp.h>
+#include <ts/MemView.h>
+#include <list>
 
 #define HttpEstablishStaticConfigStringAlloc(_ix, _n) \
   REC_EstablishStaticConfigStringAlloc(_ix, _n);      \
@@ -65,16 +67,18 @@ public:
 /// Data item for enumerated type config value.
 template <typename T> struct ConfigEnumPair {
   T _value;
-  const char *_key;
+  ts::StringView _key;
+
+  ConfigEnumPair(T v, char const *k) : _value(v), _key(k) {}
 };
 
 /// Convert a string to an enumeration value.
 /// @a n is the number of entries in the list.
 /// @return @c true if the string is found, @c false if not found.
 /// If found @a value is set to the corresponding value in @a list.
-template <typename T, unsigned N>
+template <typename E, unsigned N>
 static bool
-http_config_enum_search(const char *key, const ConfigEnumPair<T> (&list)[N], MgmtByte
&value)
+http_config_enum_search(ts::StringView key, const ConfigEnumPair<E> (&list)[N],
MgmtByte &value)
 {
   // We don't expect any of these lists to be more than 10 long, so a linear search is the
best choice.
   for (unsigned i = 0; i < N; ++i) {
@@ -86,6 +90,13 @@ http_config_enum_search(const char *key, const ConfigEnumPair<T>
(&list)[N], Mgm
   return false;
 }
 
+template <typename E, unsigned N>
+static bool
+http_config_enum_search(const char *key, const ConfigEnumPair<E> (&list)[N], MgmtByte
&value)
+{
+  return http_config_enum_search(ts::StringView(key), list, value);
+}
+
 /// Read a string from the configuration and convert it to an enumeration value.
 /// @a n is the number of entries in the list.
 /// @return @c true if the string is found, @c false if not found.
@@ -101,6 +112,100 @@ http_config_enum_read(const char *name, const ConfigEnumPair<T>
(&list)[N], Mgmt
   return false;
 }
 
+/** Create a functor that converts record data to a @c MgmtByte based on a set of enum pairs.
+    The functor takes a refernce to the byte and the record data and updates the byte if
valid.
+    @return @c true if the data was valid and @a b update. @c false otherwise.
+ */
+template <typename E, int N>
+MgmtByteEnumConversion
+CreateMgmtByteEnumConversion(const ConfigEnumPair<E> (&pairs)[N])
+{
+  return [pairs](MgmtByte &b, const char *name, RecDataT type, RecEnumData data) ->
bool {
+    MgmtByte value;
+    bool valid_p = false;
+    if (RECD_INT == type) {
+      value   = data._i;
+      valid_p = std::numeric_limits<E>::min() <= value && value <= std::numeric_limits<E>::max();
+      if (!valid_p)
+        Warning("Configuration update for '%s' failed - %d is not in [%d..%d]", name, static_cast<int>(data._i),
+                static_cast<int>(std::numeric_limits<E>::min()), static_cast<int>(std::numeric_limits<E>::max()));
+    } else if (RECD_STRING == type) {
+      valid_p = http_config_enum_search(data._s, pairs, value);
+      if (!valid_p) {
+        char buff[1024];
+        char *s     = buff;
+        char *limit = buff + sizeof(buff);
+        for (auto const &p : pairs) {
+          if (s + p._key.size() + 2 < limit) {
+            if (s != buff)
+              *s++ = ',';
+            memcpy(s, p._key.ptr(), p._key.size());
+            s += p._key.size();
+            *s = 0;
+          } else {
+            break; // out of space, give up.
+          }
+        }
+        Warning("Configuration update for '%s' failed - '%.*s' is not one of (%s)", name,
static_cast<int>(data._s.size()),
+                data._s.ptr(), buff);
+      }
+    } else {
+      Warning("Configuration update for '%s' failed - type %d - expected STRING or INT",
name, static_cast<int>(type));
+    }
+    if (valid_p)
+      b = value;
+    return valid_p;
+  };
+}
+
+// forward declare for the enum update.
+static int http_config_cb(const char *, RecDataT, RecData, void *);
+
+namespace
+{
+/// Type of function called from the generic HTTP config update callback.
+/// It validates the updated data and if valid, updates the data and returns @c true.
+using UpdateFunc = std::function<bool(const char *name, RecDataT type, RecData data)>;
+
+/** Establish an update callback for an enum value in the same manner as the base types.
+
+    This uses the generic update callback, passing it an update functor specialized for this
+    type. When the generic update (@c http_config_cb) is called it will be passed a pointer
to the
+    specialized update functor, which it will then invoke. If that succeeds, then the data
was valid
+    and the override member was updated just as for the base type callbacks.
+
+    A conversion functor must be supplied. See @c MgmtByteEnumConversion.
+ */
+void
+HttpEstablishStaticConfigEnumByte(MgmtByte &b, const char *name, MgmtByteEnumConversion
&convertor)
+{
+  // Memory management troubles. Because the callback system isn't really C++ it doesn't
handle
+  // cleaning up the callback data. That must be done here by stuffing the functor into a
list and
+  // letting the list destructor clean up. This is not strictly needed as these objects have
process
+  // lifetime and we could just "leak", but the ASAN guys will yell at me if I do that.
+  static std::list<UpdateFunc> f_list;
+
+  // Create the actual update function which updates the value in the master overide global.
+  f_list.emplace_front([&b, &convertor](const char *name, RecDataT type, RecData
data) -> bool {
+    return convertor(b, name, type, RecEnumData(type, data));
+  });
+  // Get a direct reference to it to capture in the initial update lambda.
+  UpdateFunc &f = *(f_list.begin());
+
+  // No standard config link because it's not a standard type.
+  // Just use the generic callback with the updater.
+  REC_RegisterConfigUpdateFunc(name, http_config_cb, &f);
+  // Need to do this the first time around to initialize. Find the record and whatever
+  // data it has and pass that as if it were an update.
+  RecLookupRecord(name, [&f](const RecRecord *r) -> void { f(r->name, r->data_type,
r->data); });
+}
+}
+
+////////////////////////////////////////////////////////////////
+//
+//  static variables
+//
+////////////////////////////////////////////////////////////////
 /// Session sharing match types.
 static const ConfigEnumPair<TSServerSessionSharingMatchType> SessionSharingMatchStrings[]
= {
   {TS_SERVER_SESSION_SHARING_MATCH_NONE, "none"},
@@ -112,17 +217,18 @@ static const ConfigEnumPair<TSServerSessionSharingPoolType> SessionSharingPoolSt
   {TS_SERVER_SESSION_SHARING_POOL_GLOBAL, "global"},
   {TS_SERVER_SESSION_SHARING_POOL_THREAD, "thread"}};
 
-////////////////////////////////////////////////////////////////
-//
-//  static variables
-//
-////////////////////////////////////////////////////////////////
+static const ConfigEnumPair<TSViaTransportVerbosity> ViaTransportVerbosityStrings[]
= {{TS_VIA_TRANSPORT_NONE, "none"},
+                                                                                       {TS_VIA_TRANSPORT_COMPACT,
"compact"},
+                                                                                       {TS_VIA_TRANSPORT_FULL,
"full"}};
+
 int HttpConfig::m_id = 0;
 HttpConfigParams HttpConfig::m_master;
 
 static volatile int http_config_changes = 1;
 static HttpConfigCont *http_config_cont = nullptr;
 
+MgmtByteEnumConversion ViaTransportVerbosityConversion{CreateMgmtByteEnumConversion(ViaTransportVerbosityStrings)};
+
 HttpConfigCont::HttpConfigCont() : Continuation(new_ProxyMutex())
 {
   SET_HANDLER(&HttpConfigCont::handle_event);
@@ -138,14 +244,22 @@ HttpConfigCont::handle_event(int /* event ATS_UNUSED */, void * /* edata
ATS_UNU
 }
 
 static int
-http_config_cb(const char * /* name ATS_UNUSED */, RecDataT /* data_type ATS_UNUSED */, RecData
/* data ATS_UNUSED */,
-               void * /* cookie ATS_UNUSED */)
+http_config_cb(const char *name, RecDataT data_type, RecData data, void *cookie)
 {
+  // A cookie means a specialized update function for this particular config value.
+  // Indirect through this because the config update logic only takes function pointers
+  // not generic functors. The update function verifies it's worth doing an update.
+  if (cookie) {
+    if (!((*static_cast<UpdateFunc *>(cookie))(name, data_type, data)))
+      return 0; // invalid data, don't update config.
+  }
+
   ink_atomic_increment((int *)&http_config_changes, 1);
 
   INK_MEMORY_BARRIER;
 
   eventProcessor.schedule_in(http_config_cont, HRTIME_SECONDS(1), ET_CALL);
+
   return 0;
 }
 
@@ -938,6 +1052,11 @@ HttpConfig::startup()
                         c.oride.server_session_sharing_match);
   http_config_enum_read("proxy.config.http.server_session_sharing.pool", SessionSharingPoolStrings,
c.server_session_sharing_pool);
 
+  HttpEstablishStaticConfigEnumByte(c.oride.request_via_transport, "proxy.config.http.request_via_transport",
+                                    ViaTransportVerbosityConversion);
+  HttpEstablishStaticConfigEnumByte(c.oride.response_via_transport, "proxy.config.http.response_via_transport",
+                                    ViaTransportVerbosityConversion);
+
   HttpEstablishStaticConfigByte(c.oride.auth_server_session_private, "proxy.config.http.auth_server_session_private");
 
   HttpEstablishStaticConfigByte(c.oride.keep_alive_post_out, "proxy.config.http.keep_alive_post_out");
@@ -1178,6 +1297,8 @@ HttpConfig::reconfigure()
 
   params->oride.insert_request_via_string   = m_master.oride.insert_request_via_string;
   params->oride.insert_response_via_string  = m_master.oride.insert_response_via_string;
+  params->oride.request_via_transport       = m_master.oride.request_via_transport;
+  params->oride.response_via_transport      = m_master.oride.response_via_transport;
   params->proxy_request_via_string          = ats_strdup(m_master.proxy_request_via_string);
   params->proxy_request_via_string_len      = (params->proxy_request_via_string) ?
strlen(params->proxy_request_via_string) : 0;
   params->proxy_response_via_string         = ats_strdup(m_master.proxy_response_via_string);
diff --git a/proxy/http/HttpConfig.h b/proxy/http/HttpConfig.h
index 303db6a..b52f831 100644
--- a/proxy/http/HttpConfig.h
+++ b/proxy/http/HttpConfig.h
@@ -47,6 +47,7 @@
 #include "HttpProxyAPIEnums.h"
 #include "ProxyConfig.h"
 #include "P_RecProcess.h"
+#include <functional>
 
 /* Instead of enumerating the stats in DynamicStats.h, each module needs
    to enumerate its stats separately and register them with librecords
@@ -554,6 +555,8 @@ struct OverridableHttpConfigParams {
 
   MgmtByte insert_request_via_string;
   MgmtByte insert_response_via_string;
+  MgmtByte request_via_transport  = TS_VIA_TRANSPORT_COMPACT; ///< Verbosity of the transport
via entry for a request.
+  MgmtByte response_via_transport = TS_VIA_TRANSPORT_COMPACT; ///< Verbosity of the transport
via entry for a response.
 
   //////////////////////
   //  DOC IN CACHE NO DNS//
@@ -888,4 +891,26 @@ inline HttpConfigParams::~HttpConfigParams()
     delete connect_ports;
   }
 }
+
+/// A variant of RecData that contains a StringView. This is necessary because the TS API
passes in configuration
+/// strings by pointer&length.
+union RecEnumData {
+  int _i;
+  ts::StringView _s;
+
+  RecEnumData() : _i(0) {}
+  RecEnumData(RecDataT t, RecData d)
+  {
+    if (t == RECD_INT)
+      _i = d.rec_int;
+    else if (t == RECD_STRING)
+      _s = ts::StringView{d.rec_string};
+    else
+      _i = 0;
+  }
+};
+/// Type of function called from the generic HTTP config update callback.
+/// It validates the updated data and if valid, updates the data and returns @c true.
+using MgmtByteEnumConversion = std::function<bool(MgmtByte &b, const char *name, RecDataT
type, RecEnumData data)>;
+
 #endif /* #ifndef _HttpConfig_h_ */
diff --git a/proxy/http/HttpProxyAPIEnums.h b/proxy/http/HttpProxyAPIEnums.h
index f8ff3b4..ab88b7b 100644
--- a/proxy/http/HttpProxyAPIEnums.h
+++ b/proxy/http/HttpProxyAPIEnums.h
@@ -30,6 +30,10 @@
 #ifndef _HTTP_PROXY_API_ENUMS_H_
 #define _HTTP_PROXY_API_ENUMS_H_
 
+#ifdef __cplusplus
+#include <limits>
+#endif
+
 /// Server session sharing values - match
 typedef enum {
   TS_SERVER_SESSION_SHARING_MATCH_NONE,
@@ -44,4 +48,27 @@ typedef enum {
   TS_SERVER_SESSION_SHARING_POOL_THREAD,
 } TSServerSessionSharingPoolType;
 
+/// The verbosity of the transport protocol stack in a VIA header.
+typedef enum { TS_VIA_TRANSPORT_NONE = 0, TS_VIA_TRANSPORT_COMPACT = 1, TS_VIA_TRANSPORT_FULL
= 2 } TSViaTransportVerbosity;
+
+#ifdef __cplusplus
+namespace std
+{
+template <> class numeric_limits<TSViaTransportVerbosity> : public numeric_limits<uint8_t>
+{
+public:
+  static TSViaTransportVerbosity
+  min()
+  {
+    return TS_VIA_TRANSPORT_NONE;
+  }
+  static TSViaTransportVerbosity
+  max()
+  {
+    return TS_VIA_TRANSPORT_FULL;
+  }
+};
+}
+#endif
+
 #endif // _HTTP_PROXY_API_ENUMS_H_
diff --git a/proxy/http/HttpServerSession.h b/proxy/http/HttpServerSession.h
index 5400d4e..f110ed3 100644
--- a/proxy/http/HttpServerSession.h
+++ b/proxy/http/HttpServerSession.h
@@ -180,6 +180,20 @@ public:
   //   an asyncronous cancel on NT
   MIOBuffer *read_buffer;
 
+  virtual int
+  populate_protocol(ts::StringView *result, int size) const
+  {
+    auto vc = this->get_netvc();
+    return vc ? vc->populate_protocol(result, size) : 0;
+  }
+
+  virtual const char *
+  protocol_contains(ts::StringView tag_prefix) const
+  {
+    auto vc = this->get_netvc();
+    return vc ? vc->protocol_contains(tag_prefix) : nullptr;
+  }
+
 private:
   HttpServerSession(HttpServerSession &);
 
diff --git a/proxy/http/HttpTransactHeaders.cc b/proxy/http/HttpTransactHeaders.cc
index 7bcf31f..3f7f583 100644
--- a/proxy/http/HttpTransactHeaders.cc
+++ b/proxy/http/HttpTransactHeaders.cc
@@ -683,26 +683,84 @@ HttpTransactHeaders::insert_server_header_in_response(const char *server_tag,
in
   }
 }
 
-/// Look up the protocol stack and write it to the @a via_string.
+/// write the protocol stack to the @a via_string.
 size_t
-write_client_protocol_stack(HttpTransact::State *s, char *via_string, size_t len)
+write_via_protocol_stack(char *via_string, size_t len, TSViaTransportVerbosity detail, ts::StringView
*proto_buf, int nproto)
 {
-  std::array<ts::StringView, 10> proto_buf; // 10 seems like a reasonable number of
protos to print
-  int retval        = s->state_machine->populate_client_protocol(proto_buf.data(),
proto_buf.size());
-  char *via         = via_string;
-  char *limit       = via_string + len;
-  ts::StringView *v = proto_buf.data();
-  for (int i = 0; i < retval && (via + v->size() + 1) < limit; ++i, ++v)
{
-    if (i) {
-      *via++ = '-';
+  char *via   = via_string; // keep original pointer for size computation later.
+  char *limit = via_string + len;
+  static constexpr ts::StringView tls_prefix{"tls/", ts::StringView::literal};
+
+  if (nproto <= 0 || via == nullptr || len <= 0) {
+    // nothing
+  } else if (detail == TS_VIA_TRANSPORT_FULL) {
+    ts::StringView *v = proto_buf;
+    for (int i = 0; i < nproto && (via + v->size() + 1) < limit; ++i, ++v)
{
+      if (i)
+        *via++ = '-';
+      memcpy(via, v->ptr(), v->size());
+      via += v->size();
+    }
+    *via++ = ' ';
+  } else if (detail == TS_VIA_TRANSPORT_COMPACT) {
+    ts::StringView *proto_end = proto_buf + nproto;
+    bool http_1_0_p           = std::find(proto_buf, proto_end, IP_PROTO_TAG_HTTP_1_0) !=
proto_end;
+    bool http_1_1_p           = std::find(proto_buf, proto_end, IP_PROTO_TAG_HTTP_1_1) !=
proto_end;
+
+    if ((http_1_0_p || http_1_1_p) && via + 10 < limit) {
+      bool tls_p = std::find_if(proto_buf, proto_end, [](ts::StringView tag) { return tls_prefix.isPrefixOf(tag);
}) != proto_end;
+      bool http_2_p = std::find(proto_buf, proto_end, IP_PROTO_TAG_HTTP_2_0) != proto_end;
+
+      memcpy(via, "http", 4);
+      via += 4;
+      if (tls_p)
+        *via++ = 's';
+      *via++   = '/';
+      if (http_2_p) {
+        *via++ = '2';
+      } else if (http_1_0_p) {
+        memcpy(via, "1.0", 3);
+        via += 3;
+      } else if (http_1_1_p) {
+        memcpy(via, "1.1", 3);
+        via += 3;
+      }
+      *via++ = ' ';
     }
-    memcpy(via, v->ptr(), v->size());
-    via += v->size();
   }
-  *via++ = ' ';
   return via - via_string;
 }
 
+/// Look up the protocol stack and write it to the @a via_string.
+size_t
+write_client_protocol_stack(char *via_string, size_t len, HttpTransact::State *s)
+{
+  std::array<ts::StringView, 10> proto_buf; // 10 seems like a reasonable number of
protos to print
+  int n = s->state_machine->populate_client_protocol(proto_buf.data(), proto_buf.size());
+  return write_via_protocol_stack(via_string, len, static_cast<TSViaTransportVerbosity>(s->txn_conf->request_via_transport),
+                                  proto_buf.data(), n);
+}
+
+/// Look up the protocol stack and write it to the @a via_string.
+size_t
+write_upstream_protocol_stack(char *via_string, size_t len, HttpTransact::State *s, HTTPHdr
*header)
+{
+  int n      = 0;
+  int offset = 0;                           // # of proto_buf slots reserved for protocol
data above the netvc
+  std::array<ts::StringView, 10> proto_buf; // 10 seems like a reasonable number of
protos to print
+
+  // Should suffice - if we're adding a VIA, it's HTTP and only 1.0 and 1.1 are supported
outbound.
+  proto_buf[offset] = HTTP_MINOR(header->version_get().m_version) == 0 ? IP_PROTO_TAG_HTTP_1_0
: IP_PROTO_TAG_HTTP_1_1;
+  ++offset;
+
+  auto ss = s->state_machine->get_server_session();
+  if (ss) {
+    n += ss->populate_protocol(proto_buf.data() + offset, proto_buf.size() - offset);
+  }
+  return write_via_protocol_stack(via_string, len, static_cast<TSViaTransportVerbosity>(s->txn_conf->response_via_transport),
+                                  proto_buf.data(), n + offset);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Name       : insert_via_header_in_request
 // Description: takes in existing via_string and inserts it in header
@@ -760,7 +818,7 @@ HttpTransactHeaders::insert_via_header_in_request(HttpTransact::State
*s, HTTPHd
 
   char *incoming_via = s->via_string;
 
-  via_string += write_client_protocol_stack(s, via_string, sizeof(new_via_string) - (via_string
- new_via_string));
+  via_string += write_client_protocol_stack(via_string, sizeof(new_via_string) - (via_string
- new_via_string), s);
   via_string += nstrcpy(via_string, s->http_config_param->proxy_hostname);
 
   *via_string++ = '[';
@@ -827,7 +885,7 @@ HttpTransactHeaders::insert_via_header_in_response(HttpTransact::State
*s, HTTPH
 
   char *incoming_via = s->via_string;
 
-  via_string += write_client_protocol_stack(s, via_string, sizeof(new_via_string) - (via_string
- new_via_string));
+  via_string += write_upstream_protocol_stack(via_string, sizeof(new_via_string) - (via_string
- new_via_string), s, header);
   via_string += nstrcpy(via_string, s->http_config_param->proxy_hostname);
   *via_string++ = ' ';
   *via_string++ = '(';
diff --git a/tests/gold_tests/headers/via-compact.gold b/tests/gold_tests/headers/via-compact.gold
new file mode 100644
index 0000000..cc5518b
--- /dev/null
+++ b/tests/gold_tests/headers/via-compact.gold
@@ -0,0 +1,4 @@
+Via: http/1.1
+Via: http/1.0
+Via: https/2
+Via: https/1.1
diff --git a/tests/gold_tests/headers/via.test.py b/tests/gold_tests/headers/via-compact.test.py
similarity index 81%
copy from tests/gold_tests/headers/via.test.py
copy to tests/gold_tests/headers/via-compact.test.py
index db70d79..c448789 100644
--- a/tests/gold_tests/headers/via.test.py
+++ b/tests/gold_tests/headers/via-compact.test.py
@@ -44,7 +44,8 @@ def RequireCurlFeature(tag):
   return False
 
 Test.SkipUnless(
-    Condition.Condition(lambda : RequireCurlFeature('http2'), "Via test requires a curl that
supports HTTP/2")
+    Condition.Condition(lambda : RequireCurlFeature('http2'), "Via test requires a curl that
supports HTTP/2"),
+    Condition.Condition(lambda : RequireCurlFeature('IPv6'), "Via test requires a curl that
supports IPv6")
     )
 Test.ContinueOnFail=True
 
@@ -67,9 +68,10 @@ ts.Variables.ssl_port = 4443
 ts.Disk.records_config.update({
         'proxy.config.http.insert_request_via_str' : 1,
         'proxy.config.http.insert_response_via_str' : 1,
+        'proxy.config.http.request_via_transport' : 'compact',
         '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': '{0} {1}:proto=http2;http:ssl'.format(ts.Variables.port,ts.Variables.ssl_port),
+        'proxy.config.http.server_ports': 'ipv4:{0} ipv4:{1}:proto=http2;http:ssl ipv6:{0}
ipv6:{1}:proto=http2;http:ssl'.format(ts.Variables.port,ts.Variables.ssl_port),
     })
 
 ts.Disk.remap_config.AddLine(
@@ -85,7 +87,7 @@ ts.Disk.ssl_multicert_config.AddLine(
 
 # Set up to check the output after the tests have run.
 via_log_id = Test.Disk.File("via.log")
-via_log_id.Content = "via.gold"
+via_log_id.Content = "via-compact.gold"
 
 # Ask the OS if the port is ready for connect()
 def CheckPort(Port) :
@@ -98,7 +100,7 @@ tr.Processes.Default.StartBefore(server, ready=CheckPort(server.Variables.Port))
 # Delay on readiness of our ssl ports
 tr.Processes.Default.StartBefore(Test.Processes.ts, ready=CheckPort(ts.Variables.ssl_port))
 
-tr.Processes.Default.Command='curl --verbose --http1.1 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
+tr.Processes.Default.Command='curl --verbose --ipv4 --http1.1 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
 tr.Processes.Default.ReturnCode=0
 
 tr.StillRunningAfter=server
@@ -106,7 +108,7 @@ tr.StillRunningAfter=ts
 
 # HTTP 1.0
 tr=Test.AddTestRun()
-tr.Processes.Default.Command='curl --verbose --http1.0 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
+tr.Processes.Default.Command='curl --verbose --ipv4 --http1.0 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
 tr.Processes.Default.ReturnCode=0
 
 tr.StillRunningAfter=server
@@ -114,7 +116,7 @@ tr.StillRunningAfter=ts
 
 # HTTP 2
 tr=Test.AddTestRun()
-tr.Processes.Default.Command='curl --verbose --insecure --header "Host: www.example.com"
https://localhost:{}'.format(ts.Variables.ssl_port)
+tr.Processes.Default.Command='curl --verbose --ipv4 --insecure --header "Host: www.example.com"
https://localhost:{}'.format(ts.Variables.ssl_port)
 tr.Processes.Default.ReturnCode=0
 
 tr.StillRunningAfter=server
@@ -122,7 +124,7 @@ tr.StillRunningAfter=ts
 
 # TLS
 tr=Test.AddTestRun()
-tr.Processes.Default.Command='curl --verbose --http1.1 --insecure --header "Host: www.example.com"
https://localhost:{}'.format(ts.Variables.ssl_port)
+tr.Processes.Default.Command='curl --verbose --ipv4 --http1.1 --insecure --header "Host:
www.example.com" https://localhost:{}'.format(ts.Variables.ssl_port)
 tr.Processes.Default.ReturnCode=0
 
 tr.StillRunningAfter=server
diff --git a/tests/gold_tests/headers/via.gold b/tests/gold_tests/headers/via.gold
index c2eadda..9f12e56 100644
--- a/tests/gold_tests/headers/via.gold
+++ b/tests/gold_tests/headers/via.gold
@@ -2,3 +2,5 @@ Via: http/1.1-tcp-ipv4
 Via: http/1.0-tcp-ipv4
 Via: http/1.1-h2-tls/1.2-tcp-ipv4
 Via: http/1.1-tls/1.2-tcp-ipv4
+Via: http/1.1-tcp-ipv6
+Via: http/1.1-tls/1.2-tcp-ipv6
diff --git a/tests/gold_tests/headers/via.test.py b/tests/gold_tests/headers/via.test.py
index db70d79..00eef1f 100644
--- a/tests/gold_tests/headers/via.test.py
+++ b/tests/gold_tests/headers/via.test.py
@@ -44,7 +44,8 @@ def RequireCurlFeature(tag):
   return False
 
 Test.SkipUnless(
-    Condition.Condition(lambda : RequireCurlFeature('http2'), "Via test requires a curl that
supports HTTP/2")
+    Condition.Condition(lambda : RequireCurlFeature('http2'), "Via test requires a curl that
supports HTTP/2"),
+    Condition.Condition(lambda : RequireCurlFeature('IPv6'), "Via test requires a curl that
supports IPv6")
     )
 Test.ContinueOnFail=True
 
@@ -67,9 +68,10 @@ ts.Variables.ssl_port = 4443
 ts.Disk.records_config.update({
         'proxy.config.http.insert_request_via_str' : 1,
         'proxy.config.http.insert_response_via_str' : 1,
+        'proxy.config.http.request_via_transport' : 'full',
         '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': '{0} {1}:proto=http2;http:ssl'.format(ts.Variables.port,ts.Variables.ssl_port),
+        'proxy.config.http.server_ports': 'ipv4:{0} ipv4:{1}:proto=http2;http:ssl ipv6:{0}
ipv6:{1}:proto=http2;http:ssl'.format(ts.Variables.port,ts.Variables.ssl_port),
     })
 
 ts.Disk.remap_config.AddLine(
@@ -98,7 +100,7 @@ tr.Processes.Default.StartBefore(server, ready=CheckPort(server.Variables.Port))
 # Delay on readiness of our ssl ports
 tr.Processes.Default.StartBefore(Test.Processes.ts, ready=CheckPort(ts.Variables.ssl_port))
 
-tr.Processes.Default.Command='curl --verbose --http1.1 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
+tr.Processes.Default.Command='curl --verbose --ipv4 --http1.1 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
 tr.Processes.Default.ReturnCode=0
 
 tr.StillRunningAfter=server
@@ -106,7 +108,7 @@ tr.StillRunningAfter=ts
 
 # HTTP 1.0
 tr=Test.AddTestRun()
-tr.Processes.Default.Command='curl --verbose --http1.0 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
+tr.Processes.Default.Command='curl --verbose --ipv4 --http1.0 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
 tr.Processes.Default.ReturnCode=0
 
 tr.StillRunningAfter=server
@@ -114,7 +116,7 @@ tr.StillRunningAfter=ts
 
 # HTTP 2
 tr=Test.AddTestRun()
-tr.Processes.Default.Command='curl --verbose --insecure --header "Host: www.example.com"
https://localhost:{}'.format(ts.Variables.ssl_port)
+tr.Processes.Default.Command='curl --verbose --ipv4 --insecure --header "Host: www.example.com"
https://localhost:{}'.format(ts.Variables.ssl_port)
 tr.Processes.Default.ReturnCode=0
 
 tr.StillRunningAfter=server
@@ -122,7 +124,21 @@ tr.StillRunningAfter=ts
 
 # TLS
 tr=Test.AddTestRun()
-tr.Processes.Default.Command='curl --verbose --http1.1 --insecure --header "Host: www.example.com"
https://localhost:{}'.format(ts.Variables.ssl_port)
+tr.Processes.Default.Command='curl --verbose --ipv4 --http1.1 --insecure --header "Host:
www.example.com" https://localhost:{}'.format(ts.Variables.ssl_port)
+tr.Processes.Default.ReturnCode=0
+
+tr.StillRunningAfter=server
+tr.StillRunningAfter=ts
+
+# IPv6
+tr=Test.AddTestRun()
+tr.Processes.Default.Command='curl --verbose --ipv6 --http1.1 --proxy localhost:{} http://www.example.com'.format(ts.Variables.port)
+tr.Processes.Default.ReturnCode=0
+tr.StillRunningAfter=server
+tr.StillRunningAfter=ts
+
+tr=Test.AddTestRun()
+tr.Processes.Default.Command='curl --verbose --ipv6 --http1.1 --insecure --header "Host:
www.example.com" https://localhost:{}'.format(ts.Variables.ssl_port)
 tr.Processes.Default.ReturnCode=0
 
 tr.StillRunningAfter=server

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <commits@trafficserver.apache.org>'].

Mime
View raw message