trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From masa...@apache.org
Subject [trafficserver] branch master updated: Convert HTTP/2 regression tests to use Catch
Date Sun, 12 Apr 2020 22:58:06 GMT
This is an automated email from the ASF dual-hosted git repository.

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


The following commit(s) were added to refs/heads/master by this push:
     new 3aa3206  Convert HTTP/2 regression tests to use Catch
3aa3206 is described below

commit 3aa32065756928d921a5983f3fdab2052d7d2c39
Author: Masaori Koshiba <masaori@apache.org>
AuthorDate: Fri Apr 3 15:18:27 2020 +0900

    Convert HTTP/2 regression tests to use Catch
---
 proxy/http2/HTTP2.cc                              | 140 ------
 proxy/http2/Makefile.am                           |   6 +-
 proxy/http2/RegressionHPACK.cc                    | 495 ----------------------
 proxy/http2/unit_tests/main.cc                    |  12 +-
 proxy/http2/unit_tests/test_HpackIndexingTable.cc | 487 +++++++++++++++++++++
 proxy/http2/unit_tests/test_Http2Frame.cc         | 121 ++++++
 6 files changed, 620 insertions(+), 641 deletions(-)

diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc
index ec5a5fb..38dafd9 100644
--- a/proxy/http2/HTTP2.cc
+++ b/proxy/http2/HTTP2.cc
@@ -821,143 +821,3 @@ Http2::init()
   RecRegisterRawStat(http2_rsb, RECT_PROCESS, HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE_NAME, RECD_INT, RECP_PERSISTENT,
                      static_cast<int>(HTTP2_STAT_INSUFFICIENT_AVG_WINDOW_UPDATE), RecRawStatSyncSum);
 }
-
-#if TS_HAS_TESTS
-
-void forceLinkRegressionHPACK();
-void
-forceLinkRegressionHPACKCaller()
-{
-  forceLinkRegressionHPACK();
-}
-
-#include "tscore/TestBox.h"
-
-/***********************************************************************************
- *                                                                                 *
- *                       Regression test for HTTP/2                                *
- *                                                                                 *
- ***********************************************************************************/
-
-const static struct {
-  uint8_t ftype;
-  uint8_t fflags;
-  bool valid;
-} http2_frame_flags_test_case[] = {{HTTP2_FRAME_TYPE_DATA, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_DATA, 0x01, true},
-                                   {HTTP2_FRAME_TYPE_DATA, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_DATA, 0x04, false},
-                                   {HTTP2_FRAME_TYPE_DATA, 0x08, true},
-                                   {HTTP2_FRAME_TYPE_DATA, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_DATA, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_DATA, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_DATA, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x01, true},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x04, true},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x08, true},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x20, true},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_HEADERS, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x01, false},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x04, false},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x08, false},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_PRIORITY, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x01, false},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x04, false},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x08, false},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_RST_STREAM, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x01, true},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x04, false},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x08, false},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_SETTINGS, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x01, false},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x04, true},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x08, true},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_PING, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_PING, 0x01, true},
-                                   {HTTP2_FRAME_TYPE_PING, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_PING, 0x04, false},
-                                   {HTTP2_FRAME_TYPE_PING, 0x08, false},
-                                   {HTTP2_FRAME_TYPE_PING, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_PING, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_PING, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_PING, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x01, false},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x04, false},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x08, false},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_GOAWAY, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x01, false},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x04, false},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x08, false},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x01, false},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x02, false},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x04, true},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x08, false},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x10, false},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x20, false},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x40, false},
-                                   {HTTP2_FRAME_TYPE_CONTINUATION, 0x80, false},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x00, true},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x01, true},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x02, true},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x04, true},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x08, true},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x10, true},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x20, true},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x40, true},
-                                   {HTTP2_FRAME_TYPE_MAX, 0x80, true}};
-
-static const uint8_t HTTP2_FRAME_FLAGS_MASKS[HTTP2_FRAME_TYPE_MAX] = {
-  HTTP2_FLAGS_DATA_MASK,          HTTP2_FLAGS_HEADERS_MASK,      HTTP2_FLAGS_PRIORITY_MASK, HTTP2_FLAGS_RST_STREAM_MASK,
-  HTTP2_FLAGS_SETTINGS_MASK,      HTTP2_FLAGS_PUSH_PROMISE_MASK, HTTP2_FLAGS_PING_MASK,     HTTP2_FLAGS_GOAWAY_MASK,
-  HTTP2_FLAGS_WINDOW_UPDATE_MASK, HTTP2_FLAGS_CONTINUATION_MASK,
-};
-
-REGRESSION_TEST(HTTP2_FRAME_FLAGS)(RegressionTest *t, int, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  for (auto i : http2_frame_flags_test_case) {
-    box.check((i.ftype >= HTTP2_FRAME_TYPE_MAX || (i.fflags & ~HTTP2_FRAME_FLAGS_MASKS[i.ftype]) == 0) == i.valid,
-              "Validation of frame flags (type: %d, flags: %d) are expected %d, but not", i.ftype, i.fflags, i.valid);
-  }
-}
-
-#endif /* TS_HAS_TESTS */
diff --git a/proxy/http2/Makefile.am b/proxy/http2/Makefile.am
index 0952eef..44a84f9 100644
--- a/proxy/http2/Makefile.am
+++ b/proxy/http2/Makefile.am
@@ -54,11 +54,6 @@ libhttp2_a_SOURCES = \
 	Http2SessionAccept.cc \
 	Http2SessionAccept.h
 
-if BUILD_TESTS
-libhttp2_a_SOURCES += \
-	RegressionHPACK.cc
-endif
-
 check_PROGRAMS = \
 	test_libhttp2 \
 	test_Http2DependencyTree \
@@ -83,6 +78,7 @@ test_libhttp2_CPPFLAGS = $(AM_CPPFLAGS)\
 
 test_libhttp2_SOURCES = \
 	unit_tests/test_Http2Frame.cc \
+	unit_tests/test_HpackIndexingTable.cc \
 	unit_tests/main.cc
 
 test_Http2DependencyTree_LDADD = \
diff --git a/proxy/http2/RegressionHPACK.cc b/proxy/http2/RegressionHPACK.cc
deleted file mode 100644
index 855f0f6..0000000
--- a/proxy/http2/RegressionHPACK.cc
+++ /dev/null
@@ -1,495 +0,0 @@
-/** @file
- *
- *  Regression Tests for HPACK
- *
- *  @section license License
- *
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#include "HPACK.h"
-#include "HuffmanCodec.h"
-#include "tscore/TestBox.h"
-
-// Constants for regression test
-const static int DYNAMIC_TABLE_SIZE_FOR_REGRESSION_TEST = 256;
-const static int BUFSIZE_FOR_REGRESSION_TEST            = 128;
-const static int MAX_TEST_FIELD_NUM                     = 8;
-const static int MAX_REQUEST_HEADER_SIZE                = 131072;
-const static int MAX_TABLE_SIZE                         = 4096;
-
-/***********************************************************************************
- *                                                                                 *
- *                       Regression test for HPACK                                 *
- *                                                                                 *
- *  Some test cases are based on examples of specification.                        *
- *  - https://tools.ietf.org/html/rfc7541#appendix-C                               *
- *                                                                                 *
- ***********************************************************************************/
-
-// [RFC 7541] C.2.4. Indexed Header Field
-const static struct {
-  int index;
-  const char *raw_name;
-  const char *raw_value;
-  const uint8_t *encoded_field;
-  int encoded_field_len;
-} indexed_test_case[] = {{2, (char *)":method", (char *)"GET", reinterpret_cast<const uint8_t *>("\x82"), 1}};
-
-// [RFC 7541] C.2. Header Field Representation Examples
-const static struct {
-  const char *raw_name;
-  const char *raw_value;
-  int index;
-  HpackField type;
-  const uint8_t *encoded_field;
-  int encoded_field_len;
-} literal_test_case[] = {{(char *)"custom-key", (char *)"custom-header", 0, HpackField::INDEXED_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x40\x0a"
-                                                            "custom-key\x0d"
-                                                            "custom-header"),
-                          26},
-                         {(char *)"custom-key", (char *)"custom-header", 0, HpackField::NOINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x00\x0a"
-                                                            "custom-key\x0d"
-                                                            "custom-header"),
-                          26},
-                         {(char *)"custom-key", (char *)"custom-header", 0, HpackField::NEVERINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x10\x0a"
-                                                            "custom-key\x0d"
-                                                            "custom-header"),
-                          26},
-                         {(char *)":path", (char *)"/sample/path", 4, HpackField::INDEXED_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x44\x0c"
-                                                            "/sample/path"),
-                          14},
-                         {(char *)":path", (char *)"/sample/path", 4, HpackField::NOINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x04\x0c"
-                                                            "/sample/path"),
-                          14},
-                         {(char *)":path", (char *)"/sample/path", 4, HpackField::NEVERINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x14\x0c"
-                                                            "/sample/path"),
-                          14},
-                         {(char *)"password", (char *)"secret", 0, HpackField::INDEXED_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x40\x08"
-                                                            "password\x06"
-                                                            "secret"),
-                          17},
-                         {(char *)"password", (char *)"secret", 0, HpackField::NOINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x00\x08"
-                                                            "password\x06"
-                                                            "secret"),
-                          17},
-                         {(char *)"password", (char *)"secret", 0, HpackField::NEVERINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x10\x08"
-                                                            "password\x06"
-                                                            "secret"),
-                          17},
-                         // with Huffman Coding
-                         {(char *)"custom-key", (char *)"custom-header", 0, HpackField::INDEXED_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x40"
-                                                            "\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f"
-                                                            "\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9"),
-                          20},
-                         {(char *)"custom-key", (char *)"custom-header", 0, HpackField::NOINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x00"
-                                                            "\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f"
-                                                            "\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9"),
-                          20},
-                         {(char *)"custom-key", (char *)"custom-header", 0, HpackField::NEVERINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x10"
-                                                            "\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f"
-                                                            "\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9"),
-                          20},
-                         {(char *)":path", (char *)"/sample/path", 4, HpackField::INDEXED_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x44"
-                                                            "\x89\x61\x03\xa6\xba\x0a\xc5\x63\x4c\xff"),
-                          11},
-                         {(char *)":path", (char *)"/sample/path", 4, HpackField::NOINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x04"
-                                                            "\x89\x61\x03\xa6\xba\x0a\xc5\x63\x4c\xff"),
-                          11},
-                         {(char *)":path", (char *)"/sample/path", 4, HpackField::NEVERINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x14"
-                                                            "\x89\x61\x03\xa6\xba\x0a\xc5\x63\x4c\xff"),
-                          11},
-                         {(char *)"password", (char *)"secret", 0, HpackField::INDEXED_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x40"
-                                                            "\x86\xac\x68\x47\x83\xd9\x27"
-                                                            "\x84\x41\x49\x61\x53"),
-                          13},
-                         {(char *)"password", (char *)"secret", 0, HpackField::NOINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x00"
-                                                            "\x86\xac\x68\x47\x83\xd9\x27"
-                                                            "\x84\x41\x49\x61\x53"),
-                          13},
-                         {(char *)"password", (char *)"secret", 0, HpackField::NEVERINDEX_LITERAL,
-                          reinterpret_cast<const uint8_t *>("\x10"
-                                                            "\x86\xac\x68\x47\x83\xd9\x27"
-                                                            "\x84\x41\x49\x61\x53"),
-                          13}};
-
-// [RFC 7541] C.3. Request Examples without Huffman Coding - C.3.1. First Request
-// [RFC 7541] C.4. Request Examples with Huffman Coding - C.4.1. First Request
-const static struct {
-  char *raw_name;
-  char *raw_value;
-} raw_field_request_test_case[][MAX_TEST_FIELD_NUM] = {{
-                                                         {(char *)":method", (char *)"GET"},
-                                                         {(char *)":scheme", (char *)"http"},
-                                                         {(char *)":path", (char *)"/"},
-                                                         {(char *)":authority", (char *)"www.example.com"},
-                                                         {(char *)"", (char *)""} // End of this test case
-                                                       },
-                                                       {
-                                                         {(char *)":method", (char *)"GET"},
-                                                         {(char *)":scheme", (char *)"http"},
-                                                         {(char *)":path", (char *)"/"},
-                                                         {(char *)":authority", (char *)"www.example.com"},
-                                                         {(char *)"", (char *)""} // End of this test case
-                                                       }};
-const static struct {
-  const uint8_t *encoded_field;
-  int encoded_field_len;
-} encoded_field_request_test_case[] = {{reinterpret_cast<const uint8_t *>("\x40"
-                                                                          "\x7:method"
-                                                                          "\x3GET"
-                                                                          "\x40"
-                                                                          "\x7:scheme"
-                                                                          "\x4http"
-                                                                          "\x40"
-                                                                          "\x5:path"
-                                                                          "\x1/"
-                                                                          "\x40"
-                                                                          "\xa:authority"
-                                                                          "\xfwww.example.com"),
-                                        64},
-                                       {reinterpret_cast<const uint8_t *>("\x40"
-                                                                          "\x85\xb9\x49\x53\x39\xe4"
-                                                                          "\x83\xc5\x83\x7f"
-                                                                          "\x40"
-                                                                          "\x85\xb8\x82\x4e\x5a\x4b"
-                                                                          "\x83\x9d\x29\xaf"
-                                                                          "\x40"
-                                                                          "\x84\xb9\x58\xd3\x3f"
-                                                                          "\x81\x63"
-                                                                          "\x40"
-                                                                          "\x88\xb8\x3b\x53\x39\xec\x32\x7d\x7f"
-                                                                          "\x8c\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab\x90\xf4\xff"),
-                                        53}};
-
-// [RFC 7541] C.6. Response Examples with Huffman Coding
-const static struct {
-  char *raw_name;
-  char *raw_value;
-} raw_field_response_test_case[][MAX_TEST_FIELD_NUM] = {
-  {
-    {(char *)":status", (char *)"302"},
-    {(char *)"cache-control", (char *)"private"},
-    {(char *)"date", (char *)"Mon, 21 Oct 2013 20:13:21 GMT"},
-    {(char *)"location", (char *)"https://www.example.com"},
-    {(char *)"", (char *)""} // End of this test case
-  },
-  {
-    {(char *)":status", (char *)"307"},
-    {(char *)"cache-control", (char *)"private"},
-    {(char *)"date", (char *)"Mon, 21 Oct 2013 20:13:21 GMT"},
-    {(char *)"location", (char *)"https://www.example.com"},
-    {(char *)"", (char *)""} // End of this test case
-  },
-  {
-    {(char *)":status", (char *)"200"},
-    {(char *)"cache-control", (char *)"private"},
-    {(char *)"date", (char *)"Mon, 21 Oct 2013 20:13:22 GMT"},
-    {(char *)"location", (char *)"https://www.example.com"},
-    {(char *)"content-encoding", (char *)"gzip"},
-    {(char *)"set-cookie", (char *)"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
-    {(char *)"", (char *)""} // End of this test case
-  }};
-const static struct {
-  const uint8_t *encoded_field;
-  int encoded_field_len;
-} encoded_field_response_test_case[] = {
-  {reinterpret_cast<const uint8_t *>("\x48\x82"
-                                     "\x64\x02"
-                                     "\x58\x85"
-                                     "\xae\xc3\x77\x1a\x4b"
-                                     "\x61\x96"
-                                     "\xd0\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20\x05\x95\x04\x0b\x81\x66"
-                                     "\xe0\x82\xa6\x2d\x1b\xff"
-                                     "\x6e\x91"
-                                     "\x9d\x29\xad\x17\x18\x63\xc7\x8f\x0b\x97\xc8\xe9\xae\x82\xae\x43"
-                                     "\xd3"),
-   54},
-  {reinterpret_cast<const uint8_t *>("\x48\x83"
-                                     "\x64\x0e\xff"
-                                     "\xc1"
-                                     "\xc0"
-                                     "\xbf"),
-   8},
-  {reinterpret_cast<const uint8_t *>("\x88"
-                                     "\xc1"
-                                     "\x61\x96"
-                                     "\xd0\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20\x05\x95\x04\x0b\x81\x66"
-                                     "\xe0\x84\xa6\x2d\x1b\xff"
-                                     "\xc0"
-                                     "\x5a\x83"
-                                     "\x9b\xd9\xab"
-                                     "\x77\xad"
-                                     "\x94\xe7\x82\x1d\xd7\xf2\xe6\xc7\xb3\x35\xdf\xdf\xcd\x5b\x39\x60"
-                                     "\xd5\xaf\x27\x08\x7f\x36\x72\xc1\xab\x27\x0f\xb5\x29\x1f\x95\x87"
-                                     "\x31\x60\x65\xc0\x03\xed\x4e\xe5\xb1\x06\x3d\x50\x07"),
-   79}};
-const static struct {
-  uint32_t size;
-  char *name;
-  char *value;
-} dynamic_table_response_test_case[][MAX_TEST_FIELD_NUM] = {
-  {
-    {63, (char *)"location", (char *)"https://www.example.com"},
-    {65, (char *)"date", (char *)"Mon, 21 Oct 2013 20:13:21 GMT"},
-    {52, (char *)"cache-control", (char *)"private"},
-    {42, (char *)":status", (char *)"302"},
-    {0, (char *)"", (char *)""} // End of this test case
-  },
-  {
-    {42, (char *)":status", (char *)"307"},
-    {63, (char *)"location", (char *)"https://www.example.com"},
-    {65, (char *)"date", (char *)"Mon, 21 Oct 2013 20:13:21 GMT"},
-    {52, (char *)"cache-control", (char *)"private"},
-    {0, (char *)"", (char *)""} // End of this test case
-  },
-  {
-    {98, (char *)"set-cookie", (char *)"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
-    {52, (char *)"content-encoding", (char *)"gzip"},
-    {65, (char *)"date", (char *)"Mon, 21 Oct 2013 20:13:22 GMT"},
-    {0, (char *)"", (char *)""} // End of this test case
-  }};
-
-/***********************************************************************************
- *                                                                                 *
- *                                Regression test codes                            *
- *                                                                                 *
- ***********************************************************************************/
-
-REGRESSION_TEST(HPACK_EncodeIndexedHeaderField)(RegressionTest *t, int, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
-
-  for (const auto &i : indexed_test_case) {
-    memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
-
-    int len = encode_indexed_header_field(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, i.index);
-
-    box.check(len == i.encoded_field_len, "encoded length was %d, expecting %d", len, i.encoded_field_len);
-    box.check(len > 0 && memcmp(buf, i.encoded_field, len) == 0, "encoded value was invalid");
-  }
-}
-
-REGRESSION_TEST(HPACK_EncodeLiteralHeaderField)(RegressionTest *t, int, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
-  int len;
-  HpackIndexingTable indexing_table(4096);
-
-  for (unsigned int i = 9; i < sizeof(literal_test_case) / sizeof(literal_test_case[0]); i++) {
-    memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
-
-    ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
-    headers->create(HTTP_TYPE_RESPONSE);
-    MIMEField *field = mime_field_create(headers->m_heap, headers->m_http->m_fields_impl);
-    MIMEFieldWrapper header(field, headers->m_heap, headers->m_http->m_fields_impl);
-
-    header.name_set(literal_test_case[i].raw_name, strlen(literal_test_case[i].raw_name));
-    header.value_set(literal_test_case[i].raw_value, strlen(literal_test_case[i].raw_value));
-    if (literal_test_case[i].index > 0) {
-      len = encode_literal_header_field_with_indexed_name(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, header,
-                                                          literal_test_case[i].index, indexing_table, literal_test_case[i].type);
-    } else {
-      header.name_set(literal_test_case[i].raw_name, strlen(literal_test_case[i].raw_name));
-      len = encode_literal_header_field_with_new_name(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, header, indexing_table,
-                                                      literal_test_case[i].type);
-    }
-
-    box.check(len == literal_test_case[i].encoded_field_len, "encoded length was %d, expecting %d", len,
-              literal_test_case[i].encoded_field_len);
-    box.check(len > 0 && memcmp(buf, literal_test_case[i].encoded_field, len) == 0, "encoded value was invalid");
-  }
-}
-
-REGRESSION_TEST(HPACK_Encode)(RegressionTest *t, int, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
-  HpackIndexingTable indexing_table(4096);
-  indexing_table.update_maximum_size(DYNAMIC_TABLE_SIZE_FOR_REGRESSION_TEST);
-
-  for (unsigned int i = 0; i < sizeof(encoded_field_response_test_case) / sizeof(encoded_field_response_test_case[0]); i++) {
-    ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
-    headers->create(HTTP_TYPE_RESPONSE);
-
-    for (unsigned int j = 0; j < sizeof(raw_field_response_test_case[i]) / sizeof(raw_field_response_test_case[i][0]); j++) {
-      const char *expected_name  = raw_field_response_test_case[i][j].raw_name;
-      const char *expected_value = raw_field_response_test_case[i][j].raw_value;
-      if (strlen(expected_name) == 0) {
-        break;
-      }
-
-      MIMEField *field = mime_field_create(headers->m_heap, headers->m_http->m_fields_impl);
-      field->name_set(headers->m_heap, headers->m_http->m_fields_impl, expected_name, strlen(expected_name));
-      field->value_set(headers->m_heap, headers->m_http->m_fields_impl, expected_value, strlen(expected_value));
-      mime_hdr_field_attach(headers->m_http->m_fields_impl, field, 1, nullptr);
-    }
-
-    memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
-    uint64_t buf_len = BUFSIZE_FOR_REGRESSION_TEST;
-    int64_t len      = hpack_encode_header_block(indexing_table, buf, buf_len, headers);
-
-    if (len < 0) {
-      box.check(false, "hpack_encode_header_blocks returned negative value: %" PRId64, len);
-      break;
-    }
-
-    box.check(len == encoded_field_response_test_case[i].encoded_field_len, "encoded length was %" PRId64 ", expecting %d", len,
-              encoded_field_response_test_case[i].encoded_field_len);
-    box.check(len > 0 && memcmp(buf, encoded_field_response_test_case[i].encoded_field, len) == 0, "encoded value was invalid");
-
-    // Check dynamic table
-    uint32_t expected_dynamic_table_size = 0;
-    for (unsigned int j = 0; j < sizeof(dynamic_table_response_test_case[i]) / sizeof(dynamic_table_response_test_case[i][0]);
-         j++) {
-      const char *expected_name  = dynamic_table_response_test_case[i][j].name;
-      const char *expected_value = dynamic_table_response_test_case[i][j].value;
-      int expected_name_len      = strlen(expected_name);
-      int expected_value_len     = strlen(expected_value);
-
-      if (expected_name_len == 0) {
-        break;
-      }
-
-      HpackLookupResult lookupResult = indexing_table.lookup(expected_name, expected_name_len, expected_value, expected_value_len);
-      box.check(lookupResult.match_type == HpackMatch::EXACT && lookupResult.index_type == HpackIndex::DYNAMIC,
-                "the header field is not indexed");
-
-      expected_dynamic_table_size += dynamic_table_response_test_case[i][j].size;
-    }
-    box.check(indexing_table.size() == expected_dynamic_table_size, "dynamic table is unexpected size: %d", indexing_table.size());
-  }
-}
-
-REGRESSION_TEST(HPACK_DecodeIndexedHeaderField)(RegressionTest *t, int, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  HpackIndexingTable indexing_table(4096);
-
-  for (const auto &i : indexed_test_case) {
-    ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
-    headers->create(HTTP_TYPE_REQUEST);
-    MIMEField *field = mime_field_create(headers->m_heap, headers->m_http->m_fields_impl);
-    MIMEFieldWrapper header(field, headers->m_heap, headers->m_http->m_fields_impl);
-
-    int len = decode_indexed_header_field(header, i.encoded_field, i.encoded_field + i.encoded_field_len, indexing_table);
-
-    box.check(len == i.encoded_field_len, "decoded length was %d, expecting %d", len, i.encoded_field_len);
-
-    int name_len;
-    const char *name = header.name_get(&name_len);
-    box.check(len > 0 && memcmp(name, i.raw_name, name_len) == 0, "decoded header name was invalid");
-
-    int actual_value_len;
-    const char *actual_value = header.value_get(&actual_value_len);
-    box.check(memcmp(actual_value, i.raw_value, actual_value_len) == 0, "decoded header value was invalid");
-  }
-}
-
-REGRESSION_TEST(HPACK_DecodeLiteralHeaderField)(RegressionTest *t, int, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  HpackIndexingTable indexing_table(4096);
-
-  for (const auto &i : literal_test_case) {
-    ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
-    headers->create(HTTP_TYPE_REQUEST);
-    MIMEField *field = mime_field_create(headers->m_heap, headers->m_http->m_fields_impl);
-    MIMEFieldWrapper header(field, headers->m_heap, headers->m_http->m_fields_impl);
-
-    int len = decode_literal_header_field(header, i.encoded_field, i.encoded_field + i.encoded_field_len, indexing_table);
-
-    box.check(len == i.encoded_field_len, "decoded length was %d, expecting %d", len, i.encoded_field_len);
-
-    int name_len;
-    const char *name = header.name_get(&name_len);
-    box.check(name_len > 0 && memcmp(name, i.raw_name, name_len) == 0, "decoded header name was invalid");
-
-    int actual_value_len;
-    const char *actual_value = header.value_get(&actual_value_len);
-    box.check(actual_value_len > 0 && memcmp(actual_value, i.raw_value, actual_value_len) == 0, "decoded header value was invalid");
-  }
-}
-
-REGRESSION_TEST(HPACK_Decode)(RegressionTest *t, int, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  HpackIndexingTable indexing_table(4096);
-
-  for (unsigned int i = 0; i < sizeof(encoded_field_request_test_case) / sizeof(encoded_field_request_test_case[0]); i++) {
-    ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
-    headers->create(HTTP_TYPE_REQUEST);
-
-    hpack_decode_header_block(indexing_table, headers, encoded_field_request_test_case[i].encoded_field,
-                              encoded_field_request_test_case[i].encoded_field_len, MAX_REQUEST_HEADER_SIZE, MAX_TABLE_SIZE);
-
-    for (unsigned int j = 0; j < sizeof(raw_field_request_test_case[i]) / sizeof(raw_field_request_test_case[i][0]); j++) {
-      const char *expected_name  = raw_field_request_test_case[i][j].raw_name;
-      const char *expected_value = raw_field_request_test_case[i][j].raw_value;
-      if (strlen(expected_name) == 0) {
-        break;
-      }
-
-      MIMEField *field = headers->field_find(expected_name, strlen(expected_name));
-      box.check(field != nullptr, "A MIMEField that has \"%s\" as name doesn't exist", expected_name);
-
-      if (field) {
-        int actual_value_len;
-        const char *actual_value = field->value_get(&actual_value_len);
-        box.check(strncmp(expected_value, actual_value, actual_value_len) == 0,
-                  "A MIMEField that has \"%s\" as value doesn't exist", expected_value);
-      }
-    }
-  }
-}
-
-void
-forceLinkRegressionHPACK()
-{
-  // NOTE: Do Nothing
-}
diff --git a/proxy/http2/unit_tests/main.cc b/proxy/http2/unit_tests/main.cc
index aa19e09..6352dc4 100644
--- a/proxy/http2/unit_tests/main.cc
+++ b/proxy/http2/unit_tests/main.cc
@@ -31,13 +31,15 @@
 
 #include "diags.i"
 
+#include "HuffmanCodec.h"
+
 #define TEST_THREADS 1
 
 struct EventProcessorListener : Catch::TestEventListenerBase {
   using TestEventListenerBase::TestEventListenerBase;
 
   void
-  testRunStarting(Catch::TestRunInfo const &testRunInfo) override
+  testRunStarting(Catch::TestRunInfo const & /* testRunInfo */) override
   {
     Layout::create();
     init_diags("", nullptr);
@@ -49,6 +51,14 @@ struct EventProcessorListener : Catch::TestEventListenerBase {
 
     EThread *main_thread = new EThread;
     main_thread->set_specific();
+
+    hpack_huffman_init();
+  }
+
+  void
+  testRunEnded(Catch::TestRunStats const & /* testRunStats */) override
+  {
+    hpack_huffman_fin();
   }
 };
 
diff --git a/proxy/http2/unit_tests/test_HpackIndexingTable.cc b/proxy/http2/unit_tests/test_HpackIndexingTable.cc
new file mode 100644
index 0000000..44aabd2
--- /dev/null
+++ b/proxy/http2/unit_tests/test_HpackIndexingTable.cc
@@ -0,0 +1,487 @@
+/** @file
+
+    Catch-based unit tests for HPACK
+
+    Some test cases are based on examples of specification.
+    - https://tools.ietf.org/html/rfc7541#appendix-C
+
+    @section license License
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+#include "catch.hpp"
+
+#include "HPACK.h"
+
+static constexpr int DYNAMIC_TABLE_SIZE_FOR_REGRESSION_TEST = 256;
+static constexpr int BUFSIZE_FOR_REGRESSION_TEST            = 128;
+static constexpr int MAX_TEST_FIELD_NUM                     = 8;
+static constexpr int MAX_REQUEST_HEADER_SIZE                = 131072;
+static constexpr int MAX_TABLE_SIZE                         = 4096;
+
+TEST_CASE("HPACK low level APIs", "[hpack]")
+{
+  SECTION("indexed_header_field")
+  {
+    // [RFC 7541] C.2.4. Indexed Header Field
+    const static struct {
+      int index;
+      char *raw_name;
+      char *raw_value;
+      uint8_t *encoded_field;
+      int encoded_field_len;
+    } indexed_test_case[] = {
+      {2, (char *)":method", (char *)"GET", (uint8_t *)"\x82", 1},
+    };
+
+    SECTION("encoding")
+    {
+      uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
+
+      for (const auto &i : indexed_test_case) {
+        memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
+
+        int len = encode_indexed_header_field(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, i.index);
+
+        REQUIRE(len > 0);
+        REQUIRE(len == i.encoded_field_len);
+        REQUIRE(memcmp(buf, i.encoded_field, len) == 0);
+      }
+    }
+
+    SECTION("decoding")
+    {
+      HpackIndexingTable indexing_table(4096);
+
+      for (const auto &i : indexed_test_case) {
+        ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
+        headers->create(HTTP_TYPE_REQUEST);
+        MIMEField *field = mime_field_create(headers->m_heap, headers->m_http->m_fields_impl);
+        MIMEFieldWrapper header(field, headers->m_heap, headers->m_http->m_fields_impl);
+
+        int len = decode_indexed_header_field(header, i.encoded_field, i.encoded_field + i.encoded_field_len, indexing_table);
+        REQUIRE(len == i.encoded_field_len);
+
+        int name_len;
+        const char *name = header.name_get(&name_len);
+        REQUIRE(name_len > 0);
+        REQUIRE(memcmp(name, i.raw_name, name_len) == 0);
+
+        int actual_value_len;
+        const char *actual_value = header.value_get(&actual_value_len);
+        REQUIRE(actual_value_len > 0);
+        REQUIRE(memcmp(actual_value, i.raw_value, actual_value_len) == 0);
+      }
+    }
+  }
+
+  SECTION("literal_header_field")
+  {
+    // [RFC 7541] C.2. Header Field Representation Examples
+    const static struct {
+      char *raw_name;
+      char *raw_value;
+      int index;
+      HpackField type;
+      uint8_t *encoded_field;
+      int encoded_field_len;
+    } literal_test_case[] = {
+      {(char *)"custom-key", (char *)"custom-header", 0, HpackField::INDEXED_LITERAL,
+       (uint8_t *)"\x40\x0a"
+                  "custom-key\x0d"
+                  "custom-header",
+       26},
+      {(char *)"custom-key", (char *)"custom-header", 0, HpackField::NOINDEX_LITERAL,
+       (uint8_t *)"\x00\x0a"
+                  "custom-key\x0d"
+                  "custom-header",
+       26},
+      {(char *)"custom-key", (char *)"custom-header", 0, HpackField::NEVERINDEX_LITERAL,
+       (uint8_t *)"\x10\x0a"
+                  "custom-key\x0d"
+                  "custom-header",
+       26},
+      {(char *)":path", (char *)"/sample/path", 4, HpackField::INDEXED_LITERAL,
+       (uint8_t *)"\x44\x0c"
+                  "/sample/path",
+       14},
+      {(char *)":path", (char *)"/sample/path", 4, HpackField::NOINDEX_LITERAL,
+       (uint8_t *)"\x04\x0c"
+                  "/sample/path",
+       14},
+      {(char *)":path", (char *)"/sample/path", 4, HpackField::NEVERINDEX_LITERAL,
+       (uint8_t *)"\x14\x0c"
+                  "/sample/path",
+       14},
+      {(char *)"password", (char *)"secret", 0, HpackField::INDEXED_LITERAL,
+       (uint8_t *)"\x40\x08"
+                  "password\x06"
+                  "secret",
+       17},
+      {(char *)"password", (char *)"secret", 0, HpackField::NOINDEX_LITERAL,
+       (uint8_t *)"\x00\x08"
+                  "password\x06"
+                  "secret",
+       17},
+      {(char *)"password", (char *)"secret", 0, HpackField::NEVERINDEX_LITERAL,
+       (uint8_t *)"\x10\x08"
+                  "password\x06"
+                  "secret",
+       17},
+      // with Huffman Coding
+      {(char *)"custom-key", (char *)"custom-header", 0, HpackField::INDEXED_LITERAL,
+       (uint8_t *)"\x40"
+                  "\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f"
+                  "\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9",
+       20},
+      {(char *)"custom-key", (char *)"custom-header", 0, HpackField::NOINDEX_LITERAL,
+       (uint8_t *)"\x00"
+                  "\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f"
+                  "\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9",
+       20},
+      {(char *)"custom-key", (char *)"custom-header", 0, HpackField::NEVERINDEX_LITERAL,
+       (uint8_t *)"\x10"
+                  "\x88\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f"
+                  "\x89\x25\xa8\x49\xe9\x5a\x72\x8e\x42\xd9",
+       20},
+      {(char *)":path", (char *)"/sample/path", 4, HpackField::INDEXED_LITERAL,
+       (uint8_t *)"\x44"
+                  "\x89\x61\x03\xa6\xba\x0a\xc5\x63\x4c\xff",
+       11},
+      {(char *)":path", (char *)"/sample/path", 4, HpackField::NOINDEX_LITERAL,
+       (uint8_t *)"\x04"
+                  "\x89\x61\x03\xa6\xba\x0a\xc5\x63\x4c\xff",
+       11},
+      {(char *)":path", (char *)"/sample/path", 4, HpackField::NEVERINDEX_LITERAL,
+       (uint8_t *)"\x14"
+                  "\x89\x61\x03\xa6\xba\x0a\xc5\x63\x4c\xff",
+       11},
+      {(char *)"password", (char *)"secret", 0, HpackField::INDEXED_LITERAL,
+       (uint8_t *)"\x40"
+                  "\x86\xac\x68\x47\x83\xd9\x27"
+                  "\x84\x41\x49\x61\x53",
+       13},
+      {(char *)"password", (char *)"secret", 0, HpackField::NOINDEX_LITERAL,
+       (uint8_t *)"\x00"
+                  "\x86\xac\x68\x47\x83\xd9\x27"
+                  "\x84\x41\x49\x61\x53",
+       13},
+      {(char *)"password", (char *)"secret", 0, HpackField::NEVERINDEX_LITERAL,
+       (uint8_t *)"\x10"
+                  "\x86\xac\x68\x47\x83\xd9\x27"
+                  "\x84\x41\x49\x61\x53",
+       13},
+    };
+
+    SECTION("encoding")
+    {
+      {
+        uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
+        int len;
+        HpackIndexingTable indexing_table(4096);
+
+        for (unsigned int i = 9; i < sizeof(literal_test_case) / sizeof(literal_test_case[0]); i++) {
+          memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
+
+          ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
+          headers->create(HTTP_TYPE_RESPONSE);
+          MIMEField *field = mime_field_create(headers->m_heap, headers->m_http->m_fields_impl);
+          MIMEFieldWrapper header(field, headers->m_heap, headers->m_http->m_fields_impl);
+
+          header.name_set(literal_test_case[i].raw_name, strlen(literal_test_case[i].raw_name));
+          header.value_set(literal_test_case[i].raw_value, strlen(literal_test_case[i].raw_value));
+          if (literal_test_case[i].index > 0) {
+            len =
+              encode_literal_header_field_with_indexed_name(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, header,
+                                                            literal_test_case[i].index, indexing_table, literal_test_case[i].type);
+          } else {
+            header.name_set(literal_test_case[i].raw_name, strlen(literal_test_case[i].raw_name));
+            len = encode_literal_header_field_with_new_name(buf, buf + BUFSIZE_FOR_REGRESSION_TEST, header, indexing_table,
+                                                            literal_test_case[i].type);
+          }
+
+          REQUIRE(len > 0);
+          REQUIRE(len == literal_test_case[i].encoded_field_len);
+          REQUIRE(memcmp(buf, literal_test_case[i].encoded_field, len) == 0);
+        }
+      }
+    }
+
+    SECTION("decoding")
+    {
+      {
+        HpackIndexingTable indexing_table(4096);
+
+        for (const auto &i : literal_test_case) {
+          ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
+          headers->create(HTTP_TYPE_REQUEST);
+          MIMEField *field = mime_field_create(headers->m_heap, headers->m_http->m_fields_impl);
+          MIMEFieldWrapper header(field, headers->m_heap, headers->m_http->m_fields_impl);
+
+          int len = decode_literal_header_field(header, i.encoded_field, i.encoded_field + i.encoded_field_len, indexing_table);
+          REQUIRE(len == i.encoded_field_len);
+
+          int name_len;
+          const char *name = header.name_get(&name_len);
+          REQUIRE(name_len > 0);
+          REQUIRE(memcmp(name, i.raw_name, name_len) == 0);
+
+          int actual_value_len;
+          const char *actual_value = header.value_get(&actual_value_len);
+          REQUIRE(actual_value_len > 0);
+          REQUIRE(memcmp(actual_value, i.raw_value, actual_value_len) == 0);
+        }
+      }
+    }
+  }
+}
+
+TEST_CASE("HPACK high level APIs", "[hpack]")
+{
+  SECTION("encoding")
+  {
+    // [RFC 7541] C.6. Response Examples with Huffman Coding
+    const static struct {
+      char *raw_name;
+      char *raw_value;
+    } raw_field_response_test_case[][MAX_TEST_FIELD_NUM] = {
+      {
+        {(char *)":status", (char *)"302"},
+        {(char *)"cache-control", (char *)"private"},
+        {(char *)"date", (char *)"Mon, 21 Oct 2013 20:13:21 GMT"},
+        {(char *)"location", (char *)"https://www.example.com"},
+        {(char *)"", (char *)""} // End of this test case
+      },
+      {
+        {(char *)":status", (char *)"307"},
+        {(char *)"cache-control", (char *)"private"},
+        {(char *)"date", (char *)"Mon, 21 Oct 2013 20:13:21 GMT"},
+        {(char *)"location", (char *)"https://www.example.com"},
+        {(char *)"", (char *)""} // End of this test case
+      },
+      {
+        {(char *)":status", (char *)"200"},
+        {(char *)"cache-control", (char *)"private"},
+        {(char *)"date", (char *)"Mon, 21 Oct 2013 20:13:22 GMT"},
+        {(char *)"location", (char *)"https://www.example.com"},
+        {(char *)"content-encoding", (char *)"gzip"},
+        {(char *)"set-cookie", (char *)"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
+        {(char *)"", (char *)""} // End of this test case
+      },
+    };
+
+    const static struct {
+      uint8_t *encoded_field;
+      int encoded_field_len;
+    } encoded_field_response_test_case[] = {
+      {(uint8_t *)"\x48\x82"
+                  "\x64\x02"
+                  "\x58\x85"
+                  "\xae\xc3\x77\x1a\x4b"
+                  "\x61\x96"
+                  "\xd0\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20\x05\x95\x04\x0b\x81\x66"
+                  "\xe0\x82\xa6\x2d\x1b\xff"
+                  "\x6e\x91"
+                  "\x9d\x29\xad\x17\x18\x63\xc7\x8f\x0b\x97\xc8\xe9\xae\x82\xae\x43"
+                  "\xd3",
+       54},
+      {(uint8_t *)"\x48\x83"
+                  "\x64\x0e\xff"
+                  "\xc1"
+                  "\xc0"
+                  "\xbf",
+       8},
+      {(uint8_t *)"\x88"
+                  "\xc1"
+                  "\x61\x96"
+                  "\xd0\x7a\xbe\x94\x10\x54\xd4\x44\xa8\x20\x05\x95\x04\x0b\x81\x66"
+                  "\xe0\x84\xa6\x2d\x1b\xff"
+                  "\xc0"
+                  "\x5a\x83"
+                  "\x9b\xd9\xab"
+                  "\x77\xad"
+                  "\x94\xe7\x82\x1d\xd7\xf2\xe6\xc7\xb3\x35\xdf\xdf\xcd\x5b\x39\x60"
+                  "\xd5\xaf\x27\x08\x7f\x36\x72\xc1\xab\x27\x0f\xb5\x29\x1f\x95\x87"
+                  "\x31\x60\x65\xc0\x03\xed\x4e\xe5\xb1\x06\x3d\x50\x07",
+       79},
+    };
+
+    const static struct {
+      uint32_t size;
+      char *name;
+      char *value;
+    } dynamic_table_response_test_case[][MAX_TEST_FIELD_NUM] = {
+      {
+        {63, (char *)"location", (char *)"https://www.example.com"},
+        {65, (char *)"date", (char *)"Mon, 21 Oct 2013 20:13:21 GMT"},
+        {52, (char *)"cache-control", (char *)"private"},
+        {42, (char *)":status", (char *)"302"},
+        {0, (char *)"", (char *)""} // End of this test case
+      },
+      {
+        {42, (char *)":status", (char *)"307"},
+        {63, (char *)"location", (char *)"https://www.example.com"},
+        {65, (char *)"date", (char *)"Mon, 21 Oct 2013 20:13:21 GMT"},
+        {52, (char *)"cache-control", (char *)"private"},
+        {0, (char *)"", (char *)""} // End of this test case
+      },
+      {
+        {98, (char *)"set-cookie", (char *)"foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1"},
+        {52, (char *)"content-encoding", (char *)"gzip"},
+        {65, (char *)"date", (char *)"Mon, 21 Oct 2013 20:13:22 GMT"},
+        {0, (char *)"", (char *)""} // End of this test case
+      },
+    };
+
+    uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
+    HpackIndexingTable indexing_table(4096);
+    indexing_table.update_maximum_size(DYNAMIC_TABLE_SIZE_FOR_REGRESSION_TEST);
+
+    for (unsigned int i = 0; i < sizeof(encoded_field_response_test_case) / sizeof(encoded_field_response_test_case[0]); i++) {
+      ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
+      headers->create(HTTP_TYPE_RESPONSE);
+
+      for (unsigned int j = 0; j < sizeof(raw_field_response_test_case[i]) / sizeof(raw_field_response_test_case[i][0]); j++) {
+        const char *expected_name  = raw_field_response_test_case[i][j].raw_name;
+        const char *expected_value = raw_field_response_test_case[i][j].raw_value;
+        if (strlen(expected_name) == 0) {
+          break;
+        }
+
+        MIMEField *field = mime_field_create(headers->m_heap, headers->m_http->m_fields_impl);
+        field->name_set(headers->m_heap, headers->m_http->m_fields_impl, expected_name, strlen(expected_name));
+        field->value_set(headers->m_heap, headers->m_http->m_fields_impl, expected_value, strlen(expected_value));
+        mime_hdr_field_attach(headers->m_http->m_fields_impl, field, 1, nullptr);
+      }
+
+      memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
+      uint64_t buf_len = BUFSIZE_FOR_REGRESSION_TEST;
+      int64_t len      = hpack_encode_header_block(indexing_table, buf, buf_len, headers);
+
+      REQUIRE(len > 0);
+      REQUIRE(len == encoded_field_response_test_case[i].encoded_field_len);
+      REQUIRE(memcmp(buf, encoded_field_response_test_case[i].encoded_field, len) == 0);
+
+      // Check dynamic table
+      uint32_t expected_dynamic_table_size = 0;
+      for (unsigned int j = 0; j < sizeof(dynamic_table_response_test_case[i]) / sizeof(dynamic_table_response_test_case[i][0]);
+           j++) {
+        const char *expected_name  = dynamic_table_response_test_case[i][j].name;
+        const char *expected_value = dynamic_table_response_test_case[i][j].value;
+        int expected_name_len      = strlen(expected_name);
+        int expected_value_len     = strlen(expected_value);
+
+        if (expected_name_len == 0) {
+          break;
+        }
+
+        HpackLookupResult lookupResult =
+          indexing_table.lookup(expected_name, expected_name_len, expected_value, expected_value_len);
+        CHECK(lookupResult.match_type == HpackMatch::EXACT);
+        CHECK(lookupResult.index_type == HpackIndex::DYNAMIC);
+
+        expected_dynamic_table_size += dynamic_table_response_test_case[i][j].size;
+      }
+      REQUIRE(indexing_table.size() == expected_dynamic_table_size);
+    }
+  }
+
+  SECTION("decoding")
+  {
+    // [RFC 7541] C.3. Request Examples without Huffman Coding - C.3.1. First Request
+    // [RFC 7541] C.4. Request Examples with Huffman Coding - C.4.1. First Request
+    const static struct {
+      char *raw_name;
+      char *raw_value;
+    } raw_field_request_test_case[][MAX_TEST_FIELD_NUM] = {
+      {
+        {(char *)":method", (char *)"GET"},
+        {(char *)":scheme", (char *)"http"},
+        {(char *)":path", (char *)"/"},
+        {(char *)":authority", (char *)"www.example.com"},
+        {(char *)"", (char *)""} // End of this test case
+      },
+      {
+        {(char *)":method", (char *)"GET"},
+        {(char *)":scheme", (char *)"http"},
+        {(char *)":path", (char *)"/"},
+        {(char *)":authority", (char *)"www.example.com"},
+        {(char *)"", (char *)""} // End of this test case
+      },
+    };
+
+    const static struct {
+      uint8_t *encoded_field;
+      int encoded_field_len;
+    } encoded_field_request_test_case[] = {
+      {(uint8_t *)"\x40"
+                  "\x7:method"
+                  "\x3GET"
+                  "\x40"
+                  "\x7:scheme"
+                  "\x4http"
+                  "\x40"
+                  "\x5:path"
+                  "\x1/"
+                  "\x40"
+                  "\xa:authority"
+                  "\xfwww.example.com",
+       64},
+      {(uint8_t *)"\x40"
+                  "\x85\xb9\x49\x53\x39\xe4"
+                  "\x83\xc5\x83\x7f"
+                  "\x40"
+                  "\x85\xb8\x82\x4e\x5a\x4b"
+                  "\x83\x9d\x29\xaf"
+                  "\x40"
+                  "\x84\xb9\x58\xd3\x3f"
+                  "\x81\x63"
+                  "\x40"
+                  "\x88\xb8\x3b\x53\x39\xec\x32\x7d\x7f"
+                  "\x8c\xf1\xe3\xc2\xe5\xf2\x3a\x6b\xa0\xab\x90\xf4\xff",
+       53},
+    };
+
+    HpackIndexingTable indexing_table(4096);
+
+    for (unsigned int i = 0; i < sizeof(encoded_field_request_test_case) / sizeof(encoded_field_request_test_case[0]); i++) {
+      ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
+      headers->create(HTTP_TYPE_REQUEST);
+
+      hpack_decode_header_block(indexing_table, headers, encoded_field_request_test_case[i].encoded_field,
+                                encoded_field_request_test_case[i].encoded_field_len, MAX_REQUEST_HEADER_SIZE, MAX_TABLE_SIZE);
+
+      for (unsigned int j = 0; j < sizeof(raw_field_request_test_case[i]) / sizeof(raw_field_request_test_case[i][0]); j++) {
+        const char *expected_name  = raw_field_request_test_case[i][j].raw_name;
+        const char *expected_value = raw_field_request_test_case[i][j].raw_value;
+        if (strlen(expected_name) == 0) {
+          break;
+        }
+
+        MIMEField *field = headers->field_find(expected_name, strlen(expected_name));
+        CHECK(field != nullptr);
+
+        if (field) {
+          int actual_value_len;
+          const char *actual_value = field->value_get(&actual_value_len);
+          CHECK(strncmp(expected_value, actual_value, actual_value_len) == 0);
+        }
+      }
+    }
+  }
+}
diff --git a/proxy/http2/unit_tests/test_Http2Frame.cc b/proxy/http2/unit_tests/test_Http2Frame.cc
index d1e695e..5579fe6 100644
--- a/proxy/http2/unit_tests/test_Http2Frame.cc
+++ b/proxy/http2/unit_tests/test_Http2Frame.cc
@@ -62,3 +62,124 @@ TEST_CASE("Http2Frame", "[http2][Http2Frame]")
 
   free_MIOBuffer(miob);
 }
+
+TEST_CASE("HTTP/2 Frame Flags", "[http2]")
+{
+  const static struct {
+    uint8_t ftype;
+    uint8_t fflags;
+    bool valid;
+  } http2_frame_flags_test_case[] = {
+    {HTTP2_FRAME_TYPE_DATA, 0x00, true},
+    {HTTP2_FRAME_TYPE_DATA, 0x01, true},
+    {HTTP2_FRAME_TYPE_DATA, 0x02, false},
+    {HTTP2_FRAME_TYPE_DATA, 0x04, false},
+    {HTTP2_FRAME_TYPE_DATA, 0x08, true},
+    {HTTP2_FRAME_TYPE_DATA, 0x10, false},
+    {HTTP2_FRAME_TYPE_DATA, 0x20, false},
+    {HTTP2_FRAME_TYPE_DATA, 0x40, false},
+    {HTTP2_FRAME_TYPE_DATA, 0x80, false},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x00, true},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x01, true},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x02, false},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x04, true},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x08, true},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x10, false},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x20, true},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x40, false},
+    {HTTP2_FRAME_TYPE_HEADERS, 0x80, false},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x00, true},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x01, false},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x02, false},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x04, false},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x08, false},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x10, false},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x20, false},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x40, false},
+    {HTTP2_FRAME_TYPE_PRIORITY, 0x80, false},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x00, true},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x01, false},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x02, false},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x04, false},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x08, false},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x10, false},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x20, false},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x40, false},
+    {HTTP2_FRAME_TYPE_RST_STREAM, 0x80, false},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x00, true},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x01, true},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x02, false},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x04, false},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x08, false},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x10, false},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x20, false},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x40, false},
+    {HTTP2_FRAME_TYPE_SETTINGS, 0x80, false},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x00, true},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x01, false},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x02, false},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x04, true},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x08, true},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x10, false},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x20, false},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x40, false},
+    {HTTP2_FRAME_TYPE_PUSH_PROMISE, 0x80, false},
+    {HTTP2_FRAME_TYPE_PING, 0x00, true},
+    {HTTP2_FRAME_TYPE_PING, 0x01, true},
+    {HTTP2_FRAME_TYPE_PING, 0x02, false},
+    {HTTP2_FRAME_TYPE_PING, 0x04, false},
+    {HTTP2_FRAME_TYPE_PING, 0x08, false},
+    {HTTP2_FRAME_TYPE_PING, 0x10, false},
+    {HTTP2_FRAME_TYPE_PING, 0x20, false},
+    {HTTP2_FRAME_TYPE_PING, 0x40, false},
+    {HTTP2_FRAME_TYPE_PING, 0x80, false},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x00, true},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x01, false},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x02, false},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x04, false},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x08, false},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x10, false},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x20, false},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x40, false},
+    {HTTP2_FRAME_TYPE_GOAWAY, 0x80, false},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x00, true},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x01, false},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x02, false},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x04, false},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x08, false},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x10, false},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x20, false},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x40, false},
+    {HTTP2_FRAME_TYPE_WINDOW_UPDATE, 0x80, false},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x00, true},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x01, false},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x02, false},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x04, true},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x08, false},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x10, false},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x20, false},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x40, false},
+    {HTTP2_FRAME_TYPE_CONTINUATION, 0x80, false},
+    {HTTP2_FRAME_TYPE_MAX, 0x00, true},
+    {HTTP2_FRAME_TYPE_MAX, 0x01, true},
+    {HTTP2_FRAME_TYPE_MAX, 0x02, true},
+    {HTTP2_FRAME_TYPE_MAX, 0x04, true},
+    {HTTP2_FRAME_TYPE_MAX, 0x08, true},
+    {HTTP2_FRAME_TYPE_MAX, 0x10, true},
+    {HTTP2_FRAME_TYPE_MAX, 0x20, true},
+    {HTTP2_FRAME_TYPE_MAX, 0x40, true},
+    {HTTP2_FRAME_TYPE_MAX, 0x80, true},
+  };
+
+  static const uint8_t HTTP2_FRAME_FLAGS_MASKS[HTTP2_FRAME_TYPE_MAX] = {
+    HTTP2_FLAGS_DATA_MASK,          HTTP2_FLAGS_HEADERS_MASK,      HTTP2_FLAGS_PRIORITY_MASK, HTTP2_FLAGS_RST_STREAM_MASK,
+    HTTP2_FLAGS_SETTINGS_MASK,      HTTP2_FLAGS_PUSH_PROMISE_MASK, HTTP2_FLAGS_PING_MASK,     HTTP2_FLAGS_GOAWAY_MASK,
+    HTTP2_FLAGS_WINDOW_UPDATE_MASK, HTTP2_FLAGS_CONTINUATION_MASK,
+  };
+
+  for (auto i : http2_frame_flags_test_case) {
+    if (i.ftype < HTTP2_FRAME_TYPE_MAX) {
+      CHECK(((i.fflags & ~HTTP2_FRAME_FLAGS_MASKS[i.ftype]) == 0) == i.valid);
+    }
+  }
+}


Mime
View raw message