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 2020/06/23 20:31:36 UTC

[trafficserver] branch 9.0.x updated (40135f7 -> eecc5d2)

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

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


    from 40135f7  Disable lua_stats autest until we can reliably wait for stats
     new 629c72f  Charge Proxy Header Regression tests into Catch unit tests.
     new eecc5d2  We should remove whitespace from fieldname in http response due to RFC7230:3.2.4(#6793)

The 2 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:
 .gitignore                             |    1 +
 include/tscore/Regression.h            |    2 -
 proxy/hdrs/HTTP.cc                     |   12 +-
 proxy/hdrs/HdrTest.cc                  | 2191 --------------------------------
 proxy/hdrs/HdrTest.h                   |   77 --
 proxy/hdrs/MIME.cc                     |    9 +-
 proxy/hdrs/MIME.h                      |    9 +-
 proxy/hdrs/Makefile.am                 |    6 -
 proxy/hdrs/unit_tests/test_HdrUtils.cc |    6 +-
 proxy/hdrs/unit_tests/test_Hdrs.cc     | 1920 +++++++++++++++++++++++++++-
 src/traffic_server/InkAPI.cc           |    3 +-
 src/traffic_server/traffic_server.cc   |   15 -
 12 files changed, 1943 insertions(+), 2308 deletions(-)
 delete mode 100644 proxy/hdrs/HdrTest.cc
 delete mode 100644 proxy/hdrs/HdrTest.h


[trafficserver] 02/02: We should remove whitespace from fieldname in http response due to RFC7230:3.2.4(#6793)

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

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

commit eecc5d271795a006d00af074eadb931e18c53622
Author: yangjian <ga...@hotmail.com>
AuthorDate: Fri May 15 16:49:32 2020 +0800

    We should remove whitespace from fieldname in http response due to RFC7230:3.2.4(#6793)
    
    (cherry picked from commit b13e348778845dd9aa08bd0fd872190897c8c0f7)
---
 proxy/hdrs/HTTP.cc                     | 12 ++++++------
 proxy/hdrs/MIME.cc                     |  9 +++++++--
 proxy/hdrs/MIME.h                      |  9 +++++----
 proxy/hdrs/unit_tests/test_HdrUtils.cc |  6 +++---
 proxy/hdrs/unit_tests/test_Hdrs.cc     |  2 +-
 src/traffic_server/InkAPI.cc           |  3 ++-
 6 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/proxy/hdrs/HTTP.cc b/proxy/hdrs/HTTP.cc
index 7f0dc82..c557172 100644
--- a/proxy/hdrs/HTTP.cc
+++ b/proxy/hdrs/HTTP.cc
@@ -959,8 +959,8 @@ http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const
         return PARSE_RESULT_ERROR;
       }
 
-      ParseResult ret =
-        mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, max_hdr_field_size);
+      ParseResult ret = mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof,
+                                          false, max_hdr_field_size);
       // If we're done with the main parse do some validation
       if (ret == PARSE_RESULT_DONE) {
         ret = validate_hdr_host(hh); // check HOST header
@@ -1116,8 +1116,8 @@ http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const
     parser->m_parsing_http = false;
   }
 
-  ParseResult ret =
-    mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, max_hdr_field_size);
+  ParseResult ret = mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, false,
+                                      max_hdr_field_size);
   // If we're done with the main parse do some validation
   if (ret == PARSE_RESULT_DONE) {
     ret = validate_hdr_host(hh); // check HOST header
@@ -1287,7 +1287,7 @@ http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const
 
       end                    = real_end;
       parser->m_parsing_http = false;
-      return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
+      return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, true);
     }
 #endif
 
@@ -1403,7 +1403,7 @@ http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const
     parser->m_parsing_http = false;
   }
 
-  return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
+  return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof, true);
 }
 
 /*-------------------------------------------------------------------------
diff --git a/proxy/hdrs/MIME.cc b/proxy/hdrs/MIME.cc
index a3024dc..db3cdd7 100644
--- a/proxy/hdrs/MIME.cc
+++ b/proxy/hdrs/MIME.cc
@@ -2512,7 +2512,7 @@ mime_parser_clear(MIMEParser *parser)
 
 ParseResult
 mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char **real_s, const char *real_e,
-                  bool must_copy_strings, bool eof, size_t max_hdr_field_size)
+                  bool must_copy_strings, bool eof, bool remove_ws_from_field_name, size_t max_hdr_field_size)
 {
   ParseResult err;
   bool line_is_real;
@@ -2572,8 +2572,13 @@ mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char
     // server MUST reject any received request message that contains
     // whitespace between a header field-name and colon with a response code
     // of 400 (Bad Request).
+    // A proxy MUST remove any such whitespace from a response message before
+    // fowarding the message downstream.
     if (is_ws(field_name.back())) {
-      return PARSE_RESULT_ERROR;
+      if (!remove_ws_from_field_name) {
+        return PARSE_RESULT_ERROR;
+      }
+      field_name.rtrim_if(&ParseRules::is_ws);
     }
 
     // find value first
diff --git a/proxy/hdrs/MIME.h b/proxy/hdrs/MIME.h
index a1e9dbc..b15d665 100644
--- a/proxy/hdrs/MIME.h
+++ b/proxy/hdrs/MIME.h
@@ -761,7 +761,7 @@ void mime_field_value_append(HdrHeap *heap, MIMEHdrImpl *mh, MIMEField *field, c
 void mime_parser_init(MIMEParser *parser);
 void mime_parser_clear(MIMEParser *parser);
 ParseResult mime_parser_parse(MIMEParser *parser, HdrHeap *heap, MIMEHdrImpl *mh, const char **real_s, const char *real_e,
-                              bool must_copy_strings, bool eof, size_t max_hdr_field_size = 131070);
+                              bool must_copy_strings, bool eof, bool remove_ws_from_field_name, size_t max_hdr_field_size = 131070);
 
 void mime_hdr_describe(HdrHeapObjImpl *raw, bool recurse);
 void mime_field_block_describe(HdrHeapObjImpl *raw, bool recurse);
@@ -1017,7 +1017,7 @@ public:
 
   int print(char *buf, int bufsize, int *bufindex, int *chars_to_skip);
 
-  int parse(MIMEParser *parser, const char **start, const char *end, bool must_copy_strs, bool eof,
+  int parse(MIMEParser *parser, const char **start, const char *end, bool must_copy_strs, bool eof, bool remove_ws_from_field_name,
             size_t max_hdr_field_size = UINT16_MAX);
 
   int value_get_index(const char *name, int name_length, const char *value, int value_length) const;
@@ -1299,7 +1299,8 @@ MIMEHdr::print(char *buf, int bufsize, int *bufindex, int *chars_to_skip)
   -------------------------------------------------------------------------*/
 
 inline int
-MIMEHdr::parse(MIMEParser *parser, const char **start, const char *end, bool must_copy_strs, bool eof, size_t max_hdr_field_size)
+MIMEHdr::parse(MIMEParser *parser, const char **start, const char *end, bool must_copy_strs, bool eof,
+               bool remove_ws_from_field_name, size_t max_hdr_field_size)
 {
   if (!m_heap)
     m_heap = new_HdrHeap();
@@ -1307,7 +1308,7 @@ MIMEHdr::parse(MIMEParser *parser, const char **start, const char *end, bool mus
   if (!m_mime)
     m_mime = mime_hdr_create(m_heap);
 
-  return mime_parser_parse(parser, m_heap, m_mime, start, end, must_copy_strs, eof, max_hdr_field_size);
+  return mime_parser_parse(parser, m_heap, m_mime, start, end, must_copy_strs, eof, remove_ws_from_field_name, max_hdr_field_size);
 }
 
 /*-------------------------------------------------------------------------
diff --git a/proxy/hdrs/unit_tests/test_HdrUtils.cc b/proxy/hdrs/unit_tests/test_HdrUtils.cc
index 50cca3a..b86b349 100644
--- a/proxy/hdrs/unit_tests/test_HdrUtils.cc
+++ b/proxy/hdrs/unit_tests/test_HdrUtils.cc
@@ -56,7 +56,7 @@ TEST_CASE("HdrUtils", "[proxy][hdrutils]")
   mime.create(heap);
   mime_parser_init(&parser);
 
-  auto result = mime_parser_parse(&parser, heap, mime.m_mime, &real_s, real_e, false, true);
+  auto result = mime_parser_parse(&parser, heap, mime.m_mime, &real_s, real_e, false, true, false);
   REQUIRE(PARSE_RESULT_DONE == result);
 
   HdrCsvIter iter;
@@ -143,7 +143,7 @@ TEST_CASE("HdrUtils 2", "[proxy][hdrutils]")
 
   mime.create(heap);
   mime_parser_init(&parser);
-  auto result = mime_parser_parse(&parser, heap, mime.m_mime, &real_s, real_e, false, true);
+  auto result = mime_parser_parse(&parser, heap, mime.m_mime, &real_s, real_e, false, true, false);
   REQUIRE(PARSE_RESULT_DONE == result);
 
   MIMEField *field{mime.field_find(connection_tag.data(), int(connection_tag.size()))};
@@ -185,7 +185,7 @@ TEST_CASE("HdrUtils 3", "[proxy][hdrutils]")
 
   mime.create(heap);
   mime_parser_init(&parser);
-  auto result = mime_parser_parse(&parser, heap, mime.m_mime, &real_s, real_e, false, true);
+  auto result = mime_parser_parse(&parser, heap, mime.m_mime, &real_s, real_e, false, true, false);
   REQUIRE(PARSE_RESULT_DONE == result);
 
   MIMEField *field{mime.field_find(connection_tag.data(), int(connection_tag.size()))};
diff --git a/proxy/hdrs/unit_tests/test_Hdrs.cc b/proxy/hdrs/unit_tests/test_Hdrs.cc
index dcbbd83..20ecfa8 100644
--- a/proxy/hdrs/unit_tests/test_Hdrs.cc
+++ b/proxy/hdrs/unit_tests/test_Hdrs.cc
@@ -861,7 +861,7 @@ TEST_CASE("HdrTest", "[proxy][hdrtest]")
     bool must_copy_strs = false;
 
     hdr.create(nullptr);
-    err = hdr.parse(&parser, &start, end, must_copy_strs, false);
+    err = hdr.parse(&parser, &start, end, must_copy_strs, false, false);
 
     REQUIRE(err >= 0);
 
diff --git a/src/traffic_server/InkAPI.cc b/src/traffic_server/InkAPI.cc
index 6d8a56d..edbed0f 100644
--- a/src/traffic_server/InkAPI.cc
+++ b/src/traffic_server/InkAPI.cc
@@ -2739,7 +2739,8 @@ TSMimeHdrParse(TSMimeParser parser, TSMBuffer bufp, TSMLoc obj, const char **sta
 
   MIMEHdrImpl *mh = _hdr_mloc_to_mime_hdr_impl(obj);
 
-  return (TSParseResult)mime_parser_parse((MIMEParser *)parser, ((HdrHeapSDKHandle *)bufp)->m_heap, mh, start, end, false, false);
+  return (TSParseResult)mime_parser_parse((MIMEParser *)parser, ((HdrHeapSDKHandle *)bufp)->m_heap, mh, start, end, false, false,
+                                          false);
 }
 
 int


[trafficserver] 01/02: Charge Proxy Header Regression tests into Catch unit tests.

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

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

commit 629c72f08714730c9c3a4b93d7b5fa10f9f120ff
Author: Walter Karas <wk...@verizonmedia.com>
AuthorDate: Tue Mar 10 18:43:12 2020 -0500

    Charge Proxy Header Regression tests into Catch unit tests.
    
    (cherry picked from commit 4228868a365d9774740cd153ed107768239352d3)
---
 .gitignore                           |    1 +
 include/tscore/Regression.h          |    2 -
 proxy/hdrs/HdrTest.cc                | 2191 ----------------------------------
 proxy/hdrs/HdrTest.h                 |   77 --
 proxy/hdrs/Makefile.am               |    6 -
 proxy/hdrs/unit_tests/test_Hdrs.cc   | 1920 ++++++++++++++++++++++++++++-
 src/traffic_server/traffic_server.cc |   15 -
 7 files changed, 1920 insertions(+), 2292 deletions(-)

diff --git a/.gitignore b/.gitignore
index 20c2bfa..b9563ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -123,6 +123,7 @@ proxy/http3/test_libhttp3
 proxy/http3/test_qpack
 proxy/logging/test_LogUtils
 proxy/logging/test_LogUtils2
+proxy/logging/test_RolledLogDeleter
 
 plugins/header_rewrite/header_rewrite_test
 plugins/experimental/cookie_remap/test_cookiejar
diff --git a/include/tscore/Regression.h b/include/tscore/Regression.h
index e34a497..8ebbe8c 100644
--- a/include/tscore/Regression.h
+++ b/include/tscore/Regression.h
@@ -54,8 +54,6 @@
 #define REGRESSION_TEST_QUICK 1
 #define REGRESSION_TEST_NIGHTLY 2
 #define REGRESSION_TEST_EXTENDED 3
-// use only for testing TS error handling!
-#define REGRESSION_TEST_FATAL 4
 
 // regression options
 #define REGRESSION_OPT_EXCLUSIVE (1 << 0)
diff --git a/proxy/hdrs/HdrTest.cc b/proxy/hdrs/HdrTest.cc
deleted file mode 100644
index 4678416..0000000
--- a/proxy/hdrs/HdrTest.cc
+++ /dev/null
@@ -1,2191 +0,0 @@
-/** @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.
- */
-
-/****************************************************************************
-
-   HdrTest.cc
-
-   Description:
-       Unit test code for sanity checking the header system is functioning
-         properly
-
-
- ****************************************************************************/
-
-#include "tscore/ink_platform.h"
-#include "tscore/ink_memory.h"
-#include "tscore/ink_time.h"
-
-#include "tscore/Arena.h"
-#include "HTTP.h"
-#include "MIME.h"
-#include "tscore/Regex.h"
-#include "URL.h"
-#include "HttpCompat.h"
-
-#include "HdrTest.h"
-
-//////////////////////
-// Main Test Driver //
-//////////////////////
-
-int
-HdrTest::go(RegressionTest *t, int /* atype ATS_UNUSED */)
-{
-  HdrTest::rtest = t;
-  int status     = 1;
-
-  hdrtoken_init();
-  url_init();
-  mime_init();
-  http_init();
-
-  status = status & test_http_hdr_print_and_copy();
-  status = status & test_comma_vals();
-  status = status & test_parse_comma_list();
-  status = status & test_set_comma_vals();
-  status = status & test_delete_comma_vals();
-  status = status & test_extend_comma_vals();
-  status = status & test_insert_comma_vals();
-  status = status & test_accept_language_match();
-  status = status & test_accept_charset_match();
-  status = status & test_parse_date();
-  status = status & test_format_date();
-  status = status & test_url();
-  status = status & test_arena();
-  status = status & test_regex();
-  status = status & test_http_mutation();
-  status = status & test_mime();
-  status = status & test_http();
-
-  return (status ? REGRESSION_TEST_PASSED : REGRESSION_TEST_FAILED);
-}
-
-////////////////////////////////////////////////////////////
-// Individual Tests --- return 1 on success, 0 on failure //
-////////////////////////////////////////////////////////////
-
-int
-HdrTest::test_parse_date()
-{
-  static struct {
-    const char *fast;
-    const char *slow;
-  } dates[] = {
-    {"Sun, 06 Nov 1994 08:49:37 GMT", "Sunday, 06-Nov-1994 08:49:37 GMT"},
-    {"Mon, 07 Nov 1994 08:49:37 GMT", "Monday, 07-Nov-1994 08:49:37 GMT"},
-    {"Tue, 08 Nov 1994 08:49:37 GMT", "Tuesday, 08-Nov-1994 08:49:37 GMT"},
-    {"Wed, 09 Nov 1994 08:49:37 GMT", "Wednesday, 09-Nov-1994 08:49:37 GMT"},
-    {"Thu, 10 Nov 1994 08:49:37 GMT", "Thursday, 10-Nov-1994 08:49:37 GMT"},
-    {"Fri, 11 Nov 1994 08:49:37 GMT", "Friday, 11-Nov-1994 08:49:37 GMT"},
-    {"Sat, 11 Nov 1994 08:49:37 GMT", "Saturday, 11-Nov-1994 08:49:37 GMT"},
-    {"Sun, 03 Jan 1999 08:49:37 GMT", "Sunday, 03-Jan-1999 08:49:37 GMT"},
-    {"Sun, 07 Feb 1999 08:49:37 GMT", "Sunday, 07-Feb-1999 08:49:37 GMT"},
-    {"Sun, 07 Mar 1999 08:49:37 GMT", "Sunday, 07-Mar-1999 08:49:37 GMT"},
-    {"Sun, 04 Apr 1999 08:49:37 GMT", "Sunday, 04-Apr-1999 08:49:37 GMT"},
-    {"Sun, 02 May 1999 08:49:37 GMT", "Sunday, 02-May-1999 08:49:37 GMT"},
-    {"Sun, 06 Jun 1999 08:49:37 GMT", "Sunday, 06-Jun-1999 08:49:37 GMT"},
-    {"Sun, 04 Jul 1999 08:49:37 GMT", "Sunday, 04-Jul-1999 08:49:37 GMT"},
-    {"Sun, 01 Aug 1999 08:49:37 GMT", "Sunday, 01-Aug-1999 08:49:37 GMT"},
-    {"Sun, 05 Sep 1999 08:49:37 GMT", "Sunday, 05-Sep-1999 08:49:37 GMT"},
-    {"Sun, 03 Oct 1999 08:49:37 GMT", "Sunday, 03-Oct-1999 08:49:37 GMT"},
-    {"Sun, 07 Nov 1999 08:49:37 GMT", "Sunday, 07-Nov-1999 08:49:37 GMT"},
-    {"Sun, 05 Dec 1999 08:49:37 GMT", "Sunday, 05-Dec-1999 08:49:37 GMT"},
-    {nullptr, nullptr},
-  };
-
-  int i;
-  int failures = 0;
-  time_t fast_t, slow_t;
-
-  bri_box("test_parse_date");
-
-  for (i = 0; dates[i].fast; i++) {
-    fast_t = mime_parse_date(dates[i].fast, dates[i].fast + static_cast<int>(strlen(dates[i].fast)));
-    slow_t = mime_parse_date(dates[i].slow, dates[i].slow + static_cast<int>(strlen(dates[i].slow)));
-    // compare with strptime here!
-    if (fast_t != slow_t) {
-      printf("FAILED: date %lu (%s) != %lu (%s)\n", static_cast<unsigned long>(fast_t), dates[i].fast,
-             static_cast<unsigned long>(slow_t), dates[i].slow);
-      ++failures;
-    }
-  }
-
-  return (failures_to_status("test_parse_date", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_format_date()
-{
-  static const char *dates[] = {
-    "Sun, 06 Nov 1994 08:49:37 GMT",
-    "Sun, 03 Jan 1999 08:49:37 GMT",
-    "Sun, 05 Dec 1999 08:49:37 GMT",
-    "Tue, 25 Apr 2000 20:29:53 GMT",
-    nullptr,
-  };
-
-  bri_box("test_format_date");
-
-  // (1) Test a few hand-created dates
-
-  int i;
-  time_t t, t2, t3;
-  char buffer[128], buffer2[128];
-  static const char *envstr = "TZ=GMT0";
-  int failures              = 0;
-
-  // shift into GMT timezone for cftime conversions
-  putenv(const_cast<char *>(envstr));
-  tzset();
-
-  for (i = 0; dates[i]; i++) {
-    t = mime_parse_date(dates[i], dates[i] + static_cast<int>(strlen(dates[i])));
-
-    cftime_replacement(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", &t);
-    if (memcmp(dates[i], buffer, 29) != 0) {
-      printf("FAILED: original date doesn't match cftime date\n");
-      printf("  input date:  %s\n", dates[i]);
-      printf("  cftime date: %s\n", buffer);
-      ++failures;
-    }
-
-    mime_format_date(buffer, t);
-    if (memcmp(dates[i], buffer, 29) != 0) {
-      printf("FAILED: original date doesn't match mime_format_date date\n");
-      printf("  input date:  %s\n", dates[i]);
-      printf("  cftime date: %s\n", buffer);
-      ++failures;
-    }
-  }
-
-  // (2) test a few times per day from 1/1/1970 to past 2010
-
-  // coverity[dont_call]
-  for (t = 0; t < 40 * 366 * (24 * 60 * 60); t += static_cast<int>(drand48() * (24 * 60 * 60))) {
-    cftime_replacement(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", &t);
-    t2 = mime_parse_date(buffer, buffer + static_cast<int>(strlen(buffer)));
-    if (t2 != t) {
-      printf("FAILED: parsed time_t doesn't match original time_t\n");
-      printf("  input time_t:  %d (%s)\n", static_cast<int>(t), buffer);
-      printf("  parsed time_t: %d\n", static_cast<int>(t2));
-      ++failures;
-    }
-    mime_format_date(buffer2, t);
-    if (memcmp(buffer, buffer2, 29) != 0) {
-      printf("FAILED: formatted date doesn't match original date\n");
-      printf("  original date:  %s\n", buffer);
-      printf("  formatted date: %s\n", buffer2);
-      ++failures;
-    }
-    t3 = mime_parse_date(buffer2, buffer2 + static_cast<int>(strlen(buffer2)));
-    if (t != t3) {
-      printf("FAILED: parsed time_t doesn't match original time_t\n");
-      printf("  input time_t:  %d (%s)\n", static_cast<int>(t), buffer2);
-      printf("  parsed time_t: %d\n", static_cast<int>(t3));
-      ++failures;
-    }
-
-    if (failures > 20) {
-      // Already too many failures, don't need to continue
-      break;
-    }
-  }
-
-  return (failures_to_status("test_format_date", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_url()
-{
-  static const char *strs[] = {
-    "http://some.place/path;params?query#fragment",
-
-    // Start with an easy one...
-    "http://trafficserver.apache.org/index.html",
-
-    "cheese://bogosity",
-
-    "some.place",
-    "some.place/",
-    "http://some.place",
-    "http://some.place/",
-    "http://some.place/path",
-    "http://some.place/path;params",
-    "http://some.place/path;params?query",
-    "http://some.place/path;params?query#fragment",
-    "http://some.place/path?query#fragment",
-    "http://some.place/path#fragment",
-
-    "some.place:80",
-    "some.place:80/",
-    "http://some.place:80",
-    "http://some.place:80/",
-
-    "foo@some.place:80",
-    "foo@some.place:80/",
-    "http://foo@some.place:80",
-    "http://foo@some.place:80/",
-
-    "foo:bar@some.place:80",
-    "foo:bar@some.place:80/",
-    "http://foo:bar@some.place:80",
-    "http://foo:bar@some.place:80/",
-
-    // Some address stuff
-    "http://172.16.28.101",
-    "http://172.16.28.101:8080",
-    "http://[::]",
-    "http://[::1]",
-    "http://[fc01:172:16:28::101]",
-    "http://[fc01:172:16:28::101]:80",
-    "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]",
-    "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080",
-    "http://172.16.28.101/some/path",
-    "http://172.16.28.101:8080/some/path",
-    "http://[::1]/some/path",
-    "http://[fc01:172:16:28::101]/some/path",
-    "http://[fc01:172:16:28::101]:80/some/path",
-    "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]/some/path",
-    "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080/some/path",
-    "http://172.16.28.101/",
-    "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080/",
-
-    // "foo:@some.place", TODO - foo:@some.place is change to foo@some.place in the test
-    "foo:bar@some.place",
-    "foo:bar@some.place/",
-    "http://foo:bar@some.place",
-    "http://foo:bar@some.place/",
-    "http://foo:bar@[::1]:8080/",
-    "http://foo@[::1]",
-
-    "mms://sm02.tsqa.example.com/0102rally.asf",
-    "pnm://foo:bar@some.place:80/path;params?query#fragment",
-    "rtsp://foo:bar@some.place:80/path;params?query#fragment",
-    "rtspu://foo:bar@some.place:80/path;params?query#fragment",
-    "/finance/external/cbsm/*http://cbs.marketwatch.com/archive/19990713/news/current/net.htx?source=blq/yhoo&dist=yhoo",
-    "http://a.b.com/xx.jpg?newpath=http://bob.dave.com",
-
-    "ht-tp://a.b.com",
-    "ht+tp://a.b.com",
-    "ht.tp://a.b.com",
-
-    "h1ttp://a.b.com",
-    "http1://a.b.com",
-  };
-
-  static const char *bad[] = {
-    "http://[1:2:3:4:5:6:7:8:9]",
-    "http://1:2:3:4:5:6:7:8:A:B",
-    "http://bob.com[::1]",
-    "http://[::1].com",
-
-    "http://foo:bar:baz@bob.com/",
-    "http://foo:bar:baz@[::1]:8080/",
-
-    "http://]",
-    "http://:",
-
-    "http:/",
-    "http:/foo.bar.com/",
-    "~http://invalid.char.in.scheme/foo",
-    "http~://invalid.char.in.scheme/foo",
-    "ht~tp://invalid.char.in.scheme/foo",
-    "1http://first.char.not.alpha",
-    "some.domain.com/http://invalid.domain/foo",
-    ":",
-    "://",
-
-    // maybe this should be a valid URL
-    "a.b.com/xx.jpg?newpath=http://bob.dave.com",
-  };
-
-  int err, failed;
-  URL url;
-  const char *start;
-  const char *end;
-  int old_length, new_length;
-
-  bri_box("test_url");
-
-  failed = 0;
-  for (unsigned i = 0; i < countof(strs); i++) {
-    old_length = static_cast<int>(strlen(strs[i]));
-    start      = strs[i];
-    end        = start + old_length;
-
-    url.create(nullptr);
-    err = url.parse(&start, end);
-    if (err < 0) {
-      printf("Failed to parse url '%s'\n", start);
-      failed = 1;
-      break;
-    }
-
-    char print_buf[1024];
-    new_length = 0;
-    int offset = 0;
-    url.print(print_buf, 1024, &new_length, &offset);
-    print_buf[new_length] = '\0';
-
-    const char *fail_text = nullptr;
-
-    if (old_length == new_length) {
-      if (memcmp(print_buf, strs[i], new_length) != 0) {
-        fail_text = "URLS DIFFER";
-      }
-    } else if (old_length == new_length - 1) {
-      // Check to see if the difference is the trailing
-      //   slash we add
-      if (memcmp(print_buf, strs[i], old_length) != 0 || print_buf[new_length - 1] != '/' || (strs[i])[old_length - 1] == '/') {
-        fail_text = "TRAILING SLASH";
-      }
-    } else {
-      fail_text = "LENGTHS DIFFER";
-    }
-
-    if (fail_text) {
-      failed = 1;
-      printf("%16s: OLD: (%4d) %s\n", fail_text, old_length, strs[i]);
-      printf("%16s: NEW: (%4d) %s\n", "", new_length, print_buf);
-      obj_describe(url.m_url_impl, true);
-    } else {
-      printf("%16s: '%s'\n", "PARSE SUCCESS", strs[i]);
-    }
-
-    url.destroy();
-  }
-
-  for (unsigned i = 0; i < countof(bad); ++i) {
-    const char *x = bad[i];
-
-    url.create(nullptr);
-    err = url.parse(x, strlen(x));
-    url.destroy();
-    if (err == PARSE_RESULT_DONE) {
-      failed = 1;
-      printf("Successfully parsed invalid url '%s'", x);
-      break;
-    } else {
-      printf("   bad URL - PARSE FAILED: '%s'\n", bad[i]);
-    }
-  }
-
-  return (failures_to_status("test_url", failed));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_mime()
-{
-  // This can not be a static string (any more) since we unfold the headers
-  // in place.
-  char mime[] = {
-    //        "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n"
-    "Date: 6 Nov 1994 08:49:37 GMT\r\n"
-    "Max-Forwards: 65535\r\n"
-    "Cache-Control: private\r\n"
-    "accept: foo\r\n"
-    "accept: bar\n"
-    ": (null) field name\r\n"
-    "aCCept: \n"
-    "ACCEPT\r\n"
-    "foo: bar\r\n"
-    "foo: argh\r\n"
-    "foo: three, four\r\n"
-    "word word: word \r\n"
-    "accept: \"fazzle, dazzle\"\r\n"
-    "accept: 1, 2, 3, 4, 5, 6, 7, 8\r\n"
-    "continuation: part1\r\n"
-    " part2\r\n"
-    "scooby: doo\r\n"
-    " scooby: doo\r\n"
-    "bar: foo\r\n"
-    "\r\n",
-  };
-
-  int err;
-  MIMEHdr hdr;
-  MIMEParser parser;
-  const char *start;
-  const char *end;
-
-  bri_box("test_mime");
-
-  printf("   <<< MUST BE HAND-VERIFIED FOR FULL-BENEFIT>>>\n\n");
-
-  start = mime;
-  end   = start + strlen(start);
-
-  mime_parser_init(&parser);
-
-  bool must_copy_strs = false;
-
-  hdr.create(nullptr);
-  err = hdr.parse(&parser, &start, end, must_copy_strs, false);
-
-  if (err < 0) {
-    return (failures_to_status("test_mime", 1));
-  }
-
-  // Test the (new) continuation line folding to be correct. This should replace the
-  // \r\n with two spaces (so a total of three between "part1" and "part2").
-  int length               = 0;
-  const char *continuation = hdr.value_get("continuation", 12, &length);
-
-  if ((13 != length)) {
-    printf("FAILED: continue header folded line was too short\n");
-    return (failures_to_status("test_mime", 1));
-  }
-
-  if (strncmp(continuation + 5, "   ", 3)) {
-    printf("FAILED: continue header unfolding did not produce correct WS's\n");
-    return (failures_to_status("test_mime", 1));
-  }
-
-  if (strncmp(continuation, "part1   part2", 13)) {
-    printf("FAILED: continue header unfolding was not correct\n");
-    return (failures_to_status("test_mime", 1));
-  }
-
-  hdr.field_delete("not_there", 9);
-  hdr.field_delete("accept", 6);
-  hdr.field_delete("scooby", 6);
-  hdr.field_delete("scooby", 6);
-  hdr.field_delete("bar", 3);
-  hdr.field_delete("continuation", 12);
-
-  int count = hdr.fields_count();
-  printf("hdr.fields_count() = %d\n", count);
-
-  int i_max_forwards = hdr.value_get_int("Max-Forwards", 12);
-  int u_max_forwards = hdr.value_get_uint("Max-Forwards", 12);
-  printf("i_max_forwards = %d   u_max_forwards = %d\n", i_max_forwards, u_max_forwards);
-
-  hdr.set_age(9999);
-
-  length = hdr.length_get();
-  printf("hdr.length_get() = %d\n", length);
-
-  time_t t0, t1, t2;
-
-  t0 = hdr.get_date();
-  if (t0 == 0) {
-    printf("FAILED: Initial date is zero but shouldn't be\n");
-    return (failures_to_status("test_mime", 1));
-  }
-
-  t1 = time(nullptr);
-  hdr.set_date(t1);
-  t2 = hdr.get_date();
-  if (t1 != t2) {
-    printf("FAILED: set_date(%" PRId64 ") ... get_date = %" PRId64 "\n\n", static_cast<int64_t>(t1), static_cast<int64_t>(t2));
-    return (failures_to_status("test_mime", 1));
-  }
-
-  hdr.value_append("Cache-Control", 13, "no-cache", 8, true);
-
-  MIMEField *cc_field;
-  StrList slist;
-
-  cc_field = hdr.field_find("Cache-Control", 13);
-
-  if (cc_field == nullptr) {
-    printf("FAILED: missing Cache-Control header\n\n");
-    return (failures_to_status("test_mime", 1));
-  }
-
-  // TODO: Do we need to check the "count" returned?
-  cc_field->value_get_comma_list(&slist); // FIX: correct usage?
-
-  if (cc_field->value_get_index("Private", 7) < 0) {
-    printf("Failed: value_get_index of Cache-Control did not find private");
-    return (failures_to_status("test_mime", 1));
-  }
-  if (cc_field->value_get_index("Bogus", 5) >= 0) {
-    printf("Failed: value_get_index of Cache-Control incorrectly found bogus");
-    return (failures_to_status("test_mime", 1));
-  }
-  if (hdr.value_get_index("foo", 3, "three", 5) < 0) {
-    printf("Failed: value_get_index of foo did not find three");
-    return (failures_to_status("test_mime", 1));
-  }
-  if (hdr.value_get_index("foo", 3, "bar", 3) < 0) {
-    printf("Failed: value_get_index of foo did not find bar");
-    return (failures_to_status("test_mime", 1));
-  }
-  if (hdr.value_get_index("foo", 3, "Bogus", 5) >= 0) {
-    printf("Failed: value_get_index of foo incorrectly found bogus");
-    return (failures_to_status("test_mime", 1));
-  }
-
-  mime_parser_clear(&parser);
-
-  hdr.print(nullptr, 0, nullptr, nullptr);
-  printf("\n");
-
-  obj_describe((HdrHeapObjImpl *)(hdr.m_mime), true);
-
-  const char *field_name = "Test_heap_reuse";
-
-  MIMEField *f = hdr.field_create(field_name, static_cast<int>(strlen(field_name)));
-  ink_release_assert(f->m_ptr_value == nullptr);
-
-  hdr.field_attach(f);
-  ink_release_assert(f->m_ptr_value == nullptr);
-
-  const char *test_value = "mytest";
-
-  printf("Testing Heap Reuse..\n");
-  hdr.field_value_set(f, "orig_value", strlen("orig_value"));
-  const char *m_ptr_value_orig = f->m_ptr_value;
-  hdr.field_value_set(f, test_value, strlen(test_value), true);
-  ink_release_assert(f->m_ptr_value != test_value);       // should be copied
-  ink_release_assert(f->m_ptr_value == m_ptr_value_orig); // heap doesn't change
-  ink_release_assert(f->m_len_value == strlen(test_value));
-  ink_release_assert(memcmp(f->m_ptr_value, test_value, f->m_len_value) == 0);
-
-  m_ptr_value_orig           = f->m_ptr_value;
-  const char *new_test_value = "myTest";
-  hdr.field_value_set(f, new_test_value, strlen(new_test_value), false);
-  ink_release_assert(f->m_ptr_value != new_test_value);   // should be copied
-  ink_release_assert(f->m_ptr_value != m_ptr_value_orig); // new heap
-  ink_release_assert(f->m_len_value == strlen(new_test_value));
-  ink_release_assert(memcmp(f->m_ptr_value, new_test_value, f->m_len_value) == 0);
-
-  hdr.fields_clear();
-
-  hdr.destroy();
-
-  return (failures_to_status("test_mime", 0));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_http_aux(const char *request, const char *response)
-{
-  int err;
-  HTTPHdr req_hdr, rsp_hdr;
-  HTTPParser parser;
-  const char *start;
-  const char *end;
-
-  printf("   <<< MUST BE HAND-VERIFIED FOR FULL BENEFIT >>>\n\n");
-
-  /*** (1) parse the request string into req_hdr ***/
-
-  start = request;
-  end   = start + strlen(start); // 1 character past end of string
-
-  http_parser_init(&parser);
-
-  req_hdr.create(HTTP_TYPE_REQUEST);
-  rsp_hdr.create(HTTP_TYPE_RESPONSE);
-
-  printf("======== parsing\n\n");
-  while (true) {
-    err = req_hdr.parse_req(&parser, &start, end, true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-  if (err == PARSE_RESULT_ERROR) {
-    req_hdr.destroy();
-    rsp_hdr.destroy();
-    return (failures_to_status("test_http_aux", false));
-  }
-
-  /*** useless copy to exercise copy function ***/
-
-  HTTPHdr new_hdr;
-  new_hdr.create(HTTP_TYPE_REQUEST);
-  new_hdr.copy(&req_hdr);
-  new_hdr.destroy();
-
-  /*** (2) print out the request ***/
-
-  printf("======== real request (length=%d)\n\n", static_cast<int>(strlen(request)));
-  printf("%s\n", request);
-
-  printf("\n[");
-  req_hdr.print(nullptr, 0, nullptr, nullptr);
-  printf("]\n\n");
-
-  obj_describe(req_hdr.m_http, true);
-
-  // req_hdr.destroy ();
-  // ink_release_assert(!"req_hdr.destroy() not defined");
-
-  /*** (3) parse the response string into rsp_hdr ***/
-
-  start = response;
-  end   = start + strlen(start);
-
-  http_parser_clear(&parser);
-  http_parser_init(&parser);
-
-  while (true) {
-    err = rsp_hdr.parse_resp(&parser, &start, end, true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-  if (err == PARSE_RESULT_ERROR) {
-    req_hdr.destroy();
-    rsp_hdr.destroy();
-    return (failures_to_status("test_http_aux", false));
-  }
-
-  http_parser_clear(&parser);
-
-  /*** (4) print out the response ***/
-
-  printf("\n======== real response (length=%d)\n\n", static_cast<int>(strlen(response)));
-  printf("%s\n", response);
-
-  printf("\n[");
-  rsp_hdr.print(nullptr, 0, nullptr, nullptr);
-  printf("]\n\n");
-
-  obj_describe(rsp_hdr.m_http, true);
-
-#define NNN 1000
-  {
-    char buf[NNN];
-    int bufindex, last_bufindex;
-    int tmp;
-    int i;
-
-    bufindex = 0;
-
-    do {
-      last_bufindex = bufindex;
-      tmp           = bufindex;
-      buf[0]        = '#'; // make it obvious if hdr.print doesn't print anything
-      err           = rsp_hdr.print(buf, NNN, &bufindex, &tmp);
-
-      // printf("test_header: tmp = %d  err = %d  bufindex = %d\n", tmp, err, bufindex);
-      putchar('{');
-      for (i = 0; i < bufindex - last_bufindex; i++) {
-        if (!iscntrl(buf[i])) {
-          putchar(buf[i]);
-        } else {
-          printf("\\%o", buf[i]);
-        }
-      }
-      putchar('}');
-    } while (!err);
-  }
-
-  // rsp_hdr.print (NULL, 0, NULL, NULL);
-
-  req_hdr.destroy();
-  rsp_hdr.destroy();
-
-  return (failures_to_status("test_http_aux", false));
-}
-
-int
-HdrTest::test_http_req_parse_error(const char *request, const char *response)
-{
-  int err;
-  HTTPHdr req_hdr, rsp_hdr;
-  HTTPParser parser;
-  const char *start;
-  const char *end;
-
-  int status = 1;
-
-  /*** (1) parse the request string into req_hdr ***/
-
-  start = request;
-  end   = start + strlen(start); // 1 character past end of string
-
-  http_parser_init(&parser);
-
-  req_hdr.create(HTTP_TYPE_REQUEST);
-  rsp_hdr.create(HTTP_TYPE_RESPONSE);
-
-  printf("======== test_http_req_parse_error parsing\n\n");
-  err = req_hdr.parse_req(&parser, &start, end, true, true, 1);
-  if (err != PARSE_RESULT_ERROR) {
-    status = 0;
-  }
-
-  http_parser_clear(&parser);
-
-  /*** (4) print out the response ***/
-
-  printf("\n======== real response (length=%d)\n\n", static_cast<int>(strlen(response)));
-  printf("%s\n", response);
-
-  obj_describe(rsp_hdr.m_http, true);
-
-  req_hdr.destroy();
-  rsp_hdr.destroy();
-
-  return (failures_to_status("test_http_req_parse_error", (status == 0)));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_http_hdr_print_and_copy()
-{
-  static struct {
-    const char *req;
-    const char *req_tgt;
-    const char *rsp;
-    const char *rsp_tgt;
-  } tests[] = {
-    {"GET http://foo.com/bar.txt HTTP/1.0\r\n"
-     "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa\r\n"
-     "\r\n",
-     "GET http://foo.com/bar.txt HTTP/1.0\r\n"
-     "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "\r\n"},
-    {"GET http://foo.com/bar.txt HTTP/1.0\r\n"
-     "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj "
-     "klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda \r\n"
-     "\r\n",
-     "GET http://foo.com/bar.txt HTTP/1.0\r\n"
-     "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj "
-     "klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda \r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "\r\n"},
-    {"GET http://foo.com/bar.txt HTTP/1.0\r\n"
-     "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj "
-     "klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda kfl; fsdajfl; "
-     "sdjafl;dsajlsjfl;sdafjsdal;fjds al;fdjslaf ;slajdk;f\r\n"
-     "\r\n",
-     "GET http://foo.com/bar.txt HTTP/1.0\r\n"
-     "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj "
-     "klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda kfl; fsdajfl; "
-     "sdjafl;dsajlsjfl;sdafjsdal;fjds al;fdjslaf ;slajdk;f\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "\r\n"},
-    {"GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-     "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-     "Referer: chocolate fribble\r\n", // missing final CRLF
-     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-     "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-     "Referer: chocolate fribble\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "MIME-Version: 1.0\r\n"
-     "Server: WebSTAR/2.1 ID/30013\r\n"
-     "Content-Type: text/html\r\n"
-     "Content-Length: 939\r\n"
-     "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n", // missing final CRLF
-     "HTTP/1.0 200 OK\r\n"
-     "MIME-Version: 1.0\r\n"
-     "Server: WebSTAR/2.1 ID/30013\r\n"
-     "Content-Type: text/html\r\n"
-     "Content-Length: 939\r\n"
-     "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
-     "\r\n"},
-    {"GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-     "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-     "Referer: \r\n", // missing final CRLF
-     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-     "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-     "Referer: \r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "MIME-Version: 1.0\r\n"
-     "Server: WebSTAR/2.1 ID/30013\r\n"
-     "Content-Type: text/html\r\n"
-     "Content-Length: 939\r\n"
-     "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "MIME-Version: 1.0\r\n"
-     "Server: WebSTAR/2.1 ID/30013\r\n"
-     "Content-Type: text/html\r\n"
-     "Content-Length: 939\r\n"
-     "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
-     "\r\n"},
-    {"GET http://www.news.com:80/ HTTP/1.0\r\n"
-     "Proxy-Connection: Keep-Alive\r\n"
-     "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
-     "Pragma: no-cache\r\n"
-     "Host: www.news.com\r\n"
-     "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
-     "Accept-Language: en\r\n"
-     "Accept-Charset: iso-8859-1, *, utf-8\r\n"
-     "Client-ip: D1012148\r\n"
-     "Foo: abcdefghijklmnopqrtu\r\n"
-     "\r\n",
-     "GET http://www.news.com:80/ HTTP/1.0\r\n"
-     "Proxy-Connection: Keep-Alive\r\n"
-     "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
-     "Pragma: no-cache\r\n"
-     "Host: www.news.com\r\n"
-     "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
-     "Accept-Language: en\r\n"
-     "Accept-Charset: iso-8859-1, *, utf-8\r\n"
-     "Client-ip: D1012148\r\n"
-     "Foo: abcdefghijklmnopqrtu\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "Content-Length: 16428\r\n"
-     "Content-Type: text/html\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "Content-Length: 16428\r\n"
-     "Content-Type: text/html\r\n"
-     "\r\n"},
-    {"GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-     "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-     "Referer: http://people.netscape.com/jwz/index.html\r\n"
-     "Proxy-Connection: Keep-Alive\r\n"
-     "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
-     "Pragma: no-cache\r\n"
-     "Host: people.netscape.com\r\n"
-     "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
-     "\r\n",
-     "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-     "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-     "Referer: http://people.netscape.com/jwz/index.html\r\n"
-     "Proxy-Connection: Keep-Alive\r\n"
-     "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
-     "Pragma: no-cache\r\n"
-     "Host: people.netscape.com\r\n"
-     "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "Content-Length: 16428\r\n"
-     "Content-Type: text/html\r\n"
-     "\r\n",
-     "HTTP/1.0 200 OK\r\n"
-     "Content-Length: 16428\r\n"
-     "Content-Type: text/html\r\n"
-     "\r\n"},
-  };
-
-  int ntests = sizeof(tests) / sizeof(tests[0]);
-  int i, failures;
-
-  failures = 0;
-
-  bri_box("test_http_hdr_print_and_copy");
-
-  for (i = 0; i < ntests; i++) {
-    int status = test_http_hdr_print_and_copy_aux(i + 1, tests[i].req, tests[i].req_tgt, tests[i].rsp, tests[i].rsp_tgt);
-    if (status == 0) {
-      ++failures;
-    }
-
-    // Test for expected failures
-    // parse with a '\0' in the header.  Should fail
-    status = test_http_hdr_null_char(i + 1, tests[i].req, tests[i].req_tgt);
-    if (status == 0) {
-      ++failures;
-    }
-
-    // Parse with a CTL character in the method name.  Should fail
-    status = test_http_hdr_ctl_char(i + 1, tests[i].req, tests[i].req_tgt);
-    if (status == 0) {
-      ++failures;
-    }
-  }
-
-  return (failures_to_status("test_http_hdr_print_and_copy", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-static const char *
-comp_http_hdr(HTTPHdr *h1, HTTPHdr *h2)
-{
-  int h1_len, h2_len;
-  int p_index, p_dumpoffset, rval;
-  char *h1_pbuf, *h2_pbuf;
-
-  h1_len = h1->length_get();
-  h2_len = h2->length_get();
-
-  if (h1_len != h2_len) {
-    return "length mismatch";
-  }
-
-  h1_pbuf = static_cast<char *>(ats_malloc(h1_len + 1));
-  h2_pbuf = static_cast<char *>(ats_malloc(h2_len + 1));
-
-  p_index = p_dumpoffset = 0;
-  rval                   = h1->print(h1_pbuf, h1_len, &p_index, &p_dumpoffset);
-  if (rval != 1) {
-    ats_free(h1_pbuf);
-    ats_free(h2_pbuf);
-    return "hdr print failed";
-  }
-
-  p_index = p_dumpoffset = 0;
-  rval                   = h2->print(h2_pbuf, h2_len, &p_index, &p_dumpoffset);
-  if (rval != 1) {
-    ats_free(h1_pbuf);
-    ats_free(h2_pbuf);
-    return "hdr print failed";
-  }
-
-  rval = memcmp(h1_pbuf, h2_pbuf, h1_len);
-  ats_free(h1_pbuf);
-  ats_free(h2_pbuf);
-
-  if (rval != 0) {
-    return "compare failed";
-  } else {
-    return nullptr;
-  }
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_http_hdr_copy_over_aux(int testnum, const char *request, const char *response)
-{
-  int err;
-  HTTPHdr req_hdr;
-  HTTPHdr resp_hdr;
-  HTTPHdr copy1;
-  HTTPHdr copy2;
-
-  HTTPParser parser;
-  const char *start;
-  const char *end;
-  const char *comp_str = nullptr;
-
-  /*** (1) parse the request string into hdr ***/
-
-  req_hdr.create(HTTP_TYPE_REQUEST);
-
-  start = request;
-  end   = start + strlen(start); // 1 character past end of string
-
-  http_parser_init(&parser);
-
-  while (true) {
-    err = req_hdr.parse_req(&parser, &start, end, true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-
-  if (err == PARSE_RESULT_ERROR) {
-    printf("FAILED: (test #%d) parse error parsing request hdr\n", testnum);
-    return (0);
-  }
-  http_parser_clear(&parser);
-
-  /*** (2) parse the response string into hdr ***/
-
-  resp_hdr.create(HTTP_TYPE_RESPONSE);
-
-  start = response;
-  end   = start + strlen(start); // 1 character past end of string
-
-  http_parser_init(&parser);
-
-  while (true) {
-    err = resp_hdr.parse_resp(&parser, &start, end, true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-
-  if (err == PARSE_RESULT_ERROR) {
-    printf("FAILED: (test #%d) parse error parsing response hdr\n", testnum);
-    return (0);
-  }
-
-  /*** (3) Basic copy testing ***/
-  copy1.create(HTTP_TYPE_REQUEST);
-  copy1.copy(&req_hdr);
-  comp_str = comp_http_hdr(&req_hdr, &copy1);
-  if (comp_str) {
-    goto done;
-  }
-
-  copy2.create(HTTP_TYPE_RESPONSE);
-  copy2.copy(&resp_hdr);
-  comp_str = comp_http_hdr(&resp_hdr, &copy2);
-  if (comp_str) {
-    goto done;
-  }
-
-  // The APIs for copying headers uses memcpy() which can be unsafe for
-  // overlapping memory areas. It's unclear to me why these tests were
-  // created in the first place honestly, since nothing else does this.
-
-  /*** (4) Gender bending copying ***/
-  copy1.copy(&resp_hdr);
-  comp_str = comp_http_hdr(&resp_hdr, &copy1);
-  if (comp_str) {
-    goto done;
-  }
-
-  copy2.copy(&req_hdr);
-  comp_str = comp_http_hdr(&req_hdr, &copy2);
-  if (comp_str) {
-    goto done;
-  }
-
-done:
-  req_hdr.destroy();
-  resp_hdr.destroy();
-  copy1.destroy();
-  copy2.destroy();
-
-  if (comp_str) {
-    printf("FAILED: (test #%d) copy & compare: %s\n", testnum, comp_str);
-    printf("REQ:\n[%.*s]\n", static_cast<int>(strlen(request)), request);
-    printf("RESP  :\n[%.*s]\n", static_cast<int>(strlen(response)), response);
-    return (0);
-  } else {
-    return (1);
-  }
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-int
-HdrTest::test_http_hdr_null_char(int testnum, const char *request, const char * /*request_tgt*/)
-{
-  int err;
-  HTTPHdr hdr;
-  HTTPParser parser;
-  const char *start;
-  char cpy_buf[2048];
-  const char *cpy_buf_ptr = cpy_buf;
-
-  /*** (1) parse the request string into hdr ***/
-
-  hdr.create(HTTP_TYPE_REQUEST);
-
-  start = request;
-
-  if (strlen(start) > sizeof(cpy_buf)) {
-    printf("FAILED: (test #%d) Internal buffer too small for null char test\n", testnum);
-    return (0);
-  }
-  strcpy(cpy_buf, start);
-
-  // Put a null character somewhere in the header
-  int length          = strlen(start);
-  cpy_buf[length / 2] = '\0';
-  http_parser_init(&parser);
-
-  while (true) {
-    err = hdr.parse_req(&parser, &cpy_buf_ptr, cpy_buf_ptr + length, true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-  if (err != PARSE_RESULT_ERROR) {
-    printf("FAILED: (test #%d) no parse error parsing request with null char\n", testnum);
-    return (0);
-  }
-  return 1;
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-int
-HdrTest::test_http_hdr_ctl_char(int testnum, const char *request, const char * /*request_tgt */)
-{
-  int err;
-  HTTPHdr hdr;
-  HTTPParser parser;
-  const char *start;
-  char cpy_buf[2048];
-  const char *cpy_buf_ptr = cpy_buf;
-
-  /*** (1) parse the request string into hdr ***/
-
-  hdr.create(HTTP_TYPE_REQUEST);
-
-  start = request;
-
-  if (strlen(start) > sizeof(cpy_buf)) {
-    printf("FAILED: (test #%d) Internal buffer too small for ctl char test\n", testnum);
-    return (0);
-  }
-  strcpy(cpy_buf, start);
-
-  // Replace a character in the method
-  cpy_buf[1] = 16;
-
-  http_parser_init(&parser);
-
-  while (true) {
-    err = hdr.parse_req(&parser, &cpy_buf_ptr, cpy_buf_ptr + strlen(start), true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-
-  if (err != PARSE_RESULT_ERROR) {
-    printf("FAILED: (test #%d) no parse error parsing method with ctl char\n", testnum);
-    return (0);
-  }
-  return 1;
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_http_hdr_print_and_copy_aux(int testnum, const char *request, const char *request_tgt, const char *response,
-                                          const char *response_tgt)
-{
-  int err;
-  HTTPHdr hdr;
-  HTTPParser parser;
-  const char *start;
-  const char *end;
-
-  char prt_buf[2048];
-  int prt_bufsize = sizeof(prt_buf);
-  int prt_bufindex, prt_dumpoffset, prt_ret;
-
-  char cpy_buf[2048];
-  int cpy_bufsize = sizeof(cpy_buf);
-  int cpy_bufindex, cpy_dumpoffset, cpy_ret;
-
-  char *marshal_buf   = static_cast<char *>(ats_malloc(2048));
-  int marshal_bufsize = sizeof(cpy_buf);
-
-  /*** (1) parse the request string into hdr ***/
-
-  hdr.create(HTTP_TYPE_REQUEST);
-
-  start = request;
-  end   = start + strlen(start); // 1 character past end of string
-
-  http_parser_init(&parser);
-
-  while (true) {
-    err = hdr.parse_req(&parser, &start, end, true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-
-  if (err == PARSE_RESULT_ERROR) {
-    printf("FAILED: (test #%d) parse error parsing request hdr\n", testnum);
-    ats_free(marshal_buf);
-    return (0);
-  }
-
-  /*** (2) copy the request header ***/
-  HTTPHdr new_hdr, marshal_hdr;
-  RefCountObj ref;
-
-  // Pretend to pin this object with a refcount.
-  ref.refcount_inc();
-
-  int marshal_len = hdr.m_heap->marshal(marshal_buf, marshal_bufsize);
-  marshal_hdr.create(HTTP_TYPE_REQUEST);
-  marshal_hdr.unmarshal(marshal_buf, marshal_len, &ref);
-  new_hdr.create(HTTP_TYPE_REQUEST);
-  new_hdr.copy(&marshal_hdr);
-
-  /*** (3) print the request header and copy to buffers ***/
-
-  prt_bufindex = prt_dumpoffset = 0;
-  prt_ret                       = hdr.print(prt_buf, prt_bufsize, &prt_bufindex, &prt_dumpoffset);
-
-  cpy_bufindex = cpy_dumpoffset = 0;
-  cpy_ret                       = new_hdr.print(cpy_buf, cpy_bufsize, &cpy_bufindex, &cpy_dumpoffset);
-
-  ats_free(marshal_buf);
-
-  if ((prt_ret != 1) || (cpy_ret != 1)) {
-    printf("FAILED: (test #%d) couldn't print req hdr or copy --- prt_ret=%d, cpy_ret=%d\n", testnum, prt_ret, cpy_ret);
-    return (0);
-  }
-
-  if ((static_cast<size_t>(prt_bufindex) != strlen(request_tgt)) || (static_cast<size_t>(cpy_bufindex) != strlen(request_tgt))) {
-    printf("FAILED: (test #%d) print req output size mismatch --- tgt=%d, prt_bufsize=%d, cpy_bufsize=%d\n", testnum,
-           static_cast<int>(strlen(request_tgt)), prt_bufindex, cpy_bufindex);
-
-    printf("ORIGINAL:\n[%.*s]\n", static_cast<int>(strlen(request)), request);
-    printf("TARGET  :\n[%.*s]\n", static_cast<int>(strlen(request_tgt)), request_tgt);
-    printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
-    printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
-    return (0);
-  }
-
-  if ((strncasecmp(request_tgt, prt_buf, strlen(request_tgt)) != 0) ||
-      (strncasecmp(request_tgt, cpy_buf, strlen(request_tgt)) != 0)) {
-    printf("FAILED: (test #%d) print req output mismatch\n", testnum);
-    printf("ORIGINAL:\n[%.*s]\n", static_cast<int>(strlen(request)), request);
-    printf("TARGET  :\n[%.*s]\n", static_cast<int>(strlen(request_tgt)), request_tgt);
-    printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
-    printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
-    return (0);
-  }
-
-  hdr.destroy();
-  new_hdr.destroy();
-
-  /*** (4) parse the response string into hdr ***/
-
-  hdr.create(HTTP_TYPE_RESPONSE);
-
-  start = response;
-  end   = start + strlen(start); // 1 character past end of string
-
-  http_parser_init(&parser);
-
-  while (true) {
-    err = hdr.parse_resp(&parser, &start, end, true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-
-  if (err == PARSE_RESULT_ERROR) {
-    printf("FAILED: (test #%d) parse error parsing response hdr\n", testnum);
-    return (0);
-  }
-
-  /*** (2) copy the response header ***/
-
-  new_hdr.create(HTTP_TYPE_RESPONSE);
-  new_hdr.copy(&hdr);
-
-  /*** (3) print the response header and copy to buffers ***/
-
-  prt_bufindex = prt_dumpoffset = 0;
-  prt_ret                       = hdr.print(prt_buf, prt_bufsize, &prt_bufindex, &prt_dumpoffset);
-
-  cpy_bufindex = cpy_dumpoffset = 0;
-  cpy_ret                       = new_hdr.print(cpy_buf, cpy_bufsize, &cpy_bufindex, &cpy_dumpoffset);
-
-  if ((prt_ret != 1) || (cpy_ret != 1)) {
-    printf("FAILED: (test #%d) couldn't print rsp hdr or copy --- prt_ret=%d, cpy_ret=%d\n", testnum, prt_ret, cpy_ret);
-    return (0);
-  }
-
-  if ((static_cast<size_t>(prt_bufindex) != strlen(response_tgt)) || (static_cast<size_t>(cpy_bufindex) != strlen(response_tgt))) {
-    printf("FAILED: (test #%d) print rsp output size mismatch --- tgt=%d, prt_bufsize=%d, cpy_bufsize=%d\n", testnum,
-           static_cast<int>(strlen(response_tgt)), prt_bufindex, cpy_bufindex);
-    printf("ORIGINAL:\n[%.*s]\n", static_cast<int>(strlen(response)), response);
-    printf("TARGET  :\n[%.*s]\n", static_cast<int>(strlen(response_tgt)), response_tgt);
-    printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
-    printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
-    return (0);
-  }
-
-  if ((strncasecmp(response_tgt, prt_buf, strlen(response_tgt)) != 0) ||
-      (strncasecmp(response_tgt, cpy_buf, strlen(response_tgt)) != 0)) {
-    printf("FAILED: (test #%d) print rsp output mismatch\n", testnum);
-    printf("ORIGINAL:\n[%.*s]\n", static_cast<int>(strlen(response)), response);
-    printf("TARGET  :\n[%.*s]\n", static_cast<int>(strlen(response_tgt)), response_tgt);
-    printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
-    printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
-    return (0);
-  }
-
-  hdr.destroy();
-  new_hdr.destroy();
-
-  if (test_http_hdr_copy_over_aux(testnum, request, response) == 0) {
-    return 0;
-  }
-
-  return (1);
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_http()
-{
-  int status = 1;
-
-  static const char request0[] = {
-    "GET http://www.news.com:80/ HTTP/1.0\r\n"
-    "Proxy-Connection: Keep-Alive\r\n"
-    "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
-    "Pragma: no-cache\r\n"
-    "Host: www.news.com\r\n"
-    "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
-    "Accept-Language: en\r\n"
-    "Accept-Charset: iso-8859-1, *, utf-8\r\n"
-    "Cookie: u_vid_0_0=00031ba3; "
-    "s_cur_0_0=0101sisi091314775496e7d3Jx4+POyJakrMybmNOsq6XOn5bVn5Z6a4Ln5crU5M7Rxq2lm5aWpqupo20=; "
-    "SC_Cnet001=Sampled; SC_Cnet002=Sampled\r\n"
-    "Client-ip: D1012148\r\n"
-    "Foo: abcdefghijklmnopqrtu\r\n"
-    "\r\n",
-  };
-
-  static const char request09[] = {
-    "GET /index.html\r\n"
-    "\r\n",
-  };
-
-  static const char request1[] = {
-    "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-    "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-    "Referer: http://people.netscape.com/jwz/index.html\r\n"
-    "Proxy-Connection: Keep-Alive\r\n"
-    "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
-    "Pragma: no-cache\r\n"
-    "Host: people.netscape.com\r\n"
-    "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
-    "\r\n",
-  };
-
-  static const char request_no_colon[] = {
-    "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-    "If-Modified-Since Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-    "Referer http://people.netscape.com/jwz/index.html\r\n"
-    "Proxy-Connection Keep-Alive\r\n"
-    "User-Agent  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
-    "Pragma no-cache\r\n"
-    "Host people.netscape.com\r\n"
-    "Accept image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
-    "\r\n",
-  };
-
-  static const char request_no_val[] = {
-    "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-    "If-Modified-Since:\r\n"
-    "Referer:     "
-    "Proxy-Connection:\r\n"
-    "User-Agent:     \r\n"
-    "Host:::\r\n"
-    "\r\n",
-  };
-
-  static const char request_multi_fblock[] = {
-    "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
-    "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
-    "Referer: http://people.netscape.com/jwz/index.html\r\n"
-    "Proxy-Connection: Keep-Alive\r\n"
-    "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
-    "Pragma: no-cache\r\n"
-    "Host: people.netscape.com\r\n"
-    "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
-    "X-1: blah\r\n"
-    "X-2: blah\r\n"
-    "X-3: blah\r\n"
-    "X-4: blah\r\n"
-    "X-5: blah\r\n"
-    "X-6: blah\r\n"
-    "X-7: blah\r\n"
-    "X-8: blah\r\n"
-    "X-9: blah\r\n"
-    "Pragma: no-cache\r\n"
-    "X-X-1: blah\r\n"
-    "X-X-2: blah\r\n"
-    "X-X-3: blah\r\n"
-    "X-X-4: blah\r\n"
-    "X-X-5: blah\r\n"
-    "X-X-6: blah\r\n"
-    "X-X-7: blah\r\n"
-    "X-X-8: blah\r\n"
-    "X-X-9: blah\r\n"
-    "\r\n",
-  };
-
-  static const char request_leading_space[] = {
-    " GET http://www.news.com:80/ HTTP/1.0\r\n"
-    "Proxy-Connection: Keep-Alive\r\n"
-    "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
-    "\r\n",
-  };
-
-  static const char request_padding[] = {
-    "GET http://www.padding.com:80/ HTTP/1.0\r\n"
-    "X-1: blah1\r\n"
-    //       "X-2:  blah2\r\n"
-    "X-3:   blah3\r\n"
-    //       "X-4:    blah4\r\n"
-    "X-5:     blah5\r\n"
-    //       "X-6:      blah6\r\n"
-    "X-7:       blah7\r\n"
-    //       "X-8:        blah8\r\n"
-    "X-9:         blah9\r\n"
-    "\r\n",
-  };
-
-  static const char request_09p[] = {
-    "GET http://www.news09.com/\r\n"
-    "\r\n",
-  };
-
-  static const char request_09ht[] = {
-    "GET http://www.news09.com/ HT\r\n"
-    "\r\n",
-  };
-
-  static const char request_11[] = {
-    "GET http://www.news.com/ HTTP/1.1\r\n"
-    "Connection: close\r\n"
-    "\r\n",
-  };
-
-  static const char request_too_long[] = {
-    "GET http://www.news.com/i/am/too/long HTTP/1.1\r\n"
-    "Connection: close\r\n"
-    "\r\n",
-  };
-
-  static const char request_unterminated[] = {
-    "GET http://www.unterminated.com/ HTTP/1.1",
-  };
-
-  static const char request_blank[] = {
-    "\r\n",
-  };
-
-  static const char request_blank2[] = {
-    "\r\n"
-    "\r\n",
-  };
-
-  static const char request_blank3[] = {
-    "     "
-    "\r\n",
-  };
-
-  ////////////////////////////////////////////////////
-
-  static const char response0[] = {
-    "HTTP/1.0 200 OK\r\n"
-    "MIME-Version: 1.0\r\n"
-    "Server: WebSTAR/2.1 ID/30013\r\n"
-    "Content-Type: text/html\r\n"
-    "Content-Length: 939\r\n"
-    "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
-    "\r\n",
-  };
-
-  static const char response1[] = {
-    "HTTP/1.0 200 OK\r\n"
-    "Server: Netscape-Communications/1.12\r\n"
-    "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n"
-    "Content-Type: text/html\r\n"
-    "\r\n",
-  };
-
-  static const char response_no_colon[] = {
-    "HTTP/1.0 200 OK\r\n"
-    "Server Netscape-Communications/1.12\r\n"
-    "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n"
-    "Content-Type: text/html\r\n"
-    "\r\n",
-  };
-
-  static const char response_unterminated[] = {
-    "HTTP/1.0 200 OK",
-  };
-
-  static const char response09[] = {
-    "",
-  };
-
-  static const char response_blank[] = {
-    "\r\n",
-  };
-
-  static const char response_blank2[] = {
-    "\r\n"
-    "\r\n",
-  };
-
-  static const char response_blank3[] = {
-    "     "
-    "\r\n",
-  };
-
-  static const char response_too_long_req[] = {
-    "HTTP/1.0 414 URI Too Long\r\n"
-    "\r\n",
-  };
-
-  status = status & test_http_aux(request0, response0);
-  status = status & test_http_aux(request09, response09);
-  status = status & test_http_aux(request1, response1);
-  status = status & test_http_aux(request_no_colon, response_no_colon);
-  status = status & test_http_aux(request_no_val, response_no_colon);
-  status = status & test_http_aux(request_leading_space, response0);
-  status = status & test_http_aux(request_multi_fblock, response0);
-  status = status & test_http_aux(request_padding, response0);
-  status = status & test_http_aux(request_09p, response0);
-  status = status & test_http_aux(request_09ht, response0);
-  status = status & test_http_aux(request_11, response0);
-  status = status & test_http_aux(request_unterminated, response_unterminated);
-  status = status & test_http_aux(request_blank, response_blank);
-  status = status & test_http_aux(request_blank2, response_blank2);
-  status = status & test_http_aux(request_blank3, response_blank3);
-  status = status & test_http_req_parse_error(request_too_long, response_too_long_req);
-
-  return (failures_to_status("test_http", (status == 0)));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_http_mutation()
-{
-  bri_box("test_http_mutation");
-
-  printf("   <<< MUST BE HAND-VERIFIED FOR FULL BENEFIT>>>\n\n");
-
-  HTTPHdr resp_hdr;
-  int err, i;
-  HTTPParser parser;
-  const char base_resp[] = "HTTP/1.0 200 OK\r\n\r\n";
-  const char *start, *end;
-
-  /*** (1) parse the response string into req_hdr ***/
-
-  start = base_resp;
-  end   = start + strlen(start);
-
-  http_parser_init(&parser);
-
-  resp_hdr.create(HTTP_TYPE_RESPONSE);
-
-  while (true) {
-    err = resp_hdr.parse_resp(&parser, &start, end, true);
-    if (err != PARSE_RESULT_CONT) {
-      break;
-    }
-  }
-
-  printf("\n======== before mutation ==========\n\n");
-  printf("\n[");
-  resp_hdr.print(nullptr, 0, nullptr, nullptr);
-  printf("]\n\n");
-
-  /*** (2) add in a bunch of header fields ****/
-  char field_name[1024];
-  char field_value[1024];
-  for (i = 1; i <= 100; i++) {
-    snprintf(field_name, sizeof(field_name), "Test%d", i);
-    snprintf(field_value, sizeof(field_value), "%d %d %d %d %d", i, i, i, i, i);
-    resp_hdr.value_set(field_name, static_cast<int>(strlen(field_name)), field_value, static_cast<int>(strlen(field_value)));
-  }
-
-  /**** (3) delete all the even numbered fields *****/
-  for (i = 2; i <= 100; i += 2) {
-    snprintf(field_name, sizeof(field_name), "Test%d", i);
-    resp_hdr.field_delete(field_name, static_cast<int>(strlen(field_name)));
-  }
-
-  /***** (4) add in secondary fields for all multiples of 3 ***/
-  for (i = 3; i <= 100; i += 3) {
-    snprintf(field_name, sizeof(field_name), "Test%d", i);
-    MIMEField *f = resp_hdr.field_create(field_name, static_cast<int>(strlen(field_name)));
-    resp_hdr.field_attach(f);
-    snprintf(field_value, sizeof(field_value), "d %d %d %d %d %d", i, i, i, i, i);
-    f->value_set(resp_hdr.m_heap, resp_hdr.m_mime, field_value, static_cast<int>(strlen(field_value)));
-  }
-
-  /***** (5) append all fields with multiples of 5 ***/
-  for (i = 5; i <= 100; i += 5) {
-    snprintf(field_name, sizeof(field_name), "Test%d", i);
-    snprintf(field_value, sizeof(field_value), "a %d", i);
-
-    resp_hdr.value_append(field_name, static_cast<int>(strlen(field_name)), field_value, static_cast<int>(strlen(field_value)),
-                          true);
-  }
-
-  /**** (6) delete all multiples of nine *****/
-  for (i = 9; i <= 100; i += 9) {
-    snprintf(field_name, sizeof(field_name), "Test%d", i);
-    resp_hdr.field_delete(field_name, static_cast<int>(strlen(field_name)));
-  }
-
-  printf("\n======== mutated response ==========\n\n");
-  printf("\n[");
-  resp_hdr.print(nullptr, 0, nullptr, nullptr);
-  printf("]\n\n");
-
-  resp_hdr.destroy();
-
-  return (failures_to_status("test_http_mutation", false));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_arena_aux(Arena *arena, int len)
-{
-  char *str      = arena->str_alloc(len);
-  int verify_len = static_cast<int>(arena->str_length(str));
-
-  if (len != verify_len) {
-    printf("FAILED: requested %d, got %d bytes\n", len, verify_len);
-    return (1); // 1 error (different return convention)
-  } else {
-    return (0); // no errors (different return convention)
-  }
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_arena()
-{
-  bri_box("test_arena");
-
-  Arena *arena;
-  int failures = 0;
-
-  arena = new Arena;
-
-  failures += test_arena_aux(arena, 1);
-  failures += test_arena_aux(arena, 127);
-  failures += test_arena_aux(arena, 128);
-  failures += test_arena_aux(arena, 129);
-  failures += test_arena_aux(arena, 255);
-  failures += test_arena_aux(arena, 256);
-  failures += test_arena_aux(arena, 16384);
-  failures += test_arena_aux(arena, 16385);
-  failures += test_arena_aux(arena, 16511);
-  failures += test_arena_aux(arena, 16512);
-  failures += test_arena_aux(arena, 2097152);
-  failures += test_arena_aux(arena, 2097153);
-  failures += test_arena_aux(arena, 2097279);
-  failures += test_arena_aux(arena, 2097280);
-
-  delete arena;
-
-  return (failures_to_status("test_arena", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_regex()
-{
-  DFA dfa;
-  int status = 1;
-
-  const char *test_harness[] = {"foo", "(.*\\.apache\\.org)", "(.*\\.example\\.com)"};
-
-  bri_box("test_regex");
-
-  dfa.compile(test_harness, SIZEOF(test_harness));
-  status = status & (dfa.match("trafficserver.apache.org") == 1);
-  status = status & (dfa.match("www.example.com") == 2);
-  status = status & (dfa.match("aaaaaafooooooooinktomi....com.org") == -1);
-  status = status & (dfa.match("foo") == 0);
-
-  return (failures_to_status("test_regex", (status != 1)));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_accept_language_match()
-{
-  bri_box("test_accept_language_match");
-
-  struct {
-    const char *content_language;
-    const char *accept_language;
-    float Q;
-    int L;
-    int I;
-  } test_cases[] = {
-    {"en", "*", 1.0, 1, 1},
-    {"en", "fr", 0.0, 0, 0},
-    {"en", "de, fr, en;q=0.7", 0.7, 2, 3},
-    {"en-cockney", "de, fr, en;q=0.7", 0.7, 2, 3},
-    {"en-cockney", "de, fr, en-foobar;q=0.8, en;q=0.7", 0.7, 2, 4},
-    {"en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.7", 0.8, 10, 3},
-    {"en-cockney", "de, fr, en;q=0.8, en;q=0.7", 0.8, 2, 3},
-    {"en-cockney", "de, fr, en;q=0.7, en;q=0.8", 0.8, 2, 4},
-    {"en-cockney", "de, fr, en;q=0.8, en;q=0.8", 0.8, 2, 3},
-    {"en-cockney", "de, fr, en-cockney;q=0.7, en;q=0.8", 0.7, 10, 3},
-    {"en-cockney", "de, fr, en;q=0.8, en-cockney;q=0.7", 0.7, 10, 4},
-    {"en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.8", 0.8, 10, 3},
-    {"en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.7", 0.8, 10, 3},
-    {"en-cockney", "de, fr, en-american", 0.0, 0, 0},
-    {"en-cockney", "de, fr, en;q=0.8, en;q=0.8, *", 0.8, 2, 3},
-    {"en-cockney", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.8, 2, 3},
-    {"en-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.8, 2, 3},
-    {"oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.9, 1, 5},
-    {"oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9, *", 1.0, 1, 6},
-    {"oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *, *;q=0.9", 1.0, 1, 5},
-    {"fr-belgian", "de, fr;hi-there;q=0.9, fr;q=0.8, en", 0.9, 2, 2},
-    {"fr-belgian", "de, fr;q=0.8, fr;hi-there;q=0.9, en", 0.9, 2, 3},
-    {nullptr, nullptr, 0.0, 0, 0},
-  };
-
-  int i, I, L;
-  float Q;
-  int failures = 0;
-
-  for (i = 0; test_cases[i].accept_language; i++) {
-    StrList acpt_lang_list(false);
-    HttpCompat::parse_comma_list(&acpt_lang_list, test_cases[i].accept_language,
-                                 static_cast<int>(strlen(test_cases[i].accept_language)));
-
-    Q = HttpCompat::match_accept_language(test_cases[i].content_language, static_cast<int>(strlen(test_cases[i].content_language)),
-                                          &acpt_lang_list, &L, &I);
-
-    if ((Q != test_cases[i].Q) || (L != test_cases[i].L) || (I != test_cases[i].I)) {
-      printf("FAILED: (#%d) got { Q = %.3f; L = %d; I = %d; }, expected { Q = %.3f; L = %d; I = %d; }, from matching\n  '%s' "
-             "against '%s'\n",
-             i, Q, L, I, test_cases[i].Q, test_cases[i].L, test_cases[i].I, test_cases[i].content_language,
-             test_cases[i].accept_language);
-      ++failures;
-    }
-  }
-
-  return (failures_to_status("test_accept_language_match", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_accept_charset_match()
-{
-  bri_box("test_accept_charset_match");
-
-  struct {
-    const char *content_charset;
-    const char *accept_charset;
-    float Q;
-    int I;
-  } test_cases[] = {
-    {"iso-8859-1", "*", 1.0, 1},
-    {"iso-8859-1", "iso-8859-2", 0.0, 0},
-    {"iso-8859-1", "iso-8859", 0.0, 0},
-    {"iso-8859-1", "iso-8859-12", 0.0, 0},
-    {"iso-8859-1", "koi-8-r", 0.0, 0},
-    {"euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7", 0.7, 3},
-    {"euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7", 0.7, 3},
-    {"euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.8, euc-jp;q=0.7", 0.8, 3},
-    {"euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7, euc-jp;q=0.8", 0.8, 4},
-    {"euc-jp", "euc-jp;q=0.9, shift_jis, iso-2022-jp, euc-jp;q=0.7, euc-jp;q=0.8", 0.9, 1},
-    {"EUC-JP", "euc-jp;q=0.9, shift_jis, iso-2022-jp, euc-jp, euc-jp;q=0.8", 1.0, 4},
-    {"euc-jp", "euc-jp;q=0.9, shift_jis, iso-2022-jp, EUC-JP, euc-jp;q=0.8", 1.0, 4},
-    {"euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar", 0.0, 0},
-    {"euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *", 1.0, 4},
-    {"euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *;q=0.543", 0.543, 4},
-    {"euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *;q=0.0", 0.0, 4},
-    {"euc-jp", "shift_jis, iso-2022-jp, *;q=0.0, euc-jp-foobar, *;q=0.0", 0.0, 3},
-    {"euc-jp", "shift_jis, iso-2022-jp, *;q=0.0, euc-jp-foobar, *;q=0.5", 0.5, 5},
-    {"euc-jp", "shift_jis, iso-2022-jp, *;q=0.5, euc-jp-foobar, *;q=0.0", 0.5, 3},
-    {"euc-jp", "shift_jis, iso-2022-jp, *;q=0.5, euc-jp-foobar, *, *;q=0.0", 1.0, 5},
-    {"euc-jp", "shift_jis, euc-jp;hi-there;q=0.5, iso-2022-jp", 0.5, 2},
-    {"euc-jp", "shift_jis, euc-jp;hi-there;q= 0.5, iso-2022-jp", 0.5, 2},
-    {"euc-jp", "shift_jis, euc-jp;hi-there;q = 0.5, iso-2022-jp", 0.5, 2},
-    {"euc-jp", "shift_jis, euc-jp;hi-there ; q = 0.5, iso-2022-jp", 0.5, 2},
-    {"euc-jp", "shift_jis, euc-jp;hi-there ;; q = 0.5, iso-2022-jp", 0.5, 2},
-    {"euc-jp", "shift_jis, euc-jp;hi-there ;; Q = 0.5, iso-2022-jp", 0.5, 2},
-    {nullptr, nullptr, 0.0, 0},
-  };
-
-  int i, I;
-  float Q;
-  int failures = 0;
-
-  for (i = 0; test_cases[i].accept_charset; i++) {
-    StrList acpt_lang_list(false);
-    HttpCompat::parse_comma_list(&acpt_lang_list, test_cases[i].accept_charset,
-                                 static_cast<int>(strlen(test_cases[i].accept_charset)));
-
-    Q = HttpCompat::match_accept_charset(test_cases[i].content_charset, static_cast<int>(strlen(test_cases[i].content_charset)),
-                                         &acpt_lang_list, &I);
-
-    if ((Q != test_cases[i].Q) || (I != test_cases[i].I)) {
-      printf("FAILED: (#%d) got { Q = %.3f; I = %d; }, expected { Q = %.3f; I = %d; }, from matching\n  '%s' against '%s'\n", i, Q,
-             I, test_cases[i].Q, test_cases[i].I, test_cases[i].content_charset, test_cases[i].accept_charset);
-      ++failures;
-    }
-  }
-
-  return (failures_to_status("test_accept_charset_match", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_comma_vals()
-{
-  static struct {
-    const char *value;
-    int value_count;
-    struct {
-      int offset;
-      int len;
-    } pieces[4];
-  } tests[] = {
-    {",", 2, {{0, 0}, {1, 0}, {-1, 0}, {-1, 0}}},
-    {"", 1, {{0, 0}, {-1, 0}, {-1, 0}, {-1, 0}}},
-    {" ", 1, {{0, 0}, {-1, 0}, {-1, 0}, {-1, 0}}},
-    {", ", 2, {{0, 0}, {1, 0}, {-1, 0}, {-1, 0}}},
-    {",,", 3, {{0, 0}, {1, 0}, {2, 0}, {-1, 0}}},
-    {" ,", 2, {{0, 0}, {2, 0}, {-1, 0}, {-1, 0}}},
-    {" , ", 2, {{0, 0}, {2, 0}, {-1, 0}, {-1, 0}}},
-    {"a, ", 2, {{0, 1}, {2, 0}, {-1, 0}, {-1, 0}}},
-    {" a, ", 2, {{1, 1}, {3, 0}, {-1, 0}, {-1, 0}}},
-    {" ,a", 2, {{0, 0}, {2, 1}, {-1, 0}, {-1, 0}}},
-    {" , a", 2, {{0, 0}, {3, 1}, {-1, 0}, {-1, 0}}},
-    {"a,a", 2, {{0, 1}, {2, 1}, {-1, 0}, {-1, 0}}},
-    {"foo", 1, {{0, 3}, {-1, 0}, {-1, 0}, {-1, 0}}},
-    {"foo,", 2, {{0, 3}, {4, 0}, {-1, 0}, {-1, 0}}},
-    {"foo, ", 2, {{0, 3}, {4, 0}, {-1, 0}, {-1, 0}}},
-    {"foo, bar", 2, {{0, 3}, {5, 3}, {-1, 0}, {-1, 0}}},
-    {"foo, bar,", 3, {{0, 3}, {5, 3}, {9, 0}, {-1, 0}}},
-    {"foo, bar, ", 3, {{0, 3}, {5, 3}, {9, 0}, {-1, 0}}},
-    {
-      ",foo,bar,",
-      4,
-      {{0, 0}, {1, 3}, {5, 3}, {9, 0}},
-    },
-  };
-
-  bri_box("test_comma_vals");
-
-  HTTPHdr hdr;
-  char field_name[32];
-  int i, j, len, failures, ntests, ncommavals;
-
-  failures = 0;
-  ntests   = sizeof(tests) / sizeof(tests[0]);
-
-  hdr.create(HTTP_TYPE_REQUEST);
-
-  for (i = 0; i < ntests; i++) {
-    snprintf(field_name, sizeof(field_name), "Test%d", i);
-
-    MIMEField *f = hdr.field_create(field_name, static_cast<int>(strlen(field_name)));
-    ink_release_assert(f->m_ptr_value == nullptr);
-
-    hdr.field_attach(f);
-    ink_release_assert(f->m_ptr_value == nullptr);
-
-    hdr.field_value_set(f, tests[i].value, strlen(tests[i].value));
-    ink_release_assert(f->m_ptr_value != tests[i].value); // should be copied
-    ink_release_assert(f->m_len_value == strlen(tests[i].value));
-    ink_release_assert(memcmp(f->m_ptr_value, tests[i].value, f->m_len_value) == 0);
-
-    ncommavals = mime_field_value_get_comma_val_count(f);
-    if (ncommavals != tests[i].value_count) {
-      ++failures;
-      printf("FAILED: test #%d (field value '%s') expected val count %d, got %d\n", i + 1, tests[i].value, tests[i].value_count,
-             ncommavals);
-    }
-
-    for (j = 0; j < tests[i].value_count; j++) {
-      const char *val = mime_field_value_get_comma_val(f, &len, j);
-      int offset      = ((val == nullptr) ? -1 : (val - f->m_ptr_value));
-
-      if ((offset != tests[i].pieces[j].offset) || (len != tests[i].pieces[j].len)) {
-        ++failures;
-        printf("FAILED: test #%d (field value '%s', commaval idx %d) expected [offset %d, len %d], got [offset %d, len %d]\n",
-               i + 1, tests[i].value, j, tests[i].pieces[j].offset, tests[i].pieces[j].len, offset, len);
-      }
-    }
-  }
-
-  hdr.destroy();
-  return (failures_to_status("test_comma_vals", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_set_comma_vals()
-{
-  static struct {
-    const char *old_raw;
-    int idx;
-    const char *slice;
-    const char *new_raw;
-  } tests[] = {
-    {"a,b,c", 0, "fred", "fred, b, c"},
-    {"a,b,c", 1, "fred", "a, fred, c"},
-    {"a,b,c", 2, "fred", "a, b, fred"},
-    {"a,b,c", 3, "fred", "a,b,c"},
-    {"", 0, "", ""},
-    {"", 0, "foo", "foo"},
-    {"", 1, "foo", ""},
-    {" ", 0, "", ""},
-    {" ", 0, "foo", "foo"},
-    {" ", 1, "foo", " "},
-    {",", 0, "foo", "foo, "},
-    {",", 1, "foo", ", foo"},
-    {",,", 0, "foo", "foo, , "},
-    {",,", 1, "foo", ", foo, "},
-    {",,", 2, "foo", ", , foo"},
-    {"foo", 0, "abc", "abc"},
-    {"foo", 1, "abc", "foo"},
-    {"foo", 0, "abc,", "abc,"},
-    {"foo", 0, ",abc", ",abc"},
-    {",,", 1, ",,,", ", ,,,, "},
-    {" a , b , c", 0, "fred", "fred, b, c"},
-    {" a , b , c", 1, "fred", "a, fred, c"},
-    {" a , b , c", 2, "fred", "a, b, fred"},
-    {" a , b , c", 3, "fred", " a , b , c"},
-    {"    a   ,   b ", 0, "fred", "fred, b"},
-    {"    a   ,   b ", 1, "fred", "a, fred"},
-    {"    a   , b ", 1, "fred", "a, fred"},
-    {"    a   ,b ", 1, "fred", "a, fred"},
-    {"a, , , , e, , g,", 0, "fred", "fred, , , , e, , g, "},
-    {"a, , , , e, , g,", 1, "fred", "a, fred, , , e, , g, "},
-    {"a, , , , e, , g,", 2, "fred", "a, , fred, , e, , g, "},
-    {"a, , , , e, , g,", 5, "fred", "a, , , , e, fred, g, "},
-    {"a, , , , e, , g,", 7, "fred", "a, , , , e, , g, fred"},
-    {"a, , , , e, , g,", 8, "fred", "a, , , , e, , g,"},
-    {"a, \"boo,foo\", c", 0, "wawa", "wawa, \"boo,foo\", c"},
-    {"a, \"boo,foo\", c", 1, "wawa", "a, wawa, c"},
-    {"a, \"boo,foo\", c", 2, "wawa", "a, \"boo,foo\", wawa"},
-  };
-
-  bri_box("test_set_comma_vals");
-
-  HTTPHdr hdr;
-  char field_name[32];
-  int i, failures, ntests;
-
-  failures = 0;
-  ntests   = sizeof(tests) / sizeof(tests[0]);
-
-  hdr.create(HTTP_TYPE_REQUEST);
-
-  for (i = 0; i < ntests; i++) {
-    snprintf(field_name, sizeof(field_name), "Test%d", i);
-
-    MIMEField *f = hdr.field_create(field_name, static_cast<int>(strlen(field_name)));
-    hdr.field_value_set(f, tests[i].old_raw, strlen(tests[i].old_raw));
-    mime_field_value_set_comma_val(hdr.m_heap, hdr.m_mime, f, tests[i].idx, tests[i].slice, strlen(tests[i].slice));
-    ink_release_assert(f->m_ptr_value != nullptr);
-
-    if ((f->m_len_value != strlen(tests[i].new_raw)) || (memcmp(f->m_ptr_value, tests[i].new_raw, f->m_len_value) != 0)) {
-      ++failures;
-      printf("FAILED:  test #%d (setting idx %d of '%s' to '%s') expected '%s' len %d, got '%.*s' len %d\n", i + 1, tests[i].idx,
-             tests[i].old_raw, tests[i].slice, tests[i].new_raw, static_cast<int>(strlen(tests[i].new_raw)), f->m_len_value,
-             f->m_ptr_value, f->m_len_value);
-    }
-  }
-
-  hdr.destroy();
-  return (failures_to_status("test_set_comma_vals", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_delete_comma_vals()
-{
-  bri_box("test_delete_comma_vals");
-  rprintf(rtest, "  HdrTest test_delete_comma_vals: TEST NOT IMPLEMENTED\n");
-  return (1);
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_extend_comma_vals()
-{
-  bri_box("test_extend_comma_vals");
-  rprintf(rtest, "  HdrTest test_extend_comma_vals: TEST NOT IMPLEMENTED\n");
-  return (1);
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_insert_comma_vals()
-{
-  bri_box("test_insert_comma_vals");
-  rprintf(rtest, "  HdrTest test_insert_comma_vals: TEST NOT IMPLEMENTED\n");
-  return (1);
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::test_parse_comma_list()
-{
-  static struct {
-    const char *value;
-    int count;
-    struct {
-      int offset;
-      int len;
-    } pieces[3];
-  } tests[] = {
-    {"", 1, {{0, 0}, {-1, 0}, {-1, 0}}},
-    {",", 2, {{0, 0}, {1, 0}, {-1, 0}}},
-    {" ,", 2, {{0, 0}, {2, 0}, {-1, 0}}},
-    {", ", 2, {{0, 0}, {1, 0}, {-1, 0}}},
-    {" , ", 2, {{0, 0}, {2, 0}, {-1, 0}}},
-    {"abc,", 2, {{0, 3}, {4, 0}, {-1, 0}}},
-    {"abc, ", 2, {{0, 3}, {4, 0}, {-1, 0}}},
-    {"", 1, {{0, 0}, {-1, 0}, {-1, 0}}},
-    {" ", 1, {{0, 0}, {-1, 0}, {-1, 0}}},
-    {"  ", 1, {{0, 0}, {-1, 0}, {-1, 0}}},
-    {"a", 1, {{0, 1}, {-1, 0}, {-1, 0}}},
-    {" a", 1, {{1, 1}, {-1, 0}, {-1, 0}}},
-    {"  a  ", 1, {{2, 1}, {-1, 0}, {-1, 0}}},
-    {"abc,defg", 2, {{0, 3}, {4, 4}, {-1, 0}}},
-    {" abc,defg", 2, {{1, 3}, {5, 4}, {-1, 0}}},
-    {" abc, defg", 2, {{1, 3}, {6, 4}, {-1, 0}}},
-    {" abc , defg", 2, {{1, 3}, {7, 4}, {-1, 0}}},
-    {" abc , defg ", 2, {{1, 3}, {7, 4}, {-1, 0}}},
-    {" abc , defg, ", 3, {{1, 3}, {7, 4}, {12, 0}}},
-    {" abc , defg ,", 3, {{1, 3}, {7, 4}, {13, 0}}},
-    {", abc , defg ", 3, {{0, 0}, {2, 3}, {8, 4}}},
-    {" ,abc , defg ", 3, {{0, 0}, {2, 3}, {8, 4}}},
-    {"a,b", 2, {{0, 1}, {2, 1}, {-1, 0}}},
-    {"a,,b", 3, {{0, 1}, {2, 0}, {3, 1}}},
-    {"a, ,b", 3, {{0, 1}, {2, 0}, {4, 1}}},
-    {"a ,,b", 3, {{0, 1}, {3, 0}, {4, 1}}},
-    {",", 2, {{0, 0}, {1, 0}, {-1, 0}}},
-    {" ,", 2, {{0, 0}, {2, 0}, {-1, 0}}},
-    {", ", 2, {{0, 0}, {1, 0}, {-1, 0}}},
-    {" , ", 2, {{0, 0}, {2, 0}, {-1, 0}}},
-    {"a,b,", 3, {{0, 1}, {2, 1}, {4, 0}}},
-    {"a,b, ", 3, {{0, 1}, {2, 1}, {4, 0}}},
-    {"a,b,  ", 3, {{0, 1}, {2, 1}, {4, 0}}},
-    {"a,b,  c", 3, {{0, 1}, {2, 1}, {6, 1}}},
-    {"a,b,  c ", 3, {{0, 1}, {2, 1}, {6, 1}}},
-    {"a,\"b,c\",d", 3, {{0, 1}, {3, 3}, {8, 1}}},
-  };
-
-  bri_box("test_parse_comma_list");
-
-  int i, j, failures, ntests, offset;
-
-  failures = (offset = 0);
-  ntests   = sizeof(tests) / sizeof(tests[0]);
-
-  for (i = 0; i < ntests; i++) {
-    StrList list(false);
-    HttpCompat::parse_comma_list(&list, tests[i].value);
-    if (list.count != tests[i].count) {
-      ++failures;
-      printf("FAILED: test #%d (string '%s') expected list count %d, got %d\n", i + 1, tests[i].value, tests[i].count, list.count);
-    }
-
-    for (j = 0; j < tests[i].count; j++) {
-      Str *cell = list.get_idx(j);
-      if (cell != nullptr) {
-        offset = cell->str - tests[i].value;
-      }
-
-      if (tests[i].pieces[j].offset == -1) // should not have a piece
-      {
-        if (cell != nullptr) {
-          ++failures;
-          printf("FAILED: test #%d (string '%s', idx %d) expected NULL piece, got [offset %d len %d]\n", i + 1, tests[i].value, j,
-                 offset, static_cast<int>(cell->len));
-        }
-      } else // should have a piece
-      {
-        if (cell == nullptr) {
-          ++failures;
-          printf("FAILED: test #%d (string '%s', idx %d) expected [offset %d len %d], got NULL piece\n", i + 1, tests[i].value, j,
-                 tests[i].pieces[j].offset, tests[i].pieces[j].len);
-        } else if ((offset != tests[i].pieces[j].offset) || (cell->len != static_cast<size_t>(tests[i].pieces[j].len))) {
-          ++failures;
-          printf("FAILED: test #%d (string '%s', idx %d) expected [offset %d len %d], got [offset %d len %d]\n", i + 1,
-                 tests[i].value, j, tests[i].pieces[j].offset, tests[i].pieces[j].len, offset, static_cast<int>(cell->len));
-        }
-      }
-    }
-  }
-
-  return (failures_to_status("test_parse_comma_list", failures));
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-void
-HdrTest::bri_box(const char *s)
-{
-  int i, len;
-
-  len = static_cast<int>(strlen(s));
-  printf("\n+-");
-  for (i = 0; i < len; i++) {
-    putchar('-');
-  }
-  printf("-+\n");
-  printf("| %s |\n", s);
-  printf("+-");
-  for (i = 0; i < len; i++) {
-    putchar('-');
-  }
-  printf("-+\n\n");
-}
-
-/*-------------------------------------------------------------------------
-  -------------------------------------------------------------------------*/
-
-int
-HdrTest::failures_to_status(const char *testname, int nfail)
-{
-  rprintf(rtest, "  HdrTest %s: %s\n", testname, ((nfail > 0) ? "FAILED" : "PASSED"));
-  return ((nfail > 0) ? 0 : 1);
-}
diff --git a/proxy/hdrs/HdrTest.h b/proxy/hdrs/HdrTest.h
deleted file mode 100644
index 76128fa..0000000
--- a/proxy/hdrs/HdrTest.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/** @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.
- */
-
-/****************************************************************************
-
-   HdrTest.cc
-
-   Description:
-       Unit test code for sanity checking the header system is functioning
-         properly
-
-
- ****************************************************************************/
-
-#pragma once
-
-#include "tscore/Regression.h"
-
-class HdrTest
-{
-public:
-  RegressionTest *rtest = nullptr;
-
-  HdrTest(){};
-  ~HdrTest(){};
-
-  int go(RegressionTest *t, int atype);
-
-private:
-  int test_http_hdr_print_and_copy();
-  int test_parse_date();
-  int test_format_date();
-  int test_url();
-  int test_arena();
-  int test_regex();
-  int test_accept_language_match();
-  int test_accept_charset_match();
-  int test_comma_vals();
-  int test_set_comma_vals();
-  int test_delete_comma_vals();
-  int test_extend_comma_vals();
-  int test_insert_comma_vals();
-  int test_parse_comma_list();
-  int test_mime();
-  int test_http();
-  int test_http_mutation();
-
-  int test_http_hdr_print_and_copy_aux(int testnum, const char *req, const char *req_tgt, const char *rsp, const char *rsp_tgt);
-  int test_http_hdr_null_char(int testnum, const char *req, const char *req_tgt);
-  int test_http_hdr_ctl_char(int testnum, const char *req, const char *req_tgt);
-  int test_http_hdr_copy_over_aux(int testnum, const char *request, const char *response);
-  int test_http_aux(const char *request, const char *response);
-  int test_http_req_parse_error(const char *request, const char *response);
-  int test_arena_aux(Arena *arena, int len);
-  void bri_box(const char *s);
-  int failures_to_status(const char *testname, int nfail);
-};
diff --git a/proxy/hdrs/Makefile.am b/proxy/hdrs/Makefile.am
index 7067f55..950dd2b 100644
--- a/proxy/hdrs/Makefile.am
+++ b/proxy/hdrs/Makefile.am
@@ -49,12 +49,6 @@ libhdrs_a_SOURCES = \
 	XPACK.cc \
 	XPACK.h
 
-if BUILD_TESTS
-libhdrs_a_SOURCES += \
-	HdrTest.cc \
-	HdrTest.h
-endif
-
 load_http_hdr_SOURCES = \
 	HTTP.h \
 	HdrHeap.h \
diff --git a/proxy/hdrs/unit_tests/test_Hdrs.cc b/proxy/hdrs/unit_tests/test_Hdrs.cc
index a471339..dcbbd83 100644
--- a/proxy/hdrs/unit_tests/test_Hdrs.cc
+++ b/proxy/hdrs/unit_tests/test_Hdrs.cc
@@ -26,13 +26,19 @@
 #include <initializer_list>
 #include <array>
 #include <new>
+#include <cstdio>
+#include <memory>
+
+#include "tscore/Regex.h"
+#include "tscore/ink_time.h"
 
 #include "catch.hpp"
 
 #include "HTTP.h"
+#include "HttpCompat.h"
 
 // replaces test_http_parser_eos_boundary_cases
-TEST_CASE("HdrTest", "[proxy][hdrtest]")
+TEST_CASE("HdrTestHttpParse", "[proxy][hdrtest]")
 {
   struct Test {
     ts::TextView msg;
@@ -115,3 +121,1915 @@ TEST_CASE("MIMEScanner_fragments", "[proxy][mimescanner_fragments]")
 
   REQUIRE(message == output);
 }
+
+namespace
+{
+static const char *
+comp_http_hdr(HTTPHdr *h1, HTTPHdr *h2)
+{
+  int h1_len = h1->length_get();
+  int h2_len = h2->length_get();
+
+  if (h1_len != h2_len) {
+    return "length mismatch";
+  }
+
+  std::unique_ptr<char[]> h1_pbuf(new char[h1_len + 1]);
+  std::unique_ptr<char[]> h2_pbuf(new char[h2_len + 1]);
+
+  int p_index = 0, p_dumpoffset = 0;
+
+  int rval = h1->print(h1_pbuf.get(), h1_len, &p_index, &p_dumpoffset);
+  if (rval != 1) {
+    return "hdr print failed";
+  }
+
+  p_index = p_dumpoffset = 0;
+  rval                   = h2->print(h2_pbuf.get(), h2_len, &p_index, &p_dumpoffset);
+  if (rval != 1) {
+    return "hdr print failed";
+  }
+
+  rval = memcmp(h1_pbuf.get(), h2_pbuf.get(), h1_len);
+
+  if (rval != 0) {
+    return "compare failed";
+  } else {
+    return nullptr;
+  }
+}
+
+int
+test_http_hdr_copy_over_aux(int testnum, const char *request, const char *response)
+{
+  int err;
+  HTTPHdr req_hdr;
+  HTTPHdr resp_hdr;
+  HTTPHdr copy1;
+  HTTPHdr copy2;
+
+  HTTPParser parser;
+  const char *start;
+  const char *end;
+  const char *comp_str = nullptr;
+
+  /*** (1) parse the request string into hdr ***/
+
+  req_hdr.create(HTTP_TYPE_REQUEST);
+
+  start = request;
+  end   = start + strlen(start); // 1 character past end of string
+
+  http_parser_init(&parser);
+
+  while (true) {
+    err = req_hdr.parse_req(&parser, &start, end, true);
+    if (err != PARSE_RESULT_CONT) {
+      break;
+    }
+  }
+
+  if (err == PARSE_RESULT_ERROR) {
+    std::printf("FAILED: (test #%d) parse error parsing request hdr\n", testnum);
+    return (0);
+  }
+  http_parser_clear(&parser);
+
+  /*** (2) parse the response string into hdr ***/
+
+  resp_hdr.create(HTTP_TYPE_RESPONSE);
+
+  start = response;
+  end   = start + strlen(start); // 1 character past end of string
+
+  http_parser_init(&parser);
+
+  while (true) {
+    err = resp_hdr.parse_resp(&parser, &start, end, true);
+    if (err != PARSE_RESULT_CONT) {
+      break;
+    }
+  }
+
+  if (err == PARSE_RESULT_ERROR) {
+    printf("FAILED: (test #%d) parse error parsing response hdr\n", testnum);
+    return (0);
+  }
+
+  /*** (3) Basic copy testing ***/
+  copy1.create(HTTP_TYPE_REQUEST);
+  copy1.copy(&req_hdr);
+  comp_str = comp_http_hdr(&req_hdr, &copy1);
+  if (comp_str) {
+    goto done;
+  }
+
+  copy2.create(HTTP_TYPE_RESPONSE);
+  copy2.copy(&resp_hdr);
+  comp_str = comp_http_hdr(&resp_hdr, &copy2);
+  if (comp_str) {
+    goto done;
+  }
+
+  // The APIs for copying headers uses memcpy() which can be unsafe for
+  // overlapping memory areas. It's unclear to me why these tests were
+  // created in the first place honestly, since nothing else does this.
+
+  /*** (4) Gender bending copying ***/
+  copy1.copy(&resp_hdr);
+  comp_str = comp_http_hdr(&resp_hdr, &copy1);
+  if (comp_str) {
+    goto done;
+  }
+
+  copy2.copy(&req_hdr);
+  comp_str = comp_http_hdr(&req_hdr, &copy2);
+  if (comp_str) {
+    goto done;
+  }
+
+done:
+  req_hdr.destroy();
+  resp_hdr.destroy();
+  copy1.destroy();
+  copy2.destroy();
+
+  if (comp_str) {
+    printf("FAILED: (test #%d) copy & compare: %s\n", testnum, comp_str);
+    printf("REQ:\n[%.*s]\n", static_cast<int>(strlen(request)), request);
+    printf("RESP  :\n[%.*s]\n", static_cast<int>(strlen(response)), response);
+    return (0);
+  } else {
+    return (1);
+  }
+}
+
+int
+test_http_hdr_null_char(int testnum, const char *request, const char * /*request_tgt*/)
+{
+  int err;
+  HTTPHdr hdr;
+  HTTPParser parser;
+  const char *start;
+  char cpy_buf[2048];
+  const char *cpy_buf_ptr = cpy_buf;
+
+  /*** (1) parse the request string into hdr ***/
+
+  hdr.create(HTTP_TYPE_REQUEST);
+
+  start = request;
+
+  if (strlen(start) > sizeof(cpy_buf)) {
+    std::printf("FAILED: (test #%d) Internal buffer too small for null char test\n", testnum);
+    return (0);
+  }
+  strcpy(cpy_buf, start);
+
+  // Put a null character somewhere in the header
+  int length          = strlen(start);
+  cpy_buf[length / 2] = '\0';
+  http_parser_init(&parser);
+
+  while (true) {
+    err = hdr.parse_req(&parser, &cpy_buf_ptr, cpy_buf_ptr + length, true);
+    if (err != PARSE_RESULT_CONT) {
+      break;
+    }
+  }
+  if (err != PARSE_RESULT_ERROR) {
+    std::printf("FAILED: (test #%d) no parse error parsing request with null char\n", testnum);
+    return (0);
+  }
+  return 1;
+}
+
+int
+test_http_hdr_ctl_char(int testnum, const char *request, const char * /*request_tgt */)
+{
+  int err;
+  HTTPHdr hdr;
+  HTTPParser parser;
+  const char *start;
+  char cpy_buf[2048];
+  const char *cpy_buf_ptr = cpy_buf;
+
+  /*** (1) parse the request string into hdr ***/
+
+  hdr.create(HTTP_TYPE_REQUEST);
+
+  start = request;
+
+  if (strlen(start) > sizeof(cpy_buf)) {
+    std::printf("FAILED: (test #%d) Internal buffer too small for ctl char test\n", testnum);
+    return (0);
+  }
+  strcpy(cpy_buf, start);
+
+  // Replace a character in the method
+  cpy_buf[1] = 16;
+
+  http_parser_init(&parser);
+
+  while (true) {
+    err = hdr.parse_req(&parser, &cpy_buf_ptr, cpy_buf_ptr + strlen(start), true);
+    if (err != PARSE_RESULT_CONT) {
+      break;
+    }
+  }
+
+  if (err != PARSE_RESULT_ERROR) {
+    std::printf("FAILED: (test #%d) no parse error parsing method with ctl char\n", testnum);
+    return (0);
+  }
+  return 1;
+}
+
+int
+test_http_hdr_print_and_copy_aux(int testnum, const char *request, const char *request_tgt, const char *response,
+                                 const char *response_tgt)
+{
+  int err;
+  HTTPHdr hdr;
+  HTTPParser parser;
+  const char *start;
+  const char *end;
+
+  char prt_buf[2048];
+  int prt_bufsize = sizeof(prt_buf);
+  int prt_bufindex, prt_dumpoffset, prt_ret;
+
+  char cpy_buf[2048];
+  int cpy_bufsize = sizeof(cpy_buf);
+  int cpy_bufindex, cpy_dumpoffset, cpy_ret;
+
+  std::unique_ptr<char[]> marshal_buf(new char[2048]);
+  int marshal_bufsize = sizeof(cpy_buf);
+
+  /*** (1) parse the request string into hdr ***/
+
+  hdr.create(HTTP_TYPE_REQUEST);
+
+  start = request;
+  end   = start + strlen(start); // 1 character past end of string
+
+  http_parser_init(&parser);
+
+  while (true) {
+    err = hdr.parse_req(&parser, &start, end, true);
+    if (err != PARSE_RESULT_CONT) {
+      break;
+    }
+  }
+
+  if (err == PARSE_RESULT_ERROR) {
+    std::printf("FAILED: (test #%d) parse error parsing request hdr\n", testnum);
+    return (0);
+  }
+
+  /*** (2) copy the request header ***/
+  HTTPHdr new_hdr, marshal_hdr;
+  RefCountObj ref;
+
+  // Pretend to pin this object with a refcount.
+  ref.refcount_inc();
+
+  int marshal_len = hdr.m_heap->marshal(marshal_buf.get(), marshal_bufsize);
+  marshal_hdr.create(HTTP_TYPE_REQUEST);
+  marshal_hdr.unmarshal(marshal_buf.get(), marshal_len, &ref);
+  new_hdr.create(HTTP_TYPE_REQUEST);
+  new_hdr.copy(&marshal_hdr);
+
+  /*** (3) print the request header and copy to buffers ***/
+
+  prt_bufindex = prt_dumpoffset = 0;
+  prt_ret                       = hdr.print(prt_buf, prt_bufsize, &prt_bufindex, &prt_dumpoffset);
+
+  cpy_bufindex = cpy_dumpoffset = 0;
+  cpy_ret                       = new_hdr.print(cpy_buf, cpy_bufsize, &cpy_bufindex, &cpy_dumpoffset);
+
+  if ((prt_ret != 1) || (cpy_ret != 1)) {
+    std::printf("FAILED: (test #%d) couldn't print req hdr or copy --- prt_ret=%d, cpy_ret=%d\n", testnum, prt_ret, cpy_ret);
+    return (0);
+  }
+
+  if ((static_cast<size_t>(prt_bufindex) != strlen(request_tgt)) || (static_cast<size_t>(cpy_bufindex) != strlen(request_tgt))) {
+    std::printf("FAILED: (test #%d) print req output size mismatch --- tgt=%d, prt_bufsize=%d, cpy_bufsize=%d\n", testnum,
+                static_cast<int>(strlen(request_tgt)), prt_bufindex, cpy_bufindex);
+
+    std::printf("ORIGINAL:\n[%.*s]\n", static_cast<int>(strlen(request)), request);
+    std::printf("TARGET  :\n[%.*s]\n", static_cast<int>(strlen(request_tgt)), request_tgt);
+    std::printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
+    std::printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
+    return (0);
+  }
+
+  if ((strncasecmp(request_tgt, prt_buf, strlen(request_tgt)) != 0) ||
+      (strncasecmp(request_tgt, cpy_buf, strlen(request_tgt)) != 0)) {
+    std::printf("FAILED: (test #%d) print req output mismatch\n", testnum);
+    std::printf("ORIGINAL:\n[%.*s]\n", static_cast<int>(strlen(request)), request);
+    std::printf("TARGET  :\n[%.*s]\n", static_cast<int>(strlen(request_tgt)), request_tgt);
+    std::printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
+    std::printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
+    return (0);
+  }
+
+  hdr.destroy();
+  new_hdr.destroy();
+
+  /*** (4) parse the response string into hdr ***/
+
+  hdr.create(HTTP_TYPE_RESPONSE);
+
+  start = response;
+  end   = start + strlen(start); // 1 character past end of string
+
+  http_parser_init(&parser);
+
+  while (true) {
+    err = hdr.parse_resp(&parser, &start, end, true);
+    if (err != PARSE_RESULT_CONT) {
+      break;
+    }
+  }
+
+  if (err == PARSE_RESULT_ERROR) {
+    std::printf("FAILED: (test #%d) parse error parsing response hdr\n", testnum);
+    return (0);
+  }
+
+  /*** (2) copy the response header ***/
+
+  new_hdr.create(HTTP_TYPE_RESPONSE);
+  new_hdr.copy(&hdr);
+
+  /*** (3) print the response header and copy to buffers ***/
+
+  prt_bufindex = prt_dumpoffset = 0;
+  prt_ret                       = hdr.print(prt_buf, prt_bufsize, &prt_bufindex, &prt_dumpoffset);
+
+  cpy_bufindex = cpy_dumpoffset = 0;
+  cpy_ret                       = new_hdr.print(cpy_buf, cpy_bufsize, &cpy_bufindex, &cpy_dumpoffset);
+
+  if ((prt_ret != 1) || (cpy_ret != 1)) {
+    std::printf("FAILED: (test #%d) couldn't print rsp hdr or copy --- prt_ret=%d, cpy_ret=%d\n", testnum, prt_ret, cpy_ret);
+    return (0);
+  }
+
+  if ((static_cast<size_t>(prt_bufindex) != strlen(response_tgt)) || (static_cast<size_t>(cpy_bufindex) != strlen(response_tgt))) {
+    std::printf("FAILED: (test #%d) print rsp output size mismatch --- tgt=%d, prt_bufsize=%d, cpy_bufsize=%d\n", testnum,
+                static_cast<int>(strlen(response_tgt)), prt_bufindex, cpy_bufindex);
+    std::printf("ORIGINAL:\n[%.*s]\n", static_cast<int>(strlen(response)), response);
+    std::printf("TARGET  :\n[%.*s]\n", static_cast<int>(strlen(response_tgt)), response_tgt);
+    std::printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
+    std::printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
+    return (0);
+  }
+
+  if ((strncasecmp(response_tgt, prt_buf, strlen(response_tgt)) != 0) ||
+      (strncasecmp(response_tgt, cpy_buf, strlen(response_tgt)) != 0)) {
+    std::printf("FAILED: (test #%d) print rsp output mismatch\n", testnum);
+    std::printf("ORIGINAL:\n[%.*s]\n", static_cast<int>(strlen(response)), response);
+    std::printf("TARGET  :\n[%.*s]\n", static_cast<int>(strlen(response_tgt)), response_tgt);
+    std::printf("PRT_BUFF:\n[%.*s]\n", prt_bufindex, prt_buf);
+    std::printf("CPY_BUFF:\n[%.*s]\n", cpy_bufindex, cpy_buf);
+    return (0);
+  }
+
+  hdr.destroy();
+  new_hdr.destroy();
+
+  if (test_http_hdr_copy_over_aux(testnum, request, response) == 0) {
+    return 0;
+  }
+
+  return (1);
+}
+
+int
+test_arena_aux(Arena *arena, int len)
+{
+  char *str      = arena->str_alloc(len);
+  int verify_len = static_cast<int>(arena->str_length(str));
+
+  if (len != verify_len) {
+    std::printf("FAILED: requested %d, got %d bytes\n", len, verify_len);
+    return (1); // 1 error (different return convention)
+  } else {
+    return (0); // no errors (different return convention)
+  }
+}
+
+} // end anonymous namespace
+
+TEST_CASE("HdrTest", "[proxy][hdrtest]")
+{
+  hdrtoken_init();
+  url_init();
+  mime_init();
+  http_init();
+
+  SECTION("Test parse date")
+  {
+    static struct {
+      const char *fast;
+      const char *slow;
+    } dates[] = {
+      {"Sun, 06 Nov 1994 08:49:37 GMT", "Sunday, 06-Nov-1994 08:49:37 GMT"},
+      {"Mon, 07 Nov 1994 08:49:37 GMT", "Monday, 07-Nov-1994 08:49:37 GMT"},
+      {"Tue, 08 Nov 1994 08:49:37 GMT", "Tuesday, 08-Nov-1994 08:49:37 GMT"},
+      {"Wed, 09 Nov 1994 08:49:37 GMT", "Wednesday, 09-Nov-1994 08:49:37 GMT"},
+      {"Thu, 10 Nov 1994 08:49:37 GMT", "Thursday, 10-Nov-1994 08:49:37 GMT"},
+      {"Fri, 11 Nov 1994 08:49:37 GMT", "Friday, 11-Nov-1994 08:49:37 GMT"},
+      {"Sat, 11 Nov 1994 08:49:37 GMT", "Saturday, 11-Nov-1994 08:49:37 GMT"},
+      {"Sun, 03 Jan 1999 08:49:37 GMT", "Sunday, 03-Jan-1999 08:49:37 GMT"},
+      {"Sun, 07 Feb 1999 08:49:37 GMT", "Sunday, 07-Feb-1999 08:49:37 GMT"},
+      {"Sun, 07 Mar 1999 08:49:37 GMT", "Sunday, 07-Mar-1999 08:49:37 GMT"},
+      {"Sun, 04 Apr 1999 08:49:37 GMT", "Sunday, 04-Apr-1999 08:49:37 GMT"},
+      {"Sun, 02 May 1999 08:49:37 GMT", "Sunday, 02-May-1999 08:49:37 GMT"},
+      {"Sun, 06 Jun 1999 08:49:37 GMT", "Sunday, 06-Jun-1999 08:49:37 GMT"},
+      {"Sun, 04 Jul 1999 08:49:37 GMT", "Sunday, 04-Jul-1999 08:49:37 GMT"},
+      {"Sun, 01 Aug 1999 08:49:37 GMT", "Sunday, 01-Aug-1999 08:49:37 GMT"},
+      {"Sun, 05 Sep 1999 08:49:37 GMT", "Sunday, 05-Sep-1999 08:49:37 GMT"},
+      {"Sun, 03 Oct 1999 08:49:37 GMT", "Sunday, 03-Oct-1999 08:49:37 GMT"},
+      {"Sun, 07 Nov 1999 08:49:37 GMT", "Sunday, 07-Nov-1999 08:49:37 GMT"},
+      {"Sun, 05 Dec 1999 08:49:37 GMT", "Sunday, 05-Dec-1999 08:49:37 GMT"},
+      {nullptr, nullptr},
+    };
+
+    int i;
+    time_t fast_t, slow_t;
+
+    for (i = 0; dates[i].fast; i++) {
+      fast_t = mime_parse_date(dates[i].fast, dates[i].fast + static_cast<int>(strlen(dates[i].fast)));
+      slow_t = mime_parse_date(dates[i].slow, dates[i].slow + static_cast<int>(strlen(dates[i].slow)));
+      // compare with strptime here!
+      if (fast_t != slow_t) {
+        std::printf("FAILED: date %lu (%s) != %lu (%s)\n", static_cast<unsigned long>(fast_t), dates[i].fast,
+                    static_cast<unsigned long>(slow_t), dates[i].slow);
+        CHECK(false);
+      }
+    }
+  }
+
+  SECTION("Test format date")
+  {
+    static const char *dates[] = {
+      "Sun, 06 Nov 1994 08:49:37 GMT",
+      "Sun, 03 Jan 1999 08:49:37 GMT",
+      "Sun, 05 Dec 1999 08:49:37 GMT",
+      "Tue, 25 Apr 2000 20:29:53 GMT",
+      nullptr,
+    };
+
+    // (1) Test a few hand-created dates
+
+    int i;
+    time_t t, t2, t3;
+    char buffer[128], buffer2[128];
+    static const char *envstr = "TZ=GMT0";
+
+    // shift into GMT timezone for cftime conversions
+    putenv(const_cast<char *>(envstr));
+    tzset();
+
+    for (i = 0; dates[i]; i++) {
+      t = mime_parse_date(dates[i], dates[i] + static_cast<int>(strlen(dates[i])));
+
+      cftime_replacement(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", &t);
+      if (memcmp(dates[i], buffer, 29) != 0) {
+        std::printf("FAILED: original date doesn't match cftime date\n");
+        std::printf("  input date:  %s\n", dates[i]);
+        std::printf("  cftime date: %s\n", buffer);
+        CHECK(false);
+      }
+
+      mime_format_date(buffer, t);
+      if (memcmp(dates[i], buffer, 29) != 0) {
+        std::printf("FAILED: original date doesn't match mime_format_date date\n");
+        std::printf("  input date:  %s\n", dates[i]);
+        std::printf("  cftime date: %s\n", buffer);
+        CHECK(false);
+      }
+    }
+
+    // (2) test a few times per day from 1/1/1970 to past 2010
+
+    // coverity[dont_call]
+    for (t = 0; t < 40 * 366 * (24 * 60 * 60); t += static_cast<int>(drand48() * (24 * 60 * 60))) {
+      cftime_replacement(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", &t);
+      t2 = mime_parse_date(buffer, buffer + static_cast<int>(strlen(buffer)));
+      if (t2 != t) {
+        std::printf("FAILED: parsed time_t doesn't match original time_t\n");
+        std::printf("  input time_t:  %d (%s)\n", static_cast<int>(t), buffer);
+        std::printf("  parsed time_t: %d\n", static_cast<int>(t2));
+        CHECK(false);
+      }
+      mime_format_date(buffer2, t);
+      if (memcmp(buffer, buffer2, 29) != 0) {
+        std::printf("FAILED: formatted date doesn't match original date\n");
+        std::printf("  original date:  %s\n", buffer);
+        std::printf("  formatted date: %s\n", buffer2);
+        CHECK(false);
+      }
+      t3 = mime_parse_date(buffer2, buffer2 + static_cast<int>(strlen(buffer2)));
+      if (t != t3) {
+        std::printf("FAILED: parsed time_t doesn't match original time_t\n");
+        std::printf("  input time_t:  %d (%s)\n", static_cast<int>(t), buffer2);
+        std::printf("  parsed time_t: %d\n", static_cast<int>(t3));
+        CHECK(false);
+      }
+    }
+  }
+
+  SECTION("Test url")
+  {
+    static const char *strs[] = {
+      "http://some.place/path;params?query#fragment",
+
+      // Start with an easy one...
+      "http://trafficserver.apache.org/index.html",
+
+      "cheese://bogosity",
+
+      "some.place",
+      "some.place/",
+      "http://some.place",
+      "http://some.place/",
+      "http://some.place/path",
+      "http://some.place/path;params",
+      "http://some.place/path;params?query",
+      "http://some.place/path;params?query#fragment",
+      "http://some.place/path?query#fragment",
+      "http://some.place/path#fragment",
+
+      "some.place:80",
+      "some.place:80/",
+      "http://some.place:80",
+      "http://some.place:80/",
+
+      "foo@some.place:80",
+      "foo@some.place:80/",
+      "http://foo@some.place:80",
+      "http://foo@some.place:80/",
+
+      "foo:bar@some.place:80",
+      "foo:bar@some.place:80/",
+      "http://foo:bar@some.place:80",
+      "http://foo:bar@some.place:80/",
+
+      // Some address stuff
+      "http://172.16.28.101",
+      "http://172.16.28.101:8080",
+      "http://[::]",
+      "http://[::1]",
+      "http://[fc01:172:16:28::101]",
+      "http://[fc01:172:16:28::101]:80",
+      "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]",
+      "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080",
+      "http://172.16.28.101/some/path",
+      "http://172.16.28.101:8080/some/path",
+      "http://[::1]/some/path",
+      "http://[fc01:172:16:28::101]/some/path",
+      "http://[fc01:172:16:28::101]:80/some/path",
+      "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]/some/path",
+      "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080/some/path",
+      "http://172.16.28.101/",
+      "http://[fc01:172:16:28:BAAD:BEEF:DEAD:101]:8080/",
+
+      // "foo:@some.place", TODO - foo:@some.place is change to foo@some.place in the test
+      "foo:bar@some.place",
+      "foo:bar@some.place/",
+      "http://foo:bar@some.place",
+      "http://foo:bar@some.place/",
+      "http://foo:bar@[::1]:8080/",
+      "http://foo@[::1]",
+
+      "mms://sm02.tsqa.example.com/0102rally.asf",
+      "pnm://foo:bar@some.place:80/path;params?query#fragment",
+      "rtsp://foo:bar@some.place:80/path;params?query#fragment",
+      "rtspu://foo:bar@some.place:80/path;params?query#fragment",
+      "/finance/external/cbsm/*http://cbs.marketwatch.com/archive/19990713/news/current/net.htx?source=blq/yhoo&dist=yhoo",
+      "http://a.b.com/xx.jpg?newpath=http://bob.dave.com",
+
+      "ht-tp://a.b.com",
+      "ht+tp://a.b.com",
+      "ht.tp://a.b.com",
+
+      "h1ttp://a.b.com",
+      "http1://a.b.com",
+    };
+
+    static const char *bad[] = {
+      "http://[1:2:3:4:5:6:7:8:9]",
+      "http://1:2:3:4:5:6:7:8:A:B",
+      "http://bob.com[::1]",
+      "http://[::1].com",
+
+      "http://foo:bar:baz@bob.com/",
+      "http://foo:bar:baz@[::1]:8080/",
+
+      "http://]",
+      "http://:",
+
+      "http:/",
+      "http:/foo.bar.com/",
+      "~http://invalid.char.in.scheme/foo",
+      "http~://invalid.char.in.scheme/foo",
+      "ht~tp://invalid.char.in.scheme/foo",
+      "1http://first.char.not.alpha",
+      "some.domain.com/http://invalid.domain/foo",
+      ":",
+      "://",
+
+      // maybe this should be a valid URL
+      "a.b.com/xx.jpg?newpath=http://bob.dave.com",
+    };
+
+    int err, failed = 0;
+    URL url;
+    const char *start;
+    const char *end;
+    int old_length, new_length;
+
+    for (unsigned i = 0; i < countof(strs); i++) {
+      old_length = static_cast<int>(strlen(strs[i]));
+      start      = strs[i];
+      end        = start + old_length;
+
+      url.create(nullptr);
+      err = url.parse(&start, end);
+      if (err < 0) {
+        std::printf("Failed to parse url '%s'\n", start);
+        failed = 1;
+        break;
+      }
+
+      char print_buf[1024];
+      new_length = 0;
+      int offset = 0;
+      url.print(print_buf, 1024, &new_length, &offset);
+      print_buf[new_length] = '\0';
+
+      const char *fail_text = nullptr;
+
+      if (old_length == new_length) {
+        if (memcmp(print_buf, strs[i], new_length) != 0) {
+          fail_text = "URLS DIFFER";
+        }
+      } else if (old_length == new_length - 1) {
+        // Check to see if the difference is the trailing
+        //   slash we add
+        if (memcmp(print_buf, strs[i], old_length) != 0 || print_buf[new_length - 1] != '/' || (strs[i])[old_length - 1] == '/') {
+          fail_text = "TRAILING SLASH";
+        }
+      } else {
+        fail_text = "LENGTHS DIFFER";
+      }
+
+      if (fail_text) {
+        failed = 1;
+        std::printf("%16s: OLD: (%4d) %s\n", fail_text, old_length, strs[i]);
+        std::printf("%16s: NEW: (%4d) %s\n", "", new_length, print_buf);
+        obj_describe(url.m_url_impl, true);
+      } else {
+        std::printf("%16s: '%s'\n", "PARSE SUCCESS", strs[i]);
+      }
+
+      url.destroy();
+    }
+
+    for (unsigned i = 0; i < countof(bad); ++i) {
+      const char *x = bad[i];
+
+      url.create(nullptr);
+      err = url.parse(x, strlen(x));
+      url.destroy();
+      if (err == PARSE_RESULT_DONE) {
+        failed = 1;
+        std::printf("Successfully parsed invalid url '%s'", x);
+        break;
+      } else {
+        std::printf("   bad URL - PARSE FAILED: '%s'\n", bad[i]);
+      }
+    }
+
+    CHECK(failed == 0);
+  }
+
+  SECTION("Test mime")
+  {
+    // This can not be a static string (any more) since we unfold the headers
+    // in place.
+    char mime[] = {
+      //        "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n"
+      "Date: 6 Nov 1994 08:49:37 GMT\r\n"
+      "Max-Forwards: 65535\r\n"
+      "Cache-Control: private\r\n"
+      "accept: foo\r\n"
+      "accept: bar\n"
+      ": (null) field name\r\n"
+      "aCCept: \n"
+      "ACCEPT\r\n"
+      "foo: bar\r\n"
+      "foo: argh\r\n"
+      "foo: three, four\r\n"
+      "word word: word \r\n"
+      "accept: \"fazzle, dazzle\"\r\n"
+      "accept: 1, 2, 3, 4, 5, 6, 7, 8\r\n"
+      "continuation: part1\r\n"
+      " part2\r\n"
+      "scooby: doo\r\n"
+      " scooby: doo\r\n"
+      "bar: foo\r\n"
+      "\r\n",
+    };
+
+    int err;
+    MIMEHdr hdr;
+    MIMEParser parser;
+    const char *start;
+    const char *end;
+
+    std::printf("   <<< MUST BE HAND-VERIFIED FOR FULL-BENEFIT>>>\n\n");
+
+    start = mime;
+    end   = start + strlen(start);
+
+    mime_parser_init(&parser);
+
+    bool must_copy_strs = false;
+
+    hdr.create(nullptr);
+    err = hdr.parse(&parser, &start, end, must_copy_strs, false);
+
+    REQUIRE(err >= 0);
+
+    // Test the (new) continuation line folding to be correct. This should replace the
+    // \r\n with two spaces (so a total of three between "part1" and "part2").
+    int length               = 0;
+    const char *continuation = hdr.value_get("continuation", 12, &length);
+
+    if ((13 != length)) {
+      std::printf("FAILED: continue header folded line was too short\n");
+      REQUIRE(false);
+    }
+
+    if (strncmp(continuation + 5, "   ", 3)) {
+      std::printf("FAILED: continue header unfolding did not produce correct WS's\n");
+      REQUIRE(false);
+    }
+
+    if (strncmp(continuation, "part1   part2", 13)) {
+      std::printf("FAILED: continue header unfolding was not correct\n");
+      REQUIRE(false);
+    }
+
+    hdr.field_delete("not_there", 9);
+    hdr.field_delete("accept", 6);
+    hdr.field_delete("scooby", 6);
+    hdr.field_delete("scooby", 6);
+    hdr.field_delete("bar", 3);
+    hdr.field_delete("continuation", 12);
+
+    int count = hdr.fields_count();
+    std::printf("hdr.fields_count() = %d\n", count);
+
+    int i_max_forwards = hdr.value_get_int("Max-Forwards", 12);
+    int u_max_forwards = hdr.value_get_uint("Max-Forwards", 12);
+    std::printf("i_max_forwards = %d   u_max_forwards = %d\n", i_max_forwards, u_max_forwards);
+
+    hdr.set_age(9999);
+
+    length = hdr.length_get();
+    std::printf("hdr.length_get() = %d\n", length);
+
+    time_t t0, t1, t2;
+
+    t0 = hdr.get_date();
+    if (t0 == 0) {
+      std::printf("FAILED: Initial date is zero but shouldn't be\n");
+      REQUIRE(false);
+    }
+
+    t1 = time(nullptr);
+    hdr.set_date(t1);
+    t2 = hdr.get_date();
+    if (t1 != t2) {
+      std::printf("FAILED: set_date(%" PRId64 ") ... get_date = %" PRId64 "\n\n", static_cast<int64_t>(t1),
+                  static_cast<int64_t>(t2));
+      REQUIRE(false);
+    }
+
+    hdr.value_append("Cache-Control", 13, "no-cache", 8, true);
+
+    MIMEField *cc_field;
+    StrList slist;
+
+    cc_field = hdr.field_find("Cache-Control", 13);
+
+    if (cc_field == nullptr) {
+      std::printf("FAILED: missing Cache-Control header\n\n");
+      REQUIRE(false);
+    }
+
+    // TODO: Do we need to check the "count" returned?
+    cc_field->value_get_comma_list(&slist); // FIX: correct usage?
+
+    if (cc_field->value_get_index("Private", 7) < 0) {
+      std::printf("Failed: value_get_index of Cache-Control did not find private");
+      REQUIRE(false);
+    }
+    if (cc_field->value_get_index("Bogus", 5) >= 0) {
+      std::printf("Failed: value_get_index of Cache-Control incorrectly found bogus");
+      REQUIRE(false);
+    }
+    if (hdr.value_get_index("foo", 3, "three", 5) < 0) {
+      std::printf("Failed: value_get_index of foo did not find three");
+      REQUIRE(false);
+    }
+    if (hdr.value_get_index("foo", 3, "bar", 3) < 0) {
+      std::printf("Failed: value_get_index of foo did not find bar");
+      REQUIRE(false);
+    }
+    if (hdr.value_get_index("foo", 3, "Bogus", 5) >= 0) {
+      std::printf("Failed: value_get_index of foo incorrectly found bogus");
+      REQUIRE(false);
+    }
+
+    mime_parser_clear(&parser);
+
+    hdr.print(nullptr, 0, nullptr, nullptr);
+    std::printf("\n");
+
+    obj_describe((HdrHeapObjImpl *)(hdr.m_mime), true);
+
+    const char *field_name = "Test_heap_reuse";
+
+    MIMEField *f = hdr.field_create(field_name, static_cast<int>(strlen(field_name)));
+    REQUIRE(f->m_ptr_value == nullptr);
+
+    hdr.field_attach(f);
+    REQUIRE(f->m_ptr_value == nullptr);
+
+    const char *test_value = "mytest";
+
+    std::printf("Testing Heap Reuse..\n");
+    hdr.field_value_set(f, "orig_value", strlen("orig_value"));
+    const char *m_ptr_value_orig = f->m_ptr_value;
+    hdr.field_value_set(f, test_value, strlen(test_value), true);
+    REQUIRE(f->m_ptr_value != test_value);       // should be copied
+    REQUIRE(f->m_ptr_value == m_ptr_value_orig); // heap doesn't change
+    REQUIRE(f->m_len_value == strlen(test_value));
+    REQUIRE(memcmp(f->m_ptr_value, test_value, f->m_len_value) == 0);
+
+    m_ptr_value_orig           = f->m_ptr_value;
+    const char *new_test_value = "myTest";
+    hdr.field_value_set(f, new_test_value, strlen(new_test_value), false);
+    REQUIRE(f->m_ptr_value != new_test_value);   // should be copied
+    REQUIRE(f->m_ptr_value != m_ptr_value_orig); // new heap
+    REQUIRE(f->m_len_value == strlen(new_test_value));
+    REQUIRE(memcmp(f->m_ptr_value, new_test_value, f->m_len_value) == 0);
+
+    hdr.fields_clear();
+
+    hdr.destroy();
+  }
+
+  SECTION("Test http hdr print and copy")
+  {
+    static struct {
+      const char *req;
+      const char *req_tgt;
+      const char *rsp;
+      const char *rsp_tgt;
+    } tests[] = {
+      {"GET http://foo.com/bar.txt HTTP/1.0\r\n"
+       "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa\r\n"
+       "\r\n",
+       "GET http://foo.com/bar.txt HTTP/1.0\r\n"
+       "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "\r\n"},
+      {"GET http://foo.com/bar.txt HTTP/1.0\r\n"
+       "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj "
+       "klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda \r\n"
+       "\r\n",
+       "GET http://foo.com/bar.txt HTTP/1.0\r\n"
+       "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj "
+       "klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda \r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "\r\n"},
+      {"GET http://foo.com/bar.txt HTTP/1.0\r\n"
+       "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj "
+       "klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda kfl; fsdajfl; "
+       "sdjafl;dsajlsjfl;sdafjsdal;fjds al;fdjslaf ;slajdk;f\r\n"
+       "\r\n",
+       "GET http://foo.com/bar.txt HTTP/1.0\r\n"
+       "Accept-Language: fjdfjdslkf dsjkfdj flkdsfjlk sjfdlk ajfdlksa fjfj dslkfjdslk fjsdafkl dsajfkldsa jfkldsafj "
+       "klsafjs lkafjdsalk fsdjakfl sdjaflkdsaj flksdjflsd ;ffd salfdjs lf;sdaf ;dsaf jdsal;fdjsaflkjsda kfl; fsdajfl; "
+       "sdjafl;dsajlsjfl;sdafjsdal;fjds al;fdjslaf ;slajdk;f\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "\r\n"},
+      {"GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+       "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+       "Referer: chocolate fribble\r\n", // missing final CRLF
+       "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+       "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+       "Referer: chocolate fribble\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "MIME-Version: 1.0\r\n"
+       "Server: WebSTAR/2.1 ID/30013\r\n"
+       "Content-Type: text/html\r\n"
+       "Content-Length: 939\r\n"
+       "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n", // missing final CRLF
+       "HTTP/1.0 200 OK\r\n"
+       "MIME-Version: 1.0\r\n"
+       "Server: WebSTAR/2.1 ID/30013\r\n"
+       "Content-Type: text/html\r\n"
+       "Content-Length: 939\r\n"
+       "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
+       "\r\n"},
+      {"GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+       "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+       "Referer: \r\n", // missing final CRLF
+       "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+       "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+       "Referer: \r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "MIME-Version: 1.0\r\n"
+       "Server: WebSTAR/2.1 ID/30013\r\n"
+       "Content-Type: text/html\r\n"
+       "Content-Length: 939\r\n"
+       "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "MIME-Version: 1.0\r\n"
+       "Server: WebSTAR/2.1 ID/30013\r\n"
+       "Content-Type: text/html\r\n"
+       "Content-Length: 939\r\n"
+       "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
+       "\r\n"},
+      {"GET http://www.news.com:80/ HTTP/1.0\r\n"
+       "Proxy-Connection: Keep-Alive\r\n"
+       "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
+       "Pragma: no-cache\r\n"
+       "Host: www.news.com\r\n"
+       "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
+       "Accept-Language: en\r\n"
+       "Accept-Charset: iso-8859-1, *, utf-8\r\n"
+       "Client-ip: D1012148\r\n"
+       "Foo: abcdefghijklmnopqrtu\r\n"
+       "\r\n",
+       "GET http://www.news.com:80/ HTTP/1.0\r\n"
+       "Proxy-Connection: Keep-Alive\r\n"
+       "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
+       "Pragma: no-cache\r\n"
+       "Host: www.news.com\r\n"
+       "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
+       "Accept-Language: en\r\n"
+       "Accept-Charset: iso-8859-1, *, utf-8\r\n"
+       "Client-ip: D1012148\r\n"
+       "Foo: abcdefghijklmnopqrtu\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "Content-Length: 16428\r\n"
+       "Content-Type: text/html\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "Content-Length: 16428\r\n"
+       "Content-Type: text/html\r\n"
+       "\r\n"},
+      {"GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+       "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+       "Referer: http://people.netscape.com/jwz/index.html\r\n"
+       "Proxy-Connection: Keep-Alive\r\n"
+       "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
+       "Pragma: no-cache\r\n"
+       "Host: people.netscape.com\r\n"
+       "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
+       "\r\n",
+       "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+       "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+       "Referer: http://people.netscape.com/jwz/index.html\r\n"
+       "Proxy-Connection: Keep-Alive\r\n"
+       "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
+       "Pragma: no-cache\r\n"
+       "Host: people.netscape.com\r\n"
+       "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "Content-Length: 16428\r\n"
+       "Content-Type: text/html\r\n"
+       "\r\n",
+       "HTTP/1.0 200 OK\r\n"
+       "Content-Length: 16428\r\n"
+       "Content-Type: text/html\r\n"
+       "\r\n"},
+    };
+
+    int ntests = sizeof(tests) / sizeof(tests[0]);
+    int i;
+
+    for (i = 0; i < ntests; i++) {
+      int status = test_http_hdr_print_and_copy_aux(i + 1, tests[i].req, tests[i].req_tgt, tests[i].rsp, tests[i].rsp_tgt);
+      CHECK(status != 0);
+
+      // Test for expected failures
+      // parse with a '\0' in the header.  Should fail
+      status = test_http_hdr_null_char(i + 1, tests[i].req, tests[i].req_tgt);
+      CHECK(status != 0);
+
+      // Parse with a CTL character in the method name.  Should fail
+      status = test_http_hdr_ctl_char(i + 1, tests[i].req, tests[i].req_tgt);
+      CHECK(status != 0);
+    }
+  }
+
+  SECTION("Test http")
+  {
+    static const char request0[] = {
+      "GET http://www.news.com:80/ HTTP/1.0\r\n"
+      "Proxy-Connection: Keep-Alive\r\n"
+      "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
+      "Pragma: no-cache\r\n"
+      "Host: www.news.com\r\n"
+      "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, image/png, */*\r\n"
+      "Accept-Language: en\r\n"
+      "Accept-Charset: iso-8859-1, *, utf-8\r\n"
+      "Cookie: u_vid_0_0=00031ba3; "
+      "s_cur_0_0=0101sisi091314775496e7d3Jx4+POyJakrMybmNOsq6XOn5bVn5Z6a4Ln5crU5M7Rxq2lm5aWpqupo20=; "
+      "SC_Cnet001=Sampled; SC_Cnet002=Sampled\r\n"
+      "Client-ip: D1012148\r\n"
+      "Foo: abcdefghijklmnopqrtu\r\n"
+      "\r\n",
+    };
+
+    static const char request09[] = {
+      "GET /index.html\r\n"
+      "\r\n",
+    };
+
+    static const char request1[] = {
+      "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+      "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+      "Referer: http://people.netscape.com/jwz/index.html\r\n"
+      "Proxy-Connection: Keep-Alive\r\n"
+      "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
+      "Pragma: no-cache\r\n"
+      "Host: people.netscape.com\r\n"
+      "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
+      "\r\n",
+    };
+
+    static const char request_no_colon[] = {
+      "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+      "If-Modified-Since Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+      "Referer http://people.netscape.com/jwz/index.html\r\n"
+      "Proxy-Connection Keep-Alive\r\n"
+      "User-Agent  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
+      "Pragma no-cache\r\n"
+      "Host people.netscape.com\r\n"
+      "Accept image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
+      "\r\n",
+    };
+
+    static const char request_no_val[] = {
+      "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+      "If-Modified-Since:\r\n"
+      "Referer:     "
+      "Proxy-Connection:\r\n"
+      "User-Agent:     \r\n"
+      "Host:::\r\n"
+      "\r\n",
+    };
+
+    static const char request_multi_fblock[] = {
+      "GET http://people.netscape.com/jwz/hacks-1.gif HTTP/1.0\r\n"
+      "If-Modified-Since: Wednesday, 26-Feb-97 06:58:17 GMT; length=842\r\n"
+      "Referer: http://people.netscape.com/jwz/index.html\r\n"
+      "Proxy-Connection: Keep-Alive\r\n"
+      "User-Agent:  Mozilla/3.01 (X11; I; Linux 2.0.28 i586)\r\n"
+      "Pragma: no-cache\r\n"
+      "Host: people.netscape.com\r\n"
+      "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*\r\n"
+      "X-1: blah\r\n"
+      "X-2: blah\r\n"
+      "X-3: blah\r\n"
+      "X-4: blah\r\n"
+      "X-5: blah\r\n"
+      "X-6: blah\r\n"
+      "X-7: blah\r\n"
+      "X-8: blah\r\n"
+      "X-9: blah\r\n"
+      "Pragma: no-cache\r\n"
+      "X-X-1: blah\r\n"
+      "X-X-2: blah\r\n"
+      "X-X-3: blah\r\n"
+      "X-X-4: blah\r\n"
+      "X-X-5: blah\r\n"
+      "X-X-6: blah\r\n"
+      "X-X-7: blah\r\n"
+      "X-X-8: blah\r\n"
+      "X-X-9: blah\r\n"
+      "\r\n",
+    };
+
+    static const char request_leading_space[] = {
+      " GET http://www.news.com:80/ HTTP/1.0\r\n"
+      "Proxy-Connection: Keep-Alive\r\n"
+      "User-Agent: Mozilla/4.04 [en] (X11; I; Linux 2.0.33 i586)\r\n"
+      "\r\n",
+    };
+
+    static const char request_padding[] = {
+      "GET http://www.padding.com:80/ HTTP/1.0\r\n"
+      "X-1: blah1\r\n"
+      //       "X-2:  blah2\r\n"
+      "X-3:   blah3\r\n"
+      //       "X-4:    blah4\r\n"
+      "X-5:     blah5\r\n"
+      //       "X-6:      blah6\r\n"
+      "X-7:       blah7\r\n"
+      //       "X-8:        blah8\r\n"
+      "X-9:         blah9\r\n"
+      "\r\n",
+    };
+
+    static const char request_09p[] = {
+      "GET http://www.news09.com/\r\n"
+      "\r\n",
+    };
+
+    static const char request_09ht[] = {
+      "GET http://www.news09.com/ HT\r\n"
+      "\r\n",
+    };
+
+    static const char request_11[] = {
+      "GET http://www.news.com/ HTTP/1.1\r\n"
+      "Connection: close\r\n"
+      "\r\n",
+    };
+
+    static const char request_too_long[] = {
+      "GET http://www.news.com/i/am/too/long HTTP/1.1\r\n"
+      "Connection: close\r\n"
+      "\r\n",
+    };
+
+    static const char request_unterminated[] = {
+      "GET http://www.unterminated.com/ HTTP/1.1",
+    };
+
+    static const char request_blank[] = {
+      "\r\n",
+    };
+
+    static const char request_blank2[] = {
+      "\r\n"
+      "\r\n",
+    };
+
+    static const char request_blank3[] = {
+      "     "
+      "\r\n",
+    };
+
+    ////////////////////////////////////////////////////
+
+    static const char response0[] = {
+      "HTTP/1.0 200 OK\r\n"
+      "MIME-Version: 1.0\r\n"
+      "Server: WebSTAR/2.1 ID/30013\r\n"
+      "Content-Type: text/html\r\n"
+      "Content-Length: 939\r\n"
+      "Last-Modified: Thursday, 01-Jan-04 05:00:00 GMT\r\n"
+      "\r\n",
+    };
+
+    static const char response1[] = {
+      "HTTP/1.0 200 OK\r\n"
+      "Server: Netscape-Communications/1.12\r\n"
+      "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n"
+      "Content-Type: text/html\r\n"
+      "\r\n",
+    };
+
+    static const char response_no_colon[] = {
+      "HTTP/1.0 200 OK\r\n"
+      "Server Netscape-Communications/1.12\r\n"
+      "Date: Tuesday, 08-Dec-98 20:32:17 GMT\r\n"
+      "Content-Type: text/html\r\n"
+      "\r\n",
+    };
+
+    static const char response_unterminated[] = {
+      "HTTP/1.0 200 OK",
+    };
+
+    static const char response09[] = {
+      "",
+    };
+
+    static const char response_blank[] = {
+      "\r\n",
+    };
+
+    static const char response_blank2[] = {
+      "\r\n"
+      "\r\n",
+    };
+
+    static const char response_blank3[] = {
+      "     "
+      "\r\n",
+    };
+
+    static const char response_too_long_req[] = {
+      "HTTP/1.0 414 URI Too Long\r\n"
+      "\r\n",
+    };
+
+    struct RequestResponse {
+      char const *request;
+      char const *response;
+    };
+
+    RequestResponse rr[] = {{request0, response0},
+                            {request09, response09},
+                            {request1, response1},
+                            {request_no_colon, response_no_colon},
+                            {request_no_val, response_no_colon},
+                            {request_leading_space, response0},
+                            {request_multi_fblock, response0},
+                            {request_padding, response0},
+                            {request_09p, response0},
+                            {request_09ht, response0},
+                            {request_11, response0},
+                            {request_unterminated, response_unterminated},
+                            {request_blank, response_blank},
+                            {request_blank2, response_blank2},
+                            {request_blank3, response_blank3}};
+
+    int err;
+    HTTPHdr req_hdr, rsp_hdr;
+    HTTPParser parser;
+    const char *start;
+    const char *end;
+    const char *request;
+    const char *response;
+
+    for (unsigned idx = 0; idx < (sizeof(rr) / sizeof(*rr)); ++idx) {
+      request  = rr[idx].request;
+      response = rr[idx].response;
+
+      std::printf("   <<< MUST BE HAND-VERIFIED FOR FULL BENEFIT >>>\n\n");
+
+      /*** (1) parse the request string into req_hdr ***/
+
+      start = request;
+      end   = start + strlen(start); // 1 character past end of string
+
+      http_parser_init(&parser);
+
+      req_hdr.create(HTTP_TYPE_REQUEST);
+      rsp_hdr.create(HTTP_TYPE_RESPONSE);
+
+      std::printf("======== parsing\n\n");
+      while (true) {
+        err = req_hdr.parse_req(&parser, &start, end, true);
+        if (err != PARSE_RESULT_CONT) {
+          break;
+        }
+      }
+      if (err == PARSE_RESULT_ERROR) {
+        req_hdr.destroy();
+        rsp_hdr.destroy();
+        break;
+      }
+
+      /*** useless copy to exercise copy function ***/
+
+      HTTPHdr new_hdr;
+      new_hdr.create(HTTP_TYPE_REQUEST);
+      new_hdr.copy(&req_hdr);
+      new_hdr.destroy();
+
+      /*** (2) print out the request ***/
+
+      std::printf("======== real request (length=%d)\n\n", static_cast<int>(strlen(request)));
+      std::printf("%s\n", request);
+
+      std::printf("\n[");
+      req_hdr.print(nullptr, 0, nullptr, nullptr);
+      std::printf("]\n\n");
+
+      obj_describe(req_hdr.m_http, true);
+
+      // req_hdr.destroy ();
+      // REQUIRE(!"req_hdr.destroy() not defined");
+
+      /*** (3) parse the response string into rsp_hdr ***/
+
+      start = response;
+      end   = start + strlen(start);
+
+      http_parser_clear(&parser);
+      http_parser_init(&parser);
+
+      while (true) {
+        err = rsp_hdr.parse_resp(&parser, &start, end, true);
+        if (err != PARSE_RESULT_CONT) {
+          break;
+        }
+      }
+      if (err == PARSE_RESULT_ERROR) {
+        req_hdr.destroy();
+        rsp_hdr.destroy();
+        break;
+      }
+
+      http_parser_clear(&parser);
+
+      /*** (4) print out the response ***/
+
+      std::printf("\n======== real response (length=%d)\n\n", static_cast<int>(strlen(response)));
+      std::printf("%s\n", response);
+
+      std::printf("\n[");
+      rsp_hdr.print(nullptr, 0, nullptr, nullptr);
+      std::printf("]\n\n");
+
+      obj_describe(rsp_hdr.m_http, true);
+
+      const int NNN = 1000;
+      {
+        char buf[NNN];
+        int bufindex, last_bufindex;
+        int tmp;
+        int i;
+
+        bufindex = 0;
+
+        do {
+          last_bufindex = bufindex;
+          tmp           = bufindex;
+          buf[0]        = '#'; // make it obvious if hdr.print doesn't print anything
+          err           = rsp_hdr.print(buf, NNN, &bufindex, &tmp);
+
+          // std::printf("test_header: tmp = %d  err = %d  bufindex = %d\n", tmp, err, bufindex);
+          putchar('{');
+          for (i = 0; i < bufindex - last_bufindex; i++) {
+            if (!iscntrl(buf[i])) {
+              putchar(buf[i]);
+            } else {
+              std::printf("\\%o", buf[i]);
+            }
+          }
+          putchar('}');
+        } while (!err);
+      }
+
+      // rsp_hdr.print (NULL, 0, NULL, NULL);
+
+      req_hdr.destroy();
+      rsp_hdr.destroy();
+    }
+
+    {
+      request  = request_too_long;
+      response = response_too_long_req;
+
+      int status = 1;
+
+      /*** (1) parse the request string into req_hdr ***/
+
+      start = request;
+      end   = start + strlen(start); // 1 character past end of string
+
+      http_parser_init(&parser);
+
+      req_hdr.create(HTTP_TYPE_REQUEST);
+      rsp_hdr.create(HTTP_TYPE_RESPONSE);
+
+      std::printf("======== test_http_req_parse_error parsing\n\n");
+      err = req_hdr.parse_req(&parser, &start, end, true, true, 1);
+      if (err != PARSE_RESULT_ERROR) {
+        status = 0;
+      }
+
+      http_parser_clear(&parser);
+
+      /*** (4) print out the response ***/
+
+      std::printf("\n======== real response (length=%d)\n\n", static_cast<int>(strlen(response)));
+      std::printf("%s\n", response);
+
+      obj_describe(rsp_hdr.m_http, true);
+
+      req_hdr.destroy();
+      rsp_hdr.destroy();
+
+      CHECK(status != 0);
+    }
+  }
+
+  SECTION("Test http mutation")
+  {
+    std::printf("   <<< MUST BE HAND-VERIFIED FOR FULL BENEFIT>>>\n\n");
+
+    HTTPHdr resp_hdr;
+    int err, i;
+    HTTPParser parser;
+    const char base_resp[] = "HTTP/1.0 200 OK\r\n\r\n";
+    const char *start, *end;
+
+    /*** (1) parse the response string into req_hdr ***/
+
+    start = base_resp;
+    end   = start + strlen(start);
+
+    http_parser_init(&parser);
+
+    resp_hdr.create(HTTP_TYPE_RESPONSE);
+
+    while (true) {
+      err = resp_hdr.parse_resp(&parser, &start, end, true);
+      if (err != PARSE_RESULT_CONT) {
+        break;
+      }
+    }
+
+    std::printf("\n======== before mutation ==========\n\n");
+    std::printf("\n[");
+    resp_hdr.print(nullptr, 0, nullptr, nullptr);
+    std::printf("]\n\n");
+
+    /*** (2) add in a bunch of header fields ****/
+    char field_name[1024];
+    char field_value[1024];
+    for (i = 1; i <= 100; i++) {
+      snprintf(field_name, sizeof(field_name), "Test%d", i);
+      snprintf(field_value, sizeof(field_value), "%d %d %d %d %d", i, i, i, i, i);
+      resp_hdr.value_set(field_name, static_cast<int>(strlen(field_name)), field_value, static_cast<int>(strlen(field_value)));
+    }
+
+    /**** (3) delete all the even numbered fields *****/
+    for (i = 2; i <= 100; i += 2) {
+      snprintf(field_name, sizeof(field_name), "Test%d", i);
+      resp_hdr.field_delete(field_name, static_cast<int>(strlen(field_name)));
+    }
+
+    /***** (4) add in secondary fields for all multiples of 3 ***/
+    for (i = 3; i <= 100; i += 3) {
+      snprintf(field_name, sizeof(field_name), "Test%d", i);
+      MIMEField *f = resp_hdr.field_create(field_name, static_cast<int>(strlen(field_name)));
+      resp_hdr.field_attach(f);
+      snprintf(field_value, sizeof(field_value), "d %d %d %d %d %d", i, i, i, i, i);
+      f->value_set(resp_hdr.m_heap, resp_hdr.m_mime, field_value, static_cast<int>(strlen(field_value)));
+    }
+
+    /***** (5) append all fields with multiples of 5 ***/
+    for (i = 5; i <= 100; i += 5) {
+      snprintf(field_name, sizeof(field_name), "Test%d", i);
+      snprintf(field_value, sizeof(field_value), "a %d", i);
+
+      resp_hdr.value_append(field_name, static_cast<int>(strlen(field_name)), field_value, static_cast<int>(strlen(field_value)),
+                            true);
+    }
+
+    /**** (6) delete all multiples of nine *****/
+    for (i = 9; i <= 100; i += 9) {
+      snprintf(field_name, sizeof(field_name), "Test%d", i);
+      resp_hdr.field_delete(field_name, static_cast<int>(strlen(field_name)));
+    }
+
+    std::printf("\n======== mutated response ==========\n\n");
+    std::printf("\n[");
+    resp_hdr.print(nullptr, 0, nullptr, nullptr);
+    std::printf("]\n\n");
+
+    resp_hdr.destroy();
+  }
+
+  SECTION("Test arena")
+  {
+    Arena *arena;
+
+    arena = new Arena;
+
+    CHECK(test_arena_aux(arena, 1) != 1);
+    CHECK(test_arena_aux(arena, 127) != 1);
+    CHECK(test_arena_aux(arena, 128) != 1);
+    CHECK(test_arena_aux(arena, 129) != 1);
+    CHECK(test_arena_aux(arena, 255) != 1);
+    CHECK(test_arena_aux(arena, 256) != 1);
+    CHECK(test_arena_aux(arena, 16384) != 1);
+    CHECK(test_arena_aux(arena, 16385) != 1);
+    CHECK(test_arena_aux(arena, 16511) != 1);
+    CHECK(test_arena_aux(arena, 16512) != 1);
+    CHECK(test_arena_aux(arena, 2097152) != 1);
+    CHECK(test_arena_aux(arena, 2097153) != 1);
+    CHECK(test_arena_aux(arena, 2097279) != 1);
+    CHECK(test_arena_aux(arena, 2097280) != 1);
+
+    delete arena;
+  }
+
+  SECTION("Test regex")
+  {
+    DFA dfa;
+
+    const char *test_harness[] = {"foo", "(.*\\.apache\\.org)", "(.*\\.example\\.com)"};
+
+    dfa.compile(test_harness, SIZEOF(test_harness));
+    CHECK(dfa.match("trafficserver.apache.org") == 1);
+    CHECK(dfa.match("www.example.com") == 2);
+    CHECK(dfa.match("aaaaaafooooooooinktomi....com.org") == -1);
+    CHECK(dfa.match("foo") == 0);
+  }
+
+  SECTION("Test accept language match")
+  {
+    struct {
+      const char *content_language;
+      const char *accept_language;
+      float Q;
+      int L;
+      int I;
+    } test_cases[] = {
+      {"en", "*", 1.0, 1, 1},
+      {"en", "fr", 0.0, 0, 0},
+      {"en", "de, fr, en;q=0.7", 0.7, 2, 3},
+      {"en-cockney", "de, fr, en;q=0.7", 0.7, 2, 3},
+      {"en-cockney", "de, fr, en-foobar;q=0.8, en;q=0.7", 0.7, 2, 4},
+      {"en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.7", 0.8, 10, 3},
+      {"en-cockney", "de, fr, en;q=0.8, en;q=0.7", 0.8, 2, 3},
+      {"en-cockney", "de, fr, en;q=0.7, en;q=0.8", 0.8, 2, 4},
+      {"en-cockney", "de, fr, en;q=0.8, en;q=0.8", 0.8, 2, 3},
+      {"en-cockney", "de, fr, en-cockney;q=0.7, en;q=0.8", 0.7, 10, 3},
+      {"en-cockney", "de, fr, en;q=0.8, en-cockney;q=0.7", 0.7, 10, 4},
+      {"en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.8", 0.8, 10, 3},
+      {"en-cockney", "de, fr, en-cockney;q=0.8, en;q=0.7", 0.8, 10, 3},
+      {"en-cockney", "de, fr, en-american", 0.0, 0, 0},
+      {"en-cockney", "de, fr, en;q=0.8, en;q=0.8, *", 0.8, 2, 3},
+      {"en-cockney", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.8, 2, 3},
+      {"en-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.8, 2, 3},
+      {"oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9", 0.9, 1, 5},
+      {"oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *;q=0.9, *", 1.0, 1, 6},
+      {"oo-foobar", "de, fr, en;q=0.8, en;q=0.8, *, *;q=0.9", 1.0, 1, 5},
+      {"fr-belgian", "de, fr;hi-there;q=0.9, fr;q=0.8, en", 0.9, 2, 2},
+      {"fr-belgian", "de, fr;q=0.8, fr;hi-there;q=0.9, en", 0.9, 2, 3},
+      {nullptr, nullptr, 0.0, 0, 0},
+    };
+
+    int i, I, L;
+    float Q;
+
+    for (i = 0; test_cases[i].accept_language; i++) {
+      StrList acpt_lang_list(false);
+      HttpCompat::parse_comma_list(&acpt_lang_list, test_cases[i].accept_language,
+                                   static_cast<int>(strlen(test_cases[i].accept_language)));
+
+      Q = HttpCompat::match_accept_language(test_cases[i].content_language,
+                                            static_cast<int>(strlen(test_cases[i].content_language)), &acpt_lang_list, &L, &I);
+
+      if ((Q != test_cases[i].Q) || (L != test_cases[i].L) || (I != test_cases[i].I)) {
+        std::printf(
+          "FAILED: (#%d) got { Q = %.3f; L = %d; I = %d; }, expected { Q = %.3f; L = %d; I = %d; }, from matching\n  '%s' "
+          "against '%s'\n",
+          i, Q, L, I, test_cases[i].Q, test_cases[i].L, test_cases[i].I, test_cases[i].content_language,
+          test_cases[i].accept_language);
+        CHECK(false);
+      }
+    }
+  }
+
+  SECTION("Test accept charset match")
+  {
+    struct {
+      const char *content_charset;
+      const char *accept_charset;
+      float Q;
+      int I;
+    } test_cases[] = {
+      {"iso-8859-1", "*", 1.0, 1},
+      {"iso-8859-1", "iso-8859-2", 0.0, 0},
+      {"iso-8859-1", "iso-8859", 0.0, 0},
+      {"iso-8859-1", "iso-8859-12", 0.0, 0},
+      {"iso-8859-1", "koi-8-r", 0.0, 0},
+      {"euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7", 0.7, 3},
+      {"euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7", 0.7, 3},
+      {"euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.8, euc-jp;q=0.7", 0.8, 3},
+      {"euc-jp", "shift_jis, iso-2022-jp, euc-jp;q=0.7, euc-jp;q=0.8", 0.8, 4},
+      {"euc-jp", "euc-jp;q=0.9, shift_jis, iso-2022-jp, euc-jp;q=0.7, euc-jp;q=0.8", 0.9, 1},
+      {"EUC-JP", "euc-jp;q=0.9, shift_jis, iso-2022-jp, euc-jp, euc-jp;q=0.8", 1.0, 4},
+      {"euc-jp", "euc-jp;q=0.9, shift_jis, iso-2022-jp, EUC-JP, euc-jp;q=0.8", 1.0, 4},
+      {"euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar", 0.0, 0},
+      {"euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *", 1.0, 4},
+      {"euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *;q=0.543", 0.543, 4},
+      {"euc-jp", "shift_jis, iso-2022-jp, euc-jp-foobar, *;q=0.0", 0.0, 4},
+      {"euc-jp", "shift_jis, iso-2022-jp, *;q=0.0, euc-jp-foobar, *;q=0.0", 0.0, 3},
+      {"euc-jp", "shift_jis, iso-2022-jp, *;q=0.0, euc-jp-foobar, *;q=0.5", 0.5, 5},
+      {"euc-jp", "shift_jis, iso-2022-jp, *;q=0.5, euc-jp-foobar, *;q=0.0", 0.5, 3},
+      {"euc-jp", "shift_jis, iso-2022-jp, *;q=0.5, euc-jp-foobar, *, *;q=0.0", 1.0, 5},
+      {"euc-jp", "shift_jis, euc-jp;hi-there;q=0.5, iso-2022-jp", 0.5, 2},
+      {"euc-jp", "shift_jis, euc-jp;hi-there;q= 0.5, iso-2022-jp", 0.5, 2},
+      {"euc-jp", "shift_jis, euc-jp;hi-there;q = 0.5, iso-2022-jp", 0.5, 2},
+      {"euc-jp", "shift_jis, euc-jp;hi-there ; q = 0.5, iso-2022-jp", 0.5, 2},
+      {"euc-jp", "shift_jis, euc-jp;hi-there ;; q = 0.5, iso-2022-jp", 0.5, 2},
+      {"euc-jp", "shift_jis, euc-jp;hi-there ;; Q = 0.5, iso-2022-jp", 0.5, 2},
+      {nullptr, nullptr, 0.0, 0},
+    };
+
+    int i, I;
+    float Q;
+
+    for (i = 0; test_cases[i].accept_charset; i++) {
+      StrList acpt_lang_list(false);
+      HttpCompat::parse_comma_list(&acpt_lang_list, test_cases[i].accept_charset,
+                                   static_cast<int>(strlen(test_cases[i].accept_charset)));
+
+      Q = HttpCompat::match_accept_charset(test_cases[i].content_charset, static_cast<int>(strlen(test_cases[i].content_charset)),
+                                           &acpt_lang_list, &I);
+
+      if ((Q != test_cases[i].Q) || (I != test_cases[i].I)) {
+        std::printf("FAILED: (#%d) got { Q = %.3f; I = %d; }, expected { Q = %.3f; I = %d; }, from matching\n  '%s' against '%s'\n",
+                    i, Q, I, test_cases[i].Q, test_cases[i].I, test_cases[i].content_charset, test_cases[i].accept_charset);
+        CHECK(false);
+      }
+    }
+  }
+
+  SECTION("Test comma vals")
+  {
+    static struct {
+      const char *value;
+      int value_count;
+      struct {
+        int offset;
+        int len;
+      } pieces[4];
+    } tests[] = {
+      {",", 2, {{0, 0}, {1, 0}, {-1, 0}, {-1, 0}}},
+      {"", 1, {{0, 0}, {-1, 0}, {-1, 0}, {-1, 0}}},
+      {" ", 1, {{0, 0}, {-1, 0}, {-1, 0}, {-1, 0}}},
+      {", ", 2, {{0, 0}, {1, 0}, {-1, 0}, {-1, 0}}},
+      {",,", 3, {{0, 0}, {1, 0}, {2, 0}, {-1, 0}}},
+      {" ,", 2, {{0, 0}, {2, 0}, {-1, 0}, {-1, 0}}},
+      {" , ", 2, {{0, 0}, {2, 0}, {-1, 0}, {-1, 0}}},
+      {"a, ", 2, {{0, 1}, {2, 0}, {-1, 0}, {-1, 0}}},
+      {" a, ", 2, {{1, 1}, {3, 0}, {-1, 0}, {-1, 0}}},
+      {" ,a", 2, {{0, 0}, {2, 1}, {-1, 0}, {-1, 0}}},
+      {" , a", 2, {{0, 0}, {3, 1}, {-1, 0}, {-1, 0}}},
+      {"a,a", 2, {{0, 1}, {2, 1}, {-1, 0}, {-1, 0}}},
+      {"foo", 1, {{0, 3}, {-1, 0}, {-1, 0}, {-1, 0}}},
+      {"foo,", 2, {{0, 3}, {4, 0}, {-1, 0}, {-1, 0}}},
+      {"foo, ", 2, {{0, 3}, {4, 0}, {-1, 0}, {-1, 0}}},
+      {"foo, bar", 2, {{0, 3}, {5, 3}, {-1, 0}, {-1, 0}}},
+      {"foo, bar,", 3, {{0, 3}, {5, 3}, {9, 0}, {-1, 0}}},
+      {"foo, bar, ", 3, {{0, 3}, {5, 3}, {9, 0}, {-1, 0}}},
+      {
+        ",foo,bar,",
+        4,
+        {{0, 0}, {1, 3}, {5, 3}, {9, 0}},
+      },
+    };
+
+    HTTPHdr hdr;
+    char field_name[32];
+    int i, j, len, ntests, ncommavals;
+
+    ntests = sizeof(tests) / sizeof(tests[0]);
+
+    hdr.create(HTTP_TYPE_REQUEST);
+
+    for (i = 0; i < ntests; i++) {
+      snprintf(field_name, sizeof(field_name), "Test%d", i);
+
+      MIMEField *f = hdr.field_create(field_name, static_cast<int>(strlen(field_name)));
+      REQUIRE(f->m_ptr_value == nullptr);
+
+      hdr.field_attach(f);
+      REQUIRE(f->m_ptr_value == nullptr);
+
+      hdr.field_value_set(f, tests[i].value, strlen(tests[i].value));
+      REQUIRE(f->m_ptr_value != tests[i].value); // should be copied
+      REQUIRE(f->m_len_value == strlen(tests[i].value));
+      REQUIRE(memcmp(f->m_ptr_value, tests[i].value, f->m_len_value) == 0);
+
+      ncommavals = mime_field_value_get_comma_val_count(f);
+      if (ncommavals != tests[i].value_count) {
+        std::printf("FAILED: test #%d (field value '%s') expected val count %d, got %d\n", i + 1, tests[i].value,
+                    tests[i].value_count, ncommavals);
+        CHECK(false);
+      }
+
+      for (j = 0; j < tests[i].value_count; j++) {
+        const char *val = mime_field_value_get_comma_val(f, &len, j);
+        int offset      = ((val == nullptr) ? -1 : (val - f->m_ptr_value));
+
+        if ((offset != tests[i].pieces[j].offset) || (len != tests[i].pieces[j].len)) {
+          std::printf(
+            "FAILED: test #%d (field value '%s', commaval idx %d) expected [offset %d, len %d], got [offset %d, len %d]\n", i + 1,
+            tests[i].value, j, tests[i].pieces[j].offset, tests[i].pieces[j].len, offset, len);
+          CHECK(false);
+        }
+      }
+    }
+
+    hdr.destroy();
+  }
+
+  SECTION("Test set comma vals")
+  {
+    static struct {
+      const char *old_raw;
+      int idx;
+      const char *slice;
+      const char *new_raw;
+    } tests[] = {
+      {"a,b,c", 0, "fred", "fred, b, c"},
+      {"a,b,c", 1, "fred", "a, fred, c"},
+      {"a,b,c", 2, "fred", "a, b, fred"},
+      {"a,b,c", 3, "fred", "a,b,c"},
+      {"", 0, "", ""},
+      {"", 0, "foo", "foo"},
+      {"", 1, "foo", ""},
+      {" ", 0, "", ""},
+      {" ", 0, "foo", "foo"},
+      {" ", 1, "foo", " "},
+      {",", 0, "foo", "foo, "},
+      {",", 1, "foo", ", foo"},
+      {",,", 0, "foo", "foo, , "},
+      {",,", 1, "foo", ", foo, "},
+      {",,", 2, "foo", ", , foo"},
+      {"foo", 0, "abc", "abc"},
+      {"foo", 1, "abc", "foo"},
+      {"foo", 0, "abc,", "abc,"},
+      {"foo", 0, ",abc", ",abc"},
+      {",,", 1, ",,,", ", ,,,, "},
+      {" a , b , c", 0, "fred", "fred, b, c"},
+      {" a , b , c", 1, "fred", "a, fred, c"},
+      {" a , b , c", 2, "fred", "a, b, fred"},
+      {" a , b , c", 3, "fred", " a , b , c"},
+      {"    a   ,   b ", 0, "fred", "fred, b"},
+      {"    a   ,   b ", 1, "fred", "a, fred"},
+      {"    a   , b ", 1, "fred", "a, fred"},
+      {"    a   ,b ", 1, "fred", "a, fred"},
+      {"a, , , , e, , g,", 0, "fred", "fred, , , , e, , g, "},
+      {"a, , , , e, , g,", 1, "fred", "a, fred, , , e, , g, "},
+      {"a, , , , e, , g,", 2, "fred", "a, , fred, , e, , g, "},
+      {"a, , , , e, , g,", 5, "fred", "a, , , , e, fred, g, "},
+      {"a, , , , e, , g,", 7, "fred", "a, , , , e, , g, fred"},
+      {"a, , , , e, , g,", 8, "fred", "a, , , , e, , g,"},
+      {"a, \"boo,foo\", c", 0, "wawa", "wawa, \"boo,foo\", c"},
+      {"a, \"boo,foo\", c", 1, "wawa", "a, wawa, c"},
+      {"a, \"boo,foo\", c", 2, "wawa", "a, \"boo,foo\", wawa"},
+    };
+
+    HTTPHdr hdr;
+    char field_name[32];
+    int i, ntests;
+
+    ntests = sizeof(tests) / sizeof(tests[0]);
+
+    hdr.create(HTTP_TYPE_REQUEST);
+
+    for (i = 0; i < ntests; i++) {
+      snprintf(field_name, sizeof(field_name), "Test%d", i);
+
+      MIMEField *f = hdr.field_create(field_name, static_cast<int>(strlen(field_name)));
+      hdr.field_value_set(f, tests[i].old_raw, strlen(tests[i].old_raw));
+      mime_field_value_set_comma_val(hdr.m_heap, hdr.m_mime, f, tests[i].idx, tests[i].slice, strlen(tests[i].slice));
+      REQUIRE(f->m_ptr_value != nullptr);
+
+      if ((f->m_len_value != strlen(tests[i].new_raw)) || (memcmp(f->m_ptr_value, tests[i].new_raw, f->m_len_value) != 0)) {
+        std::printf("FAILED:  test #%d (setting idx %d of '%s' to '%s') expected '%s' len %d, got '%.*s' len %d\n", i + 1,
+                    tests[i].idx, tests[i].old_raw, tests[i].slice, tests[i].new_raw, static_cast<int>(strlen(tests[i].new_raw)),
+                    f->m_len_value, f->m_ptr_value, f->m_len_value);
+        CHECK(false);
+      }
+    }
+
+    hdr.destroy();
+  }
+
+  SECTION("Test delete comma vals")
+  {
+    // TEST NOT IMPLEMENTED
+  }
+
+  SECTION("Test extend comma vals")
+  {
+    // TEST NOT IMPLEMENTED
+  }
+
+  SECTION("Test insert comma vals")
+  {
+    // TEST NOT IMPLEMENTED
+  }
+
+  SECTION("Test parse comma list")
+  {
+    static struct {
+      const char *value;
+      int count;
+      struct {
+        int offset;
+        int len;
+      } pieces[3];
+    } tests[] = {
+      {"", 1, {{0, 0}, {-1, 0}, {-1, 0}}},
+      {",", 2, {{0, 0}, {1, 0}, {-1, 0}}},
+      {" ,", 2, {{0, 0}, {2, 0}, {-1, 0}}},
+      {", ", 2, {{0, 0}, {1, 0}, {-1, 0}}},
+      {" , ", 2, {{0, 0}, {2, 0}, {-1, 0}}},
+      {"abc,", 2, {{0, 3}, {4, 0}, {-1, 0}}},
+      {"abc, ", 2, {{0, 3}, {4, 0}, {-1, 0}}},
+      {"", 1, {{0, 0}, {-1, 0}, {-1, 0}}},
+      {" ", 1, {{0, 0}, {-1, 0}, {-1, 0}}},
+      {"  ", 1, {{0, 0}, {-1, 0}, {-1, 0}}},
+      {"a", 1, {{0, 1}, {-1, 0}, {-1, 0}}},
+      {" a", 1, {{1, 1}, {-1, 0}, {-1, 0}}},
+      {"  a  ", 1, {{2, 1}, {-1, 0}, {-1, 0}}},
+      {"abc,defg", 2, {{0, 3}, {4, 4}, {-1, 0}}},
+      {" abc,defg", 2, {{1, 3}, {5, 4}, {-1, 0}}},
+      {" abc, defg", 2, {{1, 3}, {6, 4}, {-1, 0}}},
+      {" abc , defg", 2, {{1, 3}, {7, 4}, {-1, 0}}},
+      {" abc , defg ", 2, {{1, 3}, {7, 4}, {-1, 0}}},
+      {" abc , defg, ", 3, {{1, 3}, {7, 4}, {12, 0}}},
+      {" abc , defg ,", 3, {{1, 3}, {7, 4}, {13, 0}}},
+      {", abc , defg ", 3, {{0, 0}, {2, 3}, {8, 4}}},
+      {" ,abc , defg ", 3, {{0, 0}, {2, 3}, {8, 4}}},
+      {"a,b", 2, {{0, 1}, {2, 1}, {-1, 0}}},
+      {"a,,b", 3, {{0, 1}, {2, 0}, {3, 1}}},
+      {"a, ,b", 3, {{0, 1}, {2, 0}, {4, 1}}},
+      {"a ,,b", 3, {{0, 1}, {3, 0}, {4, 1}}},
+      {",", 2, {{0, 0}, {1, 0}, {-1, 0}}},
+      {" ,", 2, {{0, 0}, {2, 0}, {-1, 0}}},
+      {", ", 2, {{0, 0}, {1, 0}, {-1, 0}}},
+      {" , ", 2, {{0, 0}, {2, 0}, {-1, 0}}},
+      {"a,b,", 3, {{0, 1}, {2, 1}, {4, 0}}},
+      {"a,b, ", 3, {{0, 1}, {2, 1}, {4, 0}}},
+      {"a,b,  ", 3, {{0, 1}, {2, 1}, {4, 0}}},
+      {"a,b,  c", 3, {{0, 1}, {2, 1}, {6, 1}}},
+      {"a,b,  c ", 3, {{0, 1}, {2, 1}, {6, 1}}},
+      {"a,\"b,c\",d", 3, {{0, 1}, {3, 3}, {8, 1}}},
+    };
+
+    int i, j, ntests, offset;
+
+    offset = 0;
+    ntests = sizeof(tests) / sizeof(tests[0]);
+
+    for (i = 0; i < ntests; i++) {
+      StrList list(false);
+      HttpCompat::parse_comma_list(&list, tests[i].value);
+      if (list.count != tests[i].count) {
+        std::printf("FAILED: test #%d (string '%s') expected list count %d, got %d\n", i + 1, tests[i].value, tests[i].count,
+                    list.count);
+        CHECK(false);
+      }
+
+      for (j = 0; j < tests[i].count; j++) {
+        Str *cell = list.get_idx(j);
+        if (cell != nullptr) {
+          offset = cell->str - tests[i].value;
+        }
+
+        if (tests[i].pieces[j].offset == -1) // should not have a piece
+        {
+          if (cell != nullptr) {
+            std::printf("FAILED: test #%d (string '%s', idx %d) expected NULL piece, got [offset %d len %d]\n", i + 1,
+                        tests[i].value, j, offset, static_cast<int>(cell->len));
+            CHECK(false);
+          }
+        } else // should have a piece
+        {
+          if (cell == nullptr) {
+            std::printf("FAILED: test #%d (string '%s', idx %d) expected [offset %d len %d], got NULL piece\n", i + 1,
+                        tests[i].value, j, tests[i].pieces[j].offset, tests[i].pieces[j].len);
+            CHECK(false);
+          } else if ((offset != tests[i].pieces[j].offset) || (cell->len != static_cast<size_t>(tests[i].pieces[j].len))) {
+            std::printf("FAILED: test #%d (string '%s', idx %d) expected [offset %d len %d], got [offset %d len %d]\n", i + 1,
+                        tests[i].value, j, tests[i].pieces[j].offset, tests[i].pieces[j].len, offset, static_cast<int>(cell->len));
+            CHECK(false);
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/src/traffic_server/traffic_server.cc b/src/traffic_server/traffic_server.cc
index afb72fc..6153edd 100644
--- a/src/traffic_server/traffic_server.cc
+++ b/src/traffic_server/traffic_server.cc
@@ -2151,21 +2151,6 @@ main(int /* argc ATS_UNUSED */, const char **argv)
   delete main_thread;
 }
 
-#if TS_HAS_TESTS
-//////////////////////////////
-// Unit Regression Test Hook //
-//////////////////////////////
-
-#include "HdrTest.h"
-
-REGRESSION_TEST(Hdrs)(RegressionTest *t, int atype, int *pstatus)
-{
-  HdrTest ht;
-  *pstatus = ht.go(t, atype);
-  return;
-}
-#endif
-
 static void mgmt_restart_shutdown_callback(ts::MemSpan<void>)
 {
   sync_cache_dir_on_shutdown();