Repository: trafficserver
Updated Branches:
  refs/heads/master 5a0952b01 -> a39dd9d7c


TS-4092: Decouple HPACK from HTTP/2

This close #460


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

Branch: refs/heads/master
Commit: a39dd9d7c6d9454d8e6fe4be5cf18e517b7557aa
Parents: 5a0952b
Author: Masakazu Kitajo <[email protected]>
Authored: Mon Feb 8 23:52:59 2016 +0900
Committer: Masakazu Kitajo <[email protected]>
Committed: Sat Apr 2 00:27:36 2016 +0900

----------------------------------------------------------------------
 proxy/http2/HPACK.cc                | 334 ++++++++++++++++++----------
 proxy/http2/HPACK.h                 | 109 +++++-----
 proxy/http2/HTTP2.cc                | 360 +++++++++++++------------------
 proxy/http2/HTTP2.h                 |   8 +-
 proxy/http2/Http2ConnectionState.cc | 104 +++++----
 proxy/http2/Http2ConnectionState.h  |  12 +-
 proxy/http2/Http2Stream.cc          |   2 +-
 proxy/http2/Http2Stream.h           |   8 +-
 proxy/http2/RegressionHPACK.cc      |  52 ++---
 9 files changed, 520 insertions(+), 469 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/HPACK.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/HPACK.cc b/proxy/http2/HPACK.cc
index 3254aa5..c6de481 100644
--- a/proxy/http2/HPACK.cc
+++ b/proxy/http2/HPACK.cc
@@ -24,19 +24,6 @@
 #include "HPACK.h"
 #include "HuffmanCodec.h"
 
-// Constant strings for pseudo headers of HPACK
-const char *HPACK_VALUE_SCHEME = ":scheme";
-const char *HPACK_VALUE_METHOD = ":method";
-const char *HPACK_VALUE_AUTHORITY = ":authority";
-const char *HPACK_VALUE_PATH = ":path";
-const char *HPACK_VALUE_STATUS = ":status";
-
-const unsigned HPACK_LEN_SCHEME = countof(":scheme") - 1;
-const unsigned HPACK_LEN_METHOD = countof(":method") - 1;
-const unsigned HPACK_LEN_AUTHORITY = countof(":authority") - 1;
-const unsigned HPACK_LEN_PATH = countof(":path") - 1;
-const unsigned HPACK_LEN_STATUS = countof(":status") - 1;
-
 // [RFC 7541] 4.1. Calculating Table Size
 // The size of an entry is the sum of its name's length in octets (as defined 
in Section 5.2),
 // its value's length in octets, and 32.
@@ -174,14 +161,62 @@ const static struct {
                     {"via", ""},
                     {"www-authenticate", ""}};
 
-Http2LookupIndexResult
-Http2IndexingTable::get_index(const MIMEFieldWrapper &field) const
+
+/******************
+ * Local functions
+ ******************/
+static inline bool
+hpack_field_is_literal(HpackFieldType ftype)
+{
+  return ftype == HPACK_FIELD_INDEXED_LITERAL || ftype == 
HPACK_FIELD_NOINDEX_LITERAL || ftype == HPACK_FIELD_NEVERINDEX_LITERAL;
+}
+
+//
+// The first byte of an HPACK field unambiguously tells us what
+// kind of field it is. Field types are specified in the high 4 bits
+// and all bits are defined, so there's no way to get an invalid field type.
+//
+HpackFieldType
+hpack_parse_field_type(uint8_t ftype)
+{
+  if (ftype & 0x80) {
+    return HPACK_FIELD_INDEX;
+  }
+
+  if (ftype & 0x40) {
+    return HPACK_FIELD_INDEXED_LITERAL;
+  }
+
+  if (ftype & 0x20) {
+    return HPACK_FIELD_TABLESIZE_UPDATE;
+  }
+
+  if (ftype & 0x10) {
+    return HPACK_FIELD_NEVERINDEX_LITERAL;
+  }
+
+  ink_assert((ftype & 0xf0) == 0x0);
+  return HPACK_FIELD_NOINDEX_LITERAL;
+}
+
+
+/************************
+ * HpackIndexingTable
+ ************************/
+HpackLookupResult
+HpackIndexingTable::lookup(const MIMEFieldWrapper &field) const
 {
-  Http2LookupIndexResult result;
   int target_name_len = 0, target_value_len = 0;
   const char *target_name = field.name_get(&target_name_len);
   const char *target_value = field.value_get(&target_value_len);
-  const int entry_num = TS_HPACK_STATIC_TABLE_ENTRY_NUM + 
_dynamic_table.get_current_entry_num();
+  return lookup(target_name, target_name_len, target_value, target_value_len);
+}
+
+HpackLookupResult
+HpackIndexingTable::lookup(const char *name, int name_len, const char *value, 
int value_len) const
+{
+  HpackLookupResult result;
+  const int entry_num = TS_HPACK_STATIC_TABLE_ENTRY_NUM + 
_dynamic_table->length();
 
   for (int index = 1; index < entry_num; ++index) {
     const char *table_name, *table_value;
@@ -195,29 +230,37 @@ Http2IndexingTable::get_index(const MIMEFieldWrapper 
&field) const
       table_value_len = strlen(table_value);
     } else {
       // dynamic table
-      const MIMEField *m_field = _dynamic_table.get_header_field(index - 
TS_HPACK_STATIC_TABLE_ENTRY_NUM);
+      const MIMEField *m_field = _dynamic_table->get_header_field(index - 
TS_HPACK_STATIC_TABLE_ENTRY_NUM);
 
       table_name = m_field->name_get(&table_name_len);
       table_value = m_field->value_get(&table_value_len);
     }
 
     // Check whether name (and value) are matched
-    if (ptr_len_casecmp(target_name, target_name_len, table_name, 
table_name_len) == 0) {
-      if (ptr_len_cmp(target_value, target_value_len, table_value, 
table_value_len) == 0) {
+    if (ptr_len_casecmp(name, name_len, table_name, table_name_len) == 0) {
+      if (ptr_len_cmp(value, value_len, table_value, table_value_len) == 0) {
         result.index = index;
-        result.value_is_indexed = true;
+        result.match_type = HPACK_EXACT_MATCH;
         break;
       } else if (!result.index) {
         result.index = index;
+        result.match_type = HPACK_NAME_MATCH;
       }
     }
   }
+  if (result.match_type != HPACK_NO_MATCH) {
+    if (result.index < TS_HPACK_STATIC_TABLE_ENTRY_NUM) {
+      result.index_type = HPACK_INDEX_TYPE_STATIC;
+    } else {
+      result.index_type = HPACK_INDEX_TYPE_DYNAMIC;
+    }
+  }
 
   return result;
 }
 
 int
-Http2IndexingTable::get_header_field(uint32_t index, MIMEFieldWrapper &field) 
const
+HpackIndexingTable::get_header_field(uint32_t index, MIMEFieldWrapper &field) 
const
 {
   // Index Address Space starts at 1, so index == 0 is invalid.
   if (!index)
@@ -227,9 +270,9 @@ Http2IndexingTable::get_header_field(uint32_t index, 
MIMEFieldWrapper &field) co
     // static table
     field.name_set(STATIC_TABLE[index].name, strlen(STATIC_TABLE[index].name));
     field.value_set(STATIC_TABLE[index].value, 
strlen(STATIC_TABLE[index].value));
-  } else if (index < TS_HPACK_STATIC_TABLE_ENTRY_NUM + 
_dynamic_table.get_current_entry_num()) {
+  } else if (index < TS_HPACK_STATIC_TABLE_ENTRY_NUM + 
_dynamic_table->length()) {
     // dynamic table
-    const MIMEField *m_field = _dynamic_table.get_header_field(index - 
TS_HPACK_STATIC_TABLE_ENTRY_NUM);
+    const MIMEField *m_field = _dynamic_table->get_header_field(index - 
TS_HPACK_STATIC_TABLE_ENTRY_NUM);
 
     int name_len, value_len;
     const char *name = m_field->name_get(&name_len);
@@ -248,44 +291,38 @@ Http2IndexingTable::get_header_field(uint32_t index, 
MIMEFieldWrapper &field) co
 }
 
 void
-Http2IndexingTable::add_header_field_to_dynamic_table(const MIMEField *field)
+HpackIndexingTable::add_header_field(const MIMEField *field)
 {
-  _dynamic_table.add_header_field(field);
+  _dynamic_table->add_header_field(field);
 }
 
 uint32_t
-Http2IndexingTable::get_dynamic_table_size() const
-{
-  return _dynamic_table.get_size();
-}
-
-bool
-Http2IndexingTable::set_dynamic_table_size(uint32_t new_size)
+HpackIndexingTable::size() const
 {
-  return _dynamic_table.set_size(new_size);
+  return _dynamic_table->size();
 }
 
 bool
-Http2IndexingTable::is_header_in_dynamic_table(const char *target_name, const 
char *target_value) const
+HpackIndexingTable::update_maximum_size(uint32_t new_size)
 {
-  return _dynamic_table.is_header_in(target_name, target_value);
+  return _dynamic_table->update_maximum_size(new_size);
 }
 
 const MIMEField *
-Http2DynamicTable::get_header_field(uint32_t index) const
+HpackDynamicTable::get_header_field(uint32_t index) const
 {
   return _headers.get(index);
 }
 
 void
-Http2DynamicTable::add_header_field(const MIMEField *field)
+HpackDynamicTable::add_header_field(const MIMEField *field)
 {
   int name_len, value_len;
   const char *name = field->name_get(&name_len);
   const char *value = field->value_get(&value_len);
   uint32_t header_size = ADDITIONAL_OCTETS + name_len + value_len;
 
-  if (header_size > _settings_dynamic_table_size) {
+  if (header_size > _maximum_size) {
     // [RFC 7541] 4.4. Entry Eviction When Adding New Entries
     // It is not an error to attempt to add an entry that is larger than
     // the maximum size; an attempt to add an entry larger than the entire
@@ -295,7 +332,7 @@ Http2DynamicTable::add_header_field(const MIMEField *field)
     _current_size = 0;
   } else {
     _current_size += header_size;
-    while (_current_size > _settings_dynamic_table_size) {
+    while (_current_size > _maximum_size) {
       int last_name_len, last_value_len;
       MIMEField *last_field = _headers.last();
 
@@ -316,7 +353,7 @@ Http2DynamicTable::add_header_field(const MIMEField *field)
 }
 
 uint32_t
-Http2DynamicTable::get_size() const
+HpackDynamicTable::size() const
 {
   return _current_size;
 }
@@ -329,7 +366,7 @@ Http2DynamicTable::get_size() const
 // header table is less than or equal to the maximum size.
 //
 bool
-Http2DynamicTable::set_size(uint32_t new_size)
+HpackDynamicTable::update_maximum_size(uint32_t new_size)
 {
   while (_current_size > new_size) {
     if (_headers.n <= 0) {
@@ -346,63 +383,16 @@ Http2DynamicTable::set_size(uint32_t new_size)
     _mhdr->field_delete(last_field, false);
   }
 
-  _settings_dynamic_table_size = new_size;
+  _maximum_size = new_size;
   return true;
 }
 
-const uint32_t
-Http2DynamicTable::get_current_entry_num() const
+uint32_t
+HpackDynamicTable::length() const
 {
   return _headers.length();
 }
 
-bool
-Http2DynamicTable::is_header_in(const char *target_name, const char 
*target_value) const
-{
-  const MIMEField *field = _mhdr->field_find(target_name, strlen(target_name));
-
-  if (field) {
-    do {
-      int target_value_len = strlen(target_value);
-      int table_value_len = 0;
-      const char *table_value = field->value_get(&table_value_len);
-      if (ptr_len_cmp(target_value, target_value_len, table_value, 
table_value_len) == 0) {
-        return true;
-      }
-    } while (field->has_dups() && (field = field->m_next_dup) != NULL);
-  }
-
-  return false;
-}
-
-//
-// The first byte of an HPACK field unambiguously tells us what
-// kind of field it is. Field types are specified in the high 4 bits
-// and all bits are defined, so there's no way to get an invalid field type.
-//
-HpackFieldType
-hpack_parse_field_type(uint8_t ftype)
-{
-  if (ftype & 0x80) {
-    return HPACK_FIELD_INDEX;
-  }
-
-  if (ftype & 0x40) {
-    return HPACK_FIELD_INDEXED_LITERAL;
-  }
-
-  if (ftype & 0x20) {
-    return HPACK_FIELD_TABLESIZE_UPDATE;
-  }
-
-  if (ftype & 0x10) {
-    return HPACK_FIELD_NEVERINDEX_LITERAL;
-  }
-
-  ink_assert((ftype & 0xf0) == 0x0);
-  return HPACK_FIELD_NOINDEX_LITERAL;
-}
-
 //
 // [RFC 7541] 5.1. Integer representation
 //
@@ -508,13 +498,13 @@ encode_indexed_header_field(uint8_t *buf_start, const 
uint8_t *buf_end, uint32_t
   *p |= 0x80;
   p += len;
 
-  Debug("http2_hpack_encode", "Encoded field: %d", index);
+  Debug("hpack_encode", "Encoded field: %d", index);
   return p - buf_start;
 }
 
 int64_t
 encode_literal_header_field_with_indexed_name(uint8_t *buf_start, const 
uint8_t *buf_end, const MIMEFieldWrapper &header,
-                                              uint32_t index, 
Http2IndexingTable &indexing_table, HpackFieldType type)
+                                              uint32_t index, 
HpackIndexingTable &indexing_table, HpackFieldType type)
 {
   uint8_t *p = buf_start;
   int64_t len;
@@ -524,7 +514,7 @@ encode_literal_header_field_with_indexed_name(uint8_t 
*buf_start, const uint8_t
 
   switch (type) {
   case HPACK_FIELD_INDEXED_LITERAL:
-    indexing_table.add_header_field_to_dynamic_table(header.field_get());
+    indexing_table.add_header_field(header.field_get());
     prefix = 6;
     flag = 0x40;
     break;
@@ -560,13 +550,13 @@ encode_literal_header_field_with_indexed_name(uint8_t 
*buf_start, const uint8_t
     return -1;
   p += len;
 
-  Debug("http2_hpack_encode", "Encoded field: %d: %.*s", index, value_len, 
value);
+  Debug("hpack_encode", "Encoded field: %d: %.*s", index, value_len, value);
   return p - buf_start;
 }
 
 int64_t
 encode_literal_header_field_with_new_name(uint8_t *buf_start, const uint8_t 
*buf_end, const MIMEFieldWrapper &header,
-                                          Http2IndexingTable &indexing_table, 
HpackFieldType type)
+                                          HpackIndexingTable &indexing_table, 
HpackFieldType type)
 {
   uint8_t *p = buf_start;
   int64_t len;
@@ -576,7 +566,7 @@ encode_literal_header_field_with_new_name(uint8_t 
*buf_start, const uint8_t *buf
 
   switch (type) {
   case HPACK_FIELD_INDEXED_LITERAL:
-    indexing_table.add_header_field_to_dynamic_table(header.field_get());
+    indexing_table.add_header_field(header.field_get());
     flag = 0x40;
     break;
   case HPACK_FIELD_NOINDEX_LITERAL:
@@ -593,7 +583,8 @@ encode_literal_header_field_with_new_name(uint8_t 
*buf_start, const uint8_t *buf
   }
   *(p++) = flag;
 
-  // Convert field name to lower case
+  // Convert field name to lower case to follow HTTP2 spec.
+  // This conversion is needed because WKSs in MIMEFields is old fashioned
   Arena arena;
   int name_len;
   const char *name = header.name_get(&name_len);
@@ -603,8 +594,9 @@ encode_literal_header_field_with_new_name(uint8_t 
*buf_start, const uint8_t *buf
 
   // Name String
   len = encode_string(p, buf_end, lower_name, name_len);
-  if (len == -1)
+  if (len == -1) {
     return -1;
+  }
   p += len;
 
   // Value String
@@ -617,7 +609,7 @@ encode_literal_header_field_with_new_name(uint8_t 
*buf_start, const uint8_t *buf
 
   p += len;
 
-  Debug("http2_hpack_encode", "Encoded field: %.*s: %.*s", name_len, name, 
value_len, value);
+  Debug("hpack_encode", "Encoded field: %.*s: %.*s", name_len, name, 
value_len, value);
   return p - buf_start;
 }
 
@@ -703,7 +695,7 @@ decode_string(Arena &arena, char **str, uint32_t 
&str_length, const uint8_t *buf
 //
 int64_t
 decode_indexed_header_field(MIMEFieldWrapper &header, const uint8_t 
*buf_start, const uint8_t *buf_end,
-                            Http2IndexingTable &indexing_table)
+                            HpackIndexingTable &indexing_table)
 {
   uint32_t index = 0;
   int64_t len = 0;
@@ -716,14 +708,14 @@ decode_indexed_header_field(MIMEFieldWrapper &header, 
const uint8_t *buf_start,
     return HPACK_ERROR_COMPRESSION_ERROR;
   }
 
-  if (is_debug_tag_set("http2_hpack_decode")) {
+  if (is_debug_tag_set("hpack_decode")) {
     int decoded_name_len;
     const char *decoded_name = header.name_get(&decoded_name_len);
     int decoded_value_len;
     const char *decoded_value = header.value_get(&decoded_value_len);
 
     Arena arena;
-    Debug("http2_hpack_decode", "Decoded field: %s: %s", 
arena.str_store(decoded_name, decoded_name_len),
+    Debug("hpack_decode", "Decoded field: %s: %s", 
arena.str_store(decoded_name, decoded_name_len),
           arena.str_store(decoded_value, decoded_value_len));
   }
 
@@ -736,13 +728,14 @@ decode_indexed_header_field(MIMEFieldWrapper &header, 
const uint8_t *buf_start,
 //
 int64_t
 decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t 
*buf_start, const uint8_t *buf_end,
-                            Http2IndexingTable &indexing_table)
+                            HpackIndexingTable &indexing_table)
 {
   const uint8_t *p = buf_start;
   bool isIncremental = false;
   uint32_t index = 0;
   int64_t len = 0;
   HpackFieldType ftype = hpack_parse_field_type(*p);
+  bool has_http2_violation = false;
 
   if (ftype == HPACK_FIELD_INDEXED_LITERAL) {
     len = decode_integer(index, p, buf_end, 6);
@@ -773,9 +766,11 @@ decode_literal_header_field(MIMEFieldWrapper &header, 
const uint8_t *buf_start,
       return HPACK_ERROR_COMPRESSION_ERROR;
 
     // Check whether header field name is lower case
+    // XXX This check shouldn't be here because this rule is not a part of 
HPACK but HTTP2.
     for (uint32_t i = 0; i < name_str_len; i++) {
       if (ParseRules::is_upalpha(name_str[i])) {
-        return -2;
+        has_http2_violation = true;
+        break;
       }
     }
 
@@ -796,28 +791,33 @@ decode_literal_header_field(MIMEFieldWrapper &header, 
const uint8_t *buf_start,
 
   // Incremental Indexing adds header to header table as new entry
   if (isIncremental) {
-    indexing_table.add_header_field_to_dynamic_table(header.field_get());
+    indexing_table.add_header_field(header.field_get());
   }
 
   // Print decoded header field
-  if (is_debug_tag_set("http2_hpack_decode")) {
+  if (is_debug_tag_set("hpack_decode")) {
     int decoded_name_len;
     const char *decoded_name = header.name_get(&decoded_name_len);
     int decoded_value_len;
     const char *decoded_value = header.value_get(&decoded_value_len);
 
-    Debug("http2_hpack_decode", "Decoded field: %s: %s", 
arena.str_store(decoded_name, decoded_name_len),
+    Debug("hpack_decode", "Decoded field: %s: %s", 
arena.str_store(decoded_name, decoded_name_len),
           arena.str_store(decoded_value, decoded_value_len));
   }
 
-  return p - buf_start;
+  if (has_http2_violation) {
+    // XXX Need to return the length to continue decoding
+    return -(p - buf_start);
+  } else {
+    return p - buf_start;
+  }
 }
 
 //
 // [RFC 7541] 6.3. Dynamic Table Size Update
 //
 int64_t
-update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_end, 
Http2IndexingTable &indexing_table)
+update_dynamic_table_size(const uint8_t *buf_start, const uint8_t *buf_end, 
HpackIndexingTable &indexing_table)
 {
   if (buf_start == buf_end)
     return HPACK_ERROR_COMPRESSION_ERROR;
@@ -828,9 +828,119 @@ update_dynamic_table_size(const uint8_t *buf_start, const 
uint8_t *buf_end, Http
   if (len == HPACK_ERROR_COMPRESSION_ERROR)
     return HPACK_ERROR_COMPRESSION_ERROR;
 
-  if (indexing_table.set_dynamic_table_size(size) == false) {
+  if (indexing_table.update_maximum_size(size) == false) {
     return HPACK_ERROR_COMPRESSION_ERROR;
   }
 
   return len;
 }
+
+int64_t
+hpack_decode_header_block(HpackIndexingTable &indexing_table, HTTPHdr *hdr, 
const uint8_t *in_buf, const size_t in_buf_len)
+{
+  const uint8_t *cursor = in_buf;
+  const uint8_t *const in_buf_end = in_buf + in_buf_len;
+  HdrHeap *heap = hdr->m_heap;
+  HTTPHdrImpl *hh = hdr->m_http;
+  bool header_field_started = false;
+  bool has_http2_violation = false;
+
+  while (cursor < in_buf_end) {
+    int64_t read_bytes = 0;
+
+    // decode a header field encoded by HPACK
+    MIMEField *field = mime_field_create(heap, hh->m_fields_impl);
+    MIMEFieldWrapper header(field, heap, hh->m_fields_impl);
+    HpackFieldType ftype = hpack_parse_field_type(*cursor);
+
+    switch (ftype) {
+    case HPACK_FIELD_INDEX:
+      read_bytes = decode_indexed_header_field(header, cursor, in_buf_end, 
indexing_table);
+      if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
+        return HPACK_ERROR_COMPRESSION_ERROR;
+      }
+      cursor += read_bytes;
+      header_field_started = true;
+      break;
+    case HPACK_FIELD_INDEXED_LITERAL:
+    case HPACK_FIELD_NOINDEX_LITERAL:
+    case HPACK_FIELD_NEVERINDEX_LITERAL:
+      read_bytes = decode_literal_header_field(header, cursor, in_buf_end, 
indexing_table);
+      if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
+        return HPACK_ERROR_COMPRESSION_ERROR;
+      }
+      if (read_bytes < 0) {
+        has_http2_violation = true;
+        read_bytes = -read_bytes;
+      }
+      cursor += read_bytes;
+      header_field_started = true;
+      break;
+    case HPACK_FIELD_TABLESIZE_UPDATE:
+      if (header_field_started) {
+        return HPACK_ERROR_COMPRESSION_ERROR;
+      }
+      read_bytes = update_dynamic_table_size(cursor, in_buf_end, 
indexing_table);
+      if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
+        return HPACK_ERROR_COMPRESSION_ERROR;
+      }
+      cursor += read_bytes;
+      continue;
+    }
+    // Store to HdrHeap
+    mime_hdr_field_attach(hh->m_fields_impl, field, 1, NULL);
+  }
+  // Parsing all headers is done
+  if (has_http2_violation) {
+    return -(cursor - in_buf);
+  } else {
+    return cursor - in_buf;
+  }
+}
+
+int64_t
+hpack_encode_header_block(HpackIndexingTable &indexing_table, uint8_t 
*out_buf, const size_t out_buf_len, HTTPHdr *hdr)
+{
+  uint8_t *cursor = out_buf;
+  const uint8_t *const out_buf_end = out_buf + out_buf_len;
+  int64_t written;
+
+  ink_assert(http_hdr_type_get(hdr->m_http) != HTTP_TYPE_UNKNOWN);
+
+  MIMEFieldIter field_iter;
+  for (MIMEField *field = hdr->iter_get_first(&field_iter); field != NULL; 
field = hdr->iter_get_next(&field_iter)) {
+    HpackFieldType field_type;
+    MIMEFieldWrapper header(field, hdr->m_heap, hdr->m_http->m_fields_impl);
+    int name_len;
+    int value_len;
+    const char *name = header.name_get(&name_len);
+    header.value_get(&value_len);
+    // Choose field representation (See RFC7541 7.1.3)
+    // - Authorization header obviously should not be indexed
+    // - Short Cookie header should not be indexed because of low entropy
+    if ((ptr_len_casecmp(name, name_len, MIME_FIELD_COOKIE, MIME_LEN_COOKIE) 
== 0 && value_len < 20) ||
+        (ptr_len_casecmp(name, name_len, MIME_FIELD_AUTHORIZATION, 
MIME_LEN_AUTHORIZATION) == 0)) {
+      field_type = HPACK_FIELD_NEVERINDEX_LITERAL;
+    } else {
+      field_type = HPACK_FIELD_INDEXED_LITERAL;
+    }
+    const HpackLookupResult result = indexing_table.lookup(header);
+    switch (result.match_type) {
+    case HPACK_NO_MATCH:
+      written = encode_literal_header_field_with_new_name(cursor, out_buf_end, 
header, indexing_table, field_type);
+      break;
+    case HPACK_NAME_MATCH:
+      written =
+        encode_literal_header_field_with_indexed_name(cursor, out_buf_end, 
header, result.index, indexing_table, field_type);
+      break;
+    case HPACK_EXACT_MATCH:
+      written = encode_indexed_header_field(cursor, out_buf_end, result.index);
+      break;
+    }
+    if (written == HPACK_ERROR_COMPRESSION_ERROR) {
+      return HPACK_ERROR_COMPRESSION_ERROR;
+    }
+    cursor += written;
+  }
+  return cursor - out_buf;
+}

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/HPACK.h
----------------------------------------------------------------------
diff --git a/proxy/http2/HPACK.h b/proxy/http2/HPACK.h
index 14430da..37e3a65 100644
--- a/proxy/http2/HPACK.h
+++ b/proxy/http2/HPACK.h
@@ -29,23 +29,8 @@
 #include "ts/Diags.h"
 #include "HTTP.h"
 
-// Constant strings for pseudo headers of HPACK
-extern const char *HPACK_VALUE_SCHEME;
-extern const char *HPACK_VALUE_METHOD;
-extern const char *HPACK_VALUE_AUTHORITY;
-extern const char *HPACK_VALUE_PATH;
-extern const char *HPACK_VALUE_STATUS;
-
-extern const unsigned HPACK_LEN_SCHEME;
-extern const unsigned HPACK_LEN_METHOD;
-extern const unsigned HPACK_LEN_AUTHORITY;
-extern const unsigned HPACK_LEN_PATH;
-extern const unsigned HPACK_LEN_STATUS;
-
 // It means that any header field can be compressed/decompressed by ATS
 const static int HPACK_ERROR_COMPRESSION_ERROR = -1;
-// It means that any header field is invalid in HTTP/2 spec
-const static int HPACK_ERROR_HTTP2_PROTOCOL_ERROR = -2;
 
 enum HpackFieldType {
   HPACK_FIELD_INDEX,              // [RFC 7541] 6.1. Indexed Header Field 
Representation
@@ -55,6 +40,28 @@ enum HpackFieldType {
   HPACK_FIELD_TABLESIZE_UPDATE,   // [RFC 7541] 6.3. Dynamic Table Size Update
 };
 
+enum HpackIndexType {
+  HPACK_INDEX_TYPE_NONE,
+  HPACK_INDEX_TYPE_STATIC,
+  HPACK_INDEX_TYPE_DYNAMIC,
+};
+
+enum HpackMatchType {
+  HPACK_NO_MATCH,
+  HPACK_NAME_MATCH,
+  HPACK_EXACT_MATCH,
+};
+
+// Result of looking for a header field in IndexingTable
+struct HpackLookupResult {
+  HpackLookupResult() : index(0), index_type(HPACK_INDEX_TYPE_NONE), 
match_type(HPACK_NO_MATCH) {}
+
+  int index;
+  HpackIndexType index_type;
+  HpackMatchType match_type;
+};
+
+
 class MIMEFieldWrapper
 {
 public:
@@ -96,25 +103,17 @@ private:
   MIMEHdrImpl *_mh;
 };
 
-// Result of looking for a header field in IndexingTable
-struct Http2LookupIndexResult {
-  Http2LookupIndexResult() : index(0), value_is_indexed(false) {}
-
-  int index;
-  bool value_is_indexed;
-};
-
 // [RFC 7541] 2.3.2. Dynamic Table
-class Http2DynamicTable
+class HpackDynamicTable
 {
 public:
-  Http2DynamicTable() : _current_size(0), _settings_dynamic_table_size(4096)
+  HpackDynamicTable(uint32_t size) : _current_size(0), _maximum_size(size)
   {
     _mhdr = new MIMEHdr();
     _mhdr->create();
   }
 
-  ~Http2DynamicTable()
+  ~HpackDynamicTable()
   {
     _headers.clear();
     _mhdr->fields_clear();
@@ -125,64 +124,60 @@ public:
   const MIMEField *get_header_field(uint32_t index) const;
   void add_header_field(const MIMEField *field);
 
-  uint32_t get_size() const;
-  bool set_size(uint32_t new_size);
+  uint32_t size() const;
+  bool update_maximum_size(uint32_t new_size);
 
-  const uint32_t get_current_entry_num() const;
-
-  // For regression test
-  bool is_header_in(const char *target_name, const char *target_value) const;
+  uint32_t length() const;
 
 private:
   uint32_t _current_size;
-  uint32_t _settings_dynamic_table_size;
+  uint32_t _maximum_size;
 
   MIMEHdr *_mhdr;
   Vec<MIMEField *> _headers;
 };
 
-
 // [RFC 7541] 2.3. Indexing Table
-class Http2IndexingTable
+class HpackIndexingTable
 {
 public:
-  Http2LookupIndexResult get_index(const MIMEFieldWrapper &field) const;
+  HpackIndexingTable(uint32_t size) { _dynamic_table = new 
HpackDynamicTable(size); }
+
+  ~HpackIndexingTable() { delete _dynamic_table; }
+
+  HpackLookupResult lookup(const MIMEFieldWrapper &field) const;
+  HpackLookupResult lookup(const char *name, int name_len, const char *value, 
int value_len) const;
   int get_header_field(uint32_t index, MIMEFieldWrapper &header_field) const;
 
-  void add_header_field_to_dynamic_table(const MIMEField *field);
-  uint32_t get_dynamic_table_size() const;
-  bool set_dynamic_table_size(uint32_t new_size);
-  bool is_header_in_dynamic_table(const char *target_name, const char 
*target_value) const;
+  void add_header_field(const MIMEField *field);
+  uint32_t size() const;
+  bool update_maximum_size(uint32_t new_size);
 
 private:
-  Http2DynamicTable _dynamic_table;
+  HpackDynamicTable *_dynamic_table;
 };
 
-HpackFieldType hpack_parse_field_type(uint8_t ftype);
-
-static inline bool
-hpack_field_is_literal(HpackFieldType ftype)
-{
-  return ftype == HPACK_FIELD_INDEXED_LITERAL || ftype == 
HPACK_FIELD_NOINDEX_LITERAL || ftype == HPACK_FIELD_NEVERINDEX_LITERAL;
-}
 
+// Low level interfaces
 int64_t encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint32_t 
value, uint8_t n);
 int64_t decode_integer(uint32_t &dst, const uint8_t *buf_start, const uint8_t 
*buf_end, uint8_t n);
 int64_t encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char 
*value, size_t value_len);
 int64_t decode_string(Arena &arena, char **str, uint32_t &str_length, const 
uint8_t *buf_start, const uint8_t *buf_end);
-
 int64_t encode_indexed_header_field(uint8_t *buf_start, const uint8_t 
*buf_end, uint32_t index);
 int64_t encode_literal_header_field_with_indexed_name(uint8_t *buf_start, 
const uint8_t *buf_end, const MIMEFieldWrapper &header,
-                                                      uint32_t index, 
Http2IndexingTable &indexing_table, HpackFieldType type);
+                                                      uint32_t index, 
HpackIndexingTable &indexing_table, HpackFieldType type);
 int64_t encode_literal_header_field_with_new_name(uint8_t *buf_start, const 
uint8_t *buf_end, const MIMEFieldWrapper &header,
-                                                  Http2IndexingTable 
&indexing_table, HpackFieldType type);
-
-// When these functions returns minus value, any error occurs
-// TODO Separate error code and length of processed buffer
+                                                  HpackIndexingTable 
&indexing_table, HpackFieldType type);
 int64_t decode_indexed_header_field(MIMEFieldWrapper &header, const uint8_t 
*buf_start, const uint8_t *buf_end,
-                                    Http2IndexingTable &indexing_table);
+                                    HpackIndexingTable &indexing_table);
 int64_t decode_literal_header_field(MIMEFieldWrapper &header, const uint8_t 
*buf_start, const uint8_t *buf_end,
-                                    Http2IndexingTable &indexing_table);
-int64_t update_dynamic_table_size(const uint8_t *buf_start, const uint8_t 
*buf_end, Http2IndexingTable &indexing_table);
+                                    HpackIndexingTable &indexing_table);
+int64_t update_dynamic_table_size(const uint8_t *buf_start, const uint8_t 
*buf_end, HpackIndexingTable &indexing_table);
+
+
+// High level interfaces
+typedef HpackIndexingTable HpackHandle;
+int64_t hpack_decode_header_block(HpackHandle &handle, HTTPHdr *hdr, const 
uint8_t *in_buf, const size_t in_buf_len);
+int64_t hpack_encode_header_block(HpackHandle &handle, uint8_t *out_buf, const 
size_t out_buf_len, HTTPHdr *hdr);
 
 #endif /* __HPACK_H__ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/HTTP2.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/HTTP2.cc b/proxy/http2/HTTP2.cc
index 3eac878..f563210 100644
--- a/proxy/http2/HTTP2.cc
+++ b/proxy/http2/HTTP2.cc
@@ -29,7 +29,21 @@
 #include "P_RecProcess.h"
 
 const char *const HTTP2_CONNECTION_PREFACE = "PRI * 
HTTP/2.0\r\n\r\nSM\r\n\r\n";
-static size_t HPACK_LEN_STATUS_VALUE_STR = 3;
+
+// Constant strings for pseudo headers
+const char *HTTP2_VALUE_SCHEME = ":scheme";
+const char *HTTP2_VALUE_METHOD = ":method";
+const char *HTTP2_VALUE_AUTHORITY = ":authority";
+const char *HTTP2_VALUE_PATH = ":path";
+const char *HTTP2_VALUE_STATUS = ":status";
+
+const unsigned HTTP2_LEN_SCHEME = countof(":scheme") - 1;
+const unsigned HTTP2_LEN_METHOD = countof(":method") - 1;
+const unsigned HTTP2_LEN_AUTHORITY = countof(":authority") - 1;
+const unsigned HTTP2_LEN_PATH = countof(":path") - 1;
+const unsigned HTTP2_LEN_STATUS = countof(":status") - 1;
+
+static size_t HTTP2_LEN_STATUS_VALUE_STR = 3;
 
 // Statistics
 RecRawStatBlock *http2_rsb;
@@ -391,7 +405,7 @@ http2_parse_window_update(IOVec iov, uint32_t &size)
 }
 
 MIMEParseResult
-convert_from_2_to_1_1_header(HTTPHdr *headers)
+http2_convert_header_from_2_to_1_1(HTTPHdr *headers)
 {
   MIMEField *field;
 
@@ -402,19 +416,19 @@ convert_from_2_to_1_1_header(HTTPHdr *headers)
     int scheme_len, authority_len, path_len, method_len;
 
     // Get values of :scheme, :authority and :path to assemble requested URL
-    if ((field = headers->field_find(HPACK_VALUE_SCHEME, HPACK_LEN_SCHEME)) != 
NULL && field->value_is_valid()) {
+    if ((field = headers->field_find(HTTP2_VALUE_SCHEME, HTTP2_LEN_SCHEME)) != 
NULL && field->value_is_valid()) {
       scheme = field->value_get(&scheme_len);
     } else {
       return PARSE_ERROR;
     }
 
-    if ((field = headers->field_find(HPACK_VALUE_AUTHORITY, 
HPACK_LEN_AUTHORITY)) != NULL && field->value_is_valid()) {
+    if ((field = headers->field_find(HTTP2_VALUE_AUTHORITY, 
HTTP2_LEN_AUTHORITY)) != NULL && field->value_is_valid()) {
       authority = field->value_get(&authority_len);
     } else {
       return PARSE_ERROR;
     }
 
-    if ((field = headers->field_find(HPACK_VALUE_PATH, HPACK_LEN_PATH)) != 
NULL && field->value_is_valid()) {
+    if ((field = headers->field_find(HTTP2_VALUE_PATH, HTTP2_LEN_PATH)) != 
NULL && field->value_is_valid()) {
       path = field->value_get(&path_len);
     } else {
       return PARSE_ERROR;
@@ -434,7 +448,7 @@ convert_from_2_to_1_1_header(HTTPHdr *headers)
     arena.str_free(url);
 
     // Get value of :method
-    if ((field = headers->field_find(HPACK_VALUE_METHOD, HPACK_LEN_METHOD)) != 
NULL && field->value_is_valid()) {
+    if ((field = headers->field_find(HTTP2_VALUE_METHOD, HTTP2_LEN_METHOD)) != 
NULL && field->value_is_valid()) {
       method = field->value_get(&method_len);
 
       int method_wks_idx = hdrtoken_tokenize(method, method_len);
@@ -454,15 +468,15 @@ convert_from_2_to_1_1_header(HTTPHdr *headers)
     http_hdr_version_set(headers->m_http, version);
 
     // Remove HTTP/2 style headers
-    headers->field_delete(HPACK_VALUE_SCHEME, HPACK_LEN_SCHEME);
-    headers->field_delete(HPACK_VALUE_METHOD, HPACK_LEN_METHOD);
-    headers->field_delete(HPACK_VALUE_AUTHORITY, HPACK_LEN_AUTHORITY);
-    headers->field_delete(HPACK_VALUE_PATH, HPACK_LEN_PATH);
+    headers->field_delete(HTTP2_VALUE_SCHEME, HTTP2_LEN_SCHEME);
+    headers->field_delete(HTTP2_VALUE_METHOD, HTTP2_LEN_METHOD);
+    headers->field_delete(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY);
+    headers->field_delete(HTTP2_VALUE_PATH, HTTP2_LEN_PATH);
   } else {
     int status_len;
     const char *status;
 
-    if ((field = headers->field_find(HPACK_VALUE_STATUS, HPACK_LEN_STATUS)) != 
NULL) {
+    if ((field = headers->field_find(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS)) != 
NULL) {
       status = field->value_get(&status_len);
       headers->status_set(http_parse_status(status, status + status_len));
     } else {
@@ -470,7 +484,7 @@ convert_from_2_to_1_1_header(HTTPHdr *headers)
     }
 
     // Remove HTTP/2 style headers
-    headers->field_delete(HPACK_VALUE_STATUS, HPACK_LEN_STATUS);
+    headers->field_delete(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS);
   }
 
   // Check validity of all names and values
@@ -484,246 +498,168 @@ convert_from_2_to_1_1_header(HTTPHdr *headers)
   return PARSE_DONE;
 }
 
-static int64_t
-http2_write_header_field(uint8_t *out, const uint8_t *end, MIMEFieldWrapper 
&header, Http2IndexingTable &indexing_table)
-{
-  HpackFieldType field_type = HPACK_FIELD_INDEXED_LITERAL;
-
-  // Cookie less that 20 bytes and Authorization are never indexed
-  // This policy is refer to Firefox and nghttp2
-  int name_len = 0, value_len = 0;
-  const char *name = header.name_get(&name_len);
-  header.value_get(&value_len);
-  if ((ptr_len_casecmp(name, name_len, MIME_FIELD_COOKIE, MIME_LEN_COOKIE) == 
0 && value_len < 20) ||
-      (ptr_len_casecmp(name, name_len, MIME_FIELD_AUTHORIZATION, 
MIME_LEN_AUTHORIZATION) == 0)) {
-    field_type = HPACK_FIELD_NEVERINDEX_LITERAL;
-  }
-
-  // TODO Enable to configure selecting header field representation
+void
+http2_convert_header_from_1_1_to_2(HTTPHdr *headers)
+{
+  HTTPHdr tmp;
+  tmp.create(http_hdr_type_get(headers->m_http));
+  tmp.copy(headers);
+  headers->fields_clear();
+
+  if (http_hdr_type_get(tmp.m_http) == HTTP_TYPE_RESPONSE) {
+    char status_str[HTTP2_LEN_STATUS_VALUE_STR + 1];
+    snprintf(status_str, sizeof(status_str), "%d", tmp.status_get());
+
+    // Add ':status' header field
+    MIMEField *status_field = headers->field_create(HTTP2_VALUE_STATUS, 
HTTP2_LEN_STATUS);
+    status_field->value_set(headers->m_heap, headers->m_mime, status_str, 
HTTP2_LEN_STATUS_VALUE_STR);
+    headers->field_attach(status_field);
+
+    MIMEFieldIter field_iter;
+    for (MIMEField *field = tmp.iter_get_first(&field_iter); field != NULL; 
field = tmp.iter_get_next(&field_iter)) {
+      // Intermediaries SHOULD remove connection-specific header fields.
+      const char *name;
+      int name_len;
+      const char *value;
+      int value_len;
+      name = field->name_get(&name_len);
+      if ((name_len == MIME_LEN_CONNECTION && strncasecmp(name, 
MIME_FIELD_CONNECTION, name_len) == 0) ||
+          (name_len == MIME_LEN_KEEP_ALIVE && strncasecmp(name, 
MIME_FIELD_KEEP_ALIVE, name_len) == 0) ||
+          (name_len == MIME_LEN_PROXY_CONNECTION && strncasecmp(name, 
MIME_FIELD_PROXY_CONNECTION, name_len) == 0) ||
+          (name_len == MIME_LEN_TRANSFER_ENCODING && strncasecmp(name, 
MIME_FIELD_TRANSFER_ENCODING, name_len) == 0) ||
+          (name_len == MIME_LEN_UPGRADE && strncasecmp(name, 
MIME_FIELD_UPGRADE, name_len) == 0)) {
+        continue;
+      }
 
-  const Http2LookupIndexResult &result = indexing_table.get_index(header);
-  if (result.index > 0) {
-    if (result.value_is_indexed) {
-      return encode_indexed_header_field(out, end, result.index);
-    } else {
-      return encode_literal_header_field_with_indexed_name(out, end, header, 
result.index, indexing_table, field_type);
+      MIMEField *newfield;
+      name = field->name_get(&name_len);
+      newfield = headers->field_create(name, name_len);
+      value = field->value_get(&value_len);
+      newfield->value_set(headers->m_heap, headers->m_mime, value, value_len);
+      tmp.field_delete(field);
+      headers->field_attach(newfield);
     }
-  } else {
-    return encode_literal_header_field_with_new_name(out, end, header, 
indexing_table, field_type);
   }
+  tmp.destroy();
 }
 
-int64_t
-http2_write_psuedo_headers(HTTPHdr *in, uint8_t *out, uint64_t out_len, 
Http2IndexingTable &indexing_table)
+Http2ErrorCode
+http2_encode_header_blocks(HTTPHdr *in, uint8_t *out, uint32_t out_len, 
uint32_t *len_written, HpackHandle &handle)
 {
-  uint8_t *p = out;
-  uint8_t *end = out + out_len;
-  int64_t len;
-
-  ink_assert(http_hdr_type_get(in->m_http) != HTTP_TYPE_UNKNOWN);
-
-  // TODO Check whether buffer size is enough
-
-  // Set psuedo header
-  if (http_hdr_type_get(in->m_http) == HTTP_TYPE_RESPONSE) {
-    char status_str[HPACK_LEN_STATUS_VALUE_STR + 1];
-    snprintf(status_str, sizeof(status_str), "%d", in->status_get());
-
-    // Add 'Status:' dummy header field
-    MIMEField *status_field = mime_field_create(in->m_heap, 
in->m_http->m_fields_impl);
-    mime_field_name_value_set(in->m_heap, in->m_mime, status_field, -1, 
HPACK_VALUE_STATUS, HPACK_LEN_STATUS, status_str,
-                              HPACK_LEN_STATUS_VALUE_STR, 0, HPACK_LEN_STATUS 
+ HPACK_LEN_STATUS_VALUE_STR, true);
-    mime_hdr_field_attach(in->m_mime, status_field, 1, NULL);
-
-    // Encode psuedo headers by HPACK
-    MIMEFieldWrapper header(status_field, in->m_heap, 
in->m_http->m_fields_impl);
-
-    len = http2_write_header_field(p, end, header, indexing_table);
-    if (len == -1)
-      return -1;
-    p += len;
-
-    // Remove dummy header field
-    in->field_delete(HPACK_VALUE_STATUS, HPACK_LEN_STATUS);
+  // TODO: It would be better to split Cookie header value
+  int64_t result = hpack_encode_header_block(handle, out, out_len, in);
+  if (result < 0) {
+    return HTTP2_ERROR_COMPRESSION_ERROR;
   }
-
-  return p - out;
-}
-
-int64_t
-http2_write_header_fragment(HTTPHdr *in, MIMEFieldIter &field_iter, uint8_t 
*out, uint64_t out_len,
-                            Http2IndexingTable &indexing_table, bool &cont)
-{
-  uint8_t *p = out;
-  uint8_t *end = out + out_len;
-  int64_t len;
-
-  ink_assert(http_hdr_type_get(in->m_http) != HTTP_TYPE_UNKNOWN);
-  ink_assert(in);
-
-  // TODO Get a index value from the tables for the header field, and then
-  // choose a representation type.
-  // TODO Each indexing types per field should be passed by a caller, HTTP/2
-  // implementation.
-
-  // Get first header field which is required encoding
-  MIMEField *field;
-  if (!field_iter.m_block) {
-    field = in->iter_get_first(&field_iter);
-  } else {
-    field = in->iter_get(&field_iter);
+  if (len_written) {
+    *len_written = result;
   }
-
-  // Set mime headers
-  cont = false;
-  for (; field != NULL; field = in->iter_get_next(&field_iter)) {
-    // Intermediaries SHOULD remove connection-specific header fields.
-    int name_len;
-    const char *name = field->name_get(&name_len);
-    if ((name_len == MIME_LEN_CONNECTION && strncasecmp(name, 
MIME_FIELD_CONNECTION, name_len) == 0) ||
-        (name_len == MIME_LEN_KEEP_ALIVE && strncasecmp(name, 
MIME_FIELD_KEEP_ALIVE, name_len) == 0) ||
-        (name_len == MIME_LEN_PROXY_CONNECTION && strncasecmp(name, 
MIME_FIELD_PROXY_CONNECTION, name_len) == 0) ||
-        (name_len == MIME_LEN_TRANSFER_ENCODING && strncasecmp(name, 
MIME_FIELD_TRANSFER_ENCODING, name_len) == 0) ||
-        (name_len == MIME_LEN_UPGRADE && strncasecmp(name, MIME_FIELD_UPGRADE, 
name_len) == 0)) {
-      continue;
-    }
-
-    MIMEFieldWrapper header(field, in->m_heap, in->m_http->m_fields_impl);
-    if ((len = http2_write_header_field(p, end, header, indexing_table)) == 
-1) {
-      if (p == out) {
-        // no progress was made, header was too big for the buffer, skipping 
for now
-        continue;
-      }
-      if (!cont) {
-        // Parsing a part of headers is done
-        cont = true;
-        return p - out;
-      } else {
-        // Parse error
-        return -1;
-      }
-    }
-    p += len;
-  }
-
-  // Parsing all headers is done
-  return p - out;
+  return HTTP2_ERROR_NO_ERROR;
 }
 
 /*
  * Decode Header Blocks to Header List.
  */
-int64_t
-http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const 
uint8_t *buf_end, Http2IndexingTable &indexing_table,
+Http2ErrorCode
+http2_decode_header_blocks(HTTPHdr *hdr, const uint8_t *buf_start, const 
uint32_t buf_len, uint32_t *len_read, HpackHandle &handle,
                            bool &trailing_header)
 {
-  const uint8_t *cursor = buf_start;
-  HdrHeap *heap = hdr->m_heap;
-  HTTPHdrImpl *hh = hdr->m_http;
-  bool header_field_started = false;
+  const MIMEField *field;
+  const char *value;
+  int len;
   bool is_trailing_header = trailing_header;
+  int64_t result = hpack_decode_header_block(handle, hdr, buf_start, buf_len);
 
-  while (cursor < buf_end) {
-    int64_t read_bytes = 0;
+  if (result < 0) {
+    if (result == HPACK_ERROR_COMPRESSION_ERROR) {
+      return HTTP2_ERROR_COMPRESSION_ERROR;
+    }
+    return HTTP2_ERROR_PROTOCOL_ERROR;
+  }
+  if (len_read) {
+    *len_read = result;
+  }
 
-    // decode a header field encoded by HPACK
-    MIMEField *field = mime_field_create(heap, hh->m_fields_impl);
-    MIMEFieldWrapper header(field, heap, hh->m_fields_impl);
-    HpackFieldType ftype = hpack_parse_field_type(*cursor);
 
-    switch (ftype) {
-    case HPACK_FIELD_INDEX:
-      read_bytes = decode_indexed_header_field(header, cursor, buf_end, 
indexing_table);
-      if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
-        return HPACK_ERROR_COMPRESSION_ERROR;
-      }
-      cursor += read_bytes;
-      header_field_started = true;
-      break;
-    case HPACK_FIELD_INDEXED_LITERAL:
-    case HPACK_FIELD_NOINDEX_LITERAL:
-    case HPACK_FIELD_NEVERINDEX_LITERAL:
-      read_bytes = decode_literal_header_field(header, cursor, buf_end, 
indexing_table);
-      if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
-        return HPACK_ERROR_COMPRESSION_ERROR;
-      }
-      cursor += read_bytes;
-      header_field_started = true;
-      break;
-    case HPACK_FIELD_TABLESIZE_UPDATE:
-      if (header_field_started) {
-        return HPACK_ERROR_COMPRESSION_ERROR;
+  MIMEFieldIter iter;
+  unsigned int expected_pseudo_header_count = 4;
+  unsigned int pseudo_header_count = 0;
+
+  if (is_trailing_header) {
+    expected_pseudo_header_count = 0;
+  }
+  for (field = hdr->iter_get_first(&iter); field != NULL; field = 
hdr->iter_get_next(&iter)) {
+    value = field->name_get(&len);
+    // Pseudo headers must appear before regular headers
+    if (len && value[0] == ':') {
+      ++pseudo_header_count;
+      if (pseudo_header_count > expected_pseudo_header_count) {
+        return HTTP2_ERROR_PROTOCOL_ERROR;
       }
-      read_bytes = update_dynamic_table_size(cursor, buf_end, indexing_table);
-      if (read_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
-        return HPACK_ERROR_COMPRESSION_ERROR;
+    } else {
+      if (pseudo_header_count != expected_pseudo_header_count) {
+        return HTTP2_ERROR_PROTOCOL_ERROR;
       }
-      cursor += read_bytes;
-      continue;
-    }
-
-    int name_len = 0;
-    const char *name = field->name_get(&name_len);
-
-    // ':' started header name is only allowed for pseudo headers
-    if (hdr->fields_count() >= 4 && (name_len <= 0 || name[0] == ':')) {
-      // Decoded header field is invalid
-      return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
     }
+    // Check whether header field name is lower case
+    // This check should be here but it will fail because WKSs in MIMEField is 
old fashioned.
+    // for (uint32_t i = 0; i < len; ++i) {
+    //   if (ParseRules::is_upalpha(value[i])) {
+    //     return HTTP2_ERROR_PROTOCOL_ERROR;
+    //   }
+    // }
+  }
 
-    // rfc7540,sec8.1.2.2: Any message containing connection-specific header
-    // fields MUST be treated as malformed
-    if (name == MIME_FIELD_CONNECTION) {
-      return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
-    }
+  // rfc7540,sec8.1.2.2: Any message containing connection-specific header
+  // fields MUST be treated as malformed
+  if (hdr->field_find(MIME_FIELD_CONNECTION, MIME_LEN_CONNECTION) != NULL) {
+    return HTTP2_ERROR_PROTOCOL_ERROR;
+  }
 
-    // :path pseudo header MUST NOT empty for http or https URIs
-    if (static_cast<unsigned>(name_len) == HPACK_LEN_PATH && strncmp(name, 
HPACK_VALUE_PATH, name_len) == 0) {
-      int value_len = 0;
-      field->value_get(&value_len);
-      if (value_len == 0) {
-        return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
-      }
+  // :path pseudo header MUST NOT empty for http or https URIs
+  field = hdr->field_find(HTTP2_VALUE_PATH, HTTP2_LEN_PATH);
+  if (field) {
+    field->value_get(&len);
+    if (len == 0) {
+      return HTTP2_ERROR_PROTOCOL_ERROR;
     }
+  }
 
-    // when The TE header field is received, it MUST NOT contain any value 
other than "trailers".
-    if (name_len == MIME_LEN_TE && strncmp(name, MIME_FIELD_TE, name_len) == 
0) {
-      int value_len = 0;
-      const char *value = field->value_get(&value_len);
-      const char trailers[] = "trailers";
-      if (!(value_len == (sizeof(trailers) - 1) && memcmp(value, trailers, 
value_len) == 0)) {
-        return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
-      }
-    }
+  // turn on that we have a trailer header
+  const char trailer_name[] = "trailer";
+  field = hdr->field_find(trailer_name, sizeof(trailer_name) - 1);
+  if (field) {
+    trailing_header = true;
+  }
 
-    // turn on that we have a trailer header
-    const char trailer_name[] = "trailer";
-    if (name_len == (sizeof(trailer_name) - 1) && strncmp(name, trailer_name, 
sizeof(trailer_name) - 1) == 0) {
-      trailing_header = true;
+  // when The TE header field is received, it MUST NOT contain any
+  // value other than "trailers".
+  field = hdr->field_find(MIME_FIELD_TE, MIME_LEN_TE);
+  if (field) {
+    value = field->value_get(&len);
+    if (!(len == 8 && memcmp(value, "trailers", 8) == 0)) {
+      return HTTP2_ERROR_PROTOCOL_ERROR;
     }
-
-    // Store to HdrHeap
-    mime_hdr_field_attach(hh->m_fields_impl, field, 1, NULL);
   }
 
   if (!is_trailing_header) {
     // Check psuedo headers
     if (hdr->fields_count() >= 4) {
-      if (hdr->field_find(HPACK_VALUE_SCHEME, HPACK_LEN_SCHEME) == NULL ||
-          hdr->field_find(HPACK_VALUE_METHOD, HPACK_LEN_METHOD) == NULL ||
-          hdr->field_find(HPACK_VALUE_PATH, HPACK_LEN_PATH) == NULL ||
-          hdr->field_find(HPACK_VALUE_AUTHORITY, HPACK_LEN_AUTHORITY) == NULL) 
{
+      if (hdr->field_find(HTTP2_VALUE_SCHEME, HTTP2_LEN_SCHEME) == NULL ||
+          hdr->field_find(HTTP2_VALUE_METHOD, HTTP2_LEN_METHOD) == NULL ||
+          hdr->field_find(HTTP2_VALUE_PATH, HTTP2_LEN_PATH) == NULL ||
+          hdr->field_find(HTTP2_VALUE_AUTHORITY, HTTP2_LEN_AUTHORITY) == NULL 
||
+          hdr->field_find(HTTP2_VALUE_STATUS, HTTP2_LEN_STATUS) != NULL) {
         // Decoded header field is invalid
-        return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
+        return HTTP2_ERROR_PROTOCOL_ERROR;
       }
     } else {
       // Psuedo headers is insufficient
-      return HPACK_ERROR_HTTP2_PROTOCOL_ERROR;
+      return HTTP2_ERROR_PROTOCOL_ERROR;
     }
   }
 
-  // Parsing all headers is done
-  return cursor - buf_start;
+  return HTTP2_ERROR_NO_ERROR;
 }
 
 // Initialize this subsystem with librecords configs (for now)

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/HTTP2.h
----------------------------------------------------------------------
diff --git a/proxy/http2/HTTP2.h b/proxy/http2/HTTP2.h
index 9b62b17..a70703c 100644
--- a/proxy/http2/HTTP2.h
+++ b/proxy/http2/HTTP2.h
@@ -326,13 +326,13 @@ bool http2_parse_goaway(IOVec, Http2Goaway &);
 
 bool http2_parse_window_update(IOVec, uint32_t &);
 
-int64_t http2_decode_header_blocks(HTTPHdr *, const uint8_t *, const uint8_t 
*, Http2IndexingTable &, bool &);
+Http2ErrorCode http2_decode_header_blocks(HTTPHdr *, const uint8_t *, const 
uint32_t, uint32_t *, HpackHandle &, bool &);
 
-MIMEParseResult convert_from_2_to_1_1_header(HTTPHdr *);
+Http2ErrorCode http2_encode_header_blocks(HTTPHdr *, uint8_t *, uint32_t, 
uint32_t *, HpackHandle &);
 
-int64_t http2_write_psuedo_headers(HTTPHdr *, uint8_t *, uint64_t, 
Http2IndexingTable &);
+MIMEParseResult http2_convert_header_from_2_to_1_1(HTTPHdr *);
+void http2_convert_header_from_1_1_to_2(HTTPHdr *);
 
-int64_t http2_write_header_fragment(HTTPHdr *, MIMEFieldIter &, uint8_t *, 
uint64_t, Http2IndexingTable &, bool &);
 
 // Not sure where else to put this, but figure this is as good of a start as
 // anything else.

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/Http2ConnectionState.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/Http2ConnectionState.cc 
b/proxy/http2/Http2ConnectionState.cc
index 5180b3f..713b91f 100644
--- a/proxy/http2/Http2ConnectionState.cc
+++ b/proxy/http2/Http2ConnectionState.cc
@@ -277,12 +277,14 @@ rcv_headers_frame(Http2ConnectionState &cstate, const 
Http2Frame &frame)
       skip_fetcher = true;
     }
 
-    const int64_t decoded_bytes = 
stream->decode_header_blocks(*cstate.local_indexing_table);
+    Http2ErrorCode result = 
stream->decode_header_blocks(*cstate.local_hpack_handle);
 
-    if (decoded_bytes == 0 || decoded_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
-      return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, 
HTTP2_ERROR_COMPRESSION_ERROR);
-    } else if (decoded_bytes == HPACK_ERROR_HTTP2_PROTOCOL_ERROR) {
-      return Http2Error(HTTP2_ERROR_CLASS_STREAM, HTTP2_ERROR_PROTOCOL_ERROR);
+    if (result != HTTP2_ERROR_NO_ERROR) {
+      if (result == HTTP2_ERROR_COMPRESSION_ERROR) {
+        return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, 
HTTP2_ERROR_COMPRESSION_ERROR);
+      } else {
+        return Http2Error(HTTP2_ERROR_CLASS_STREAM, 
HTTP2_ERROR_PROTOCOL_ERROR);
+      }
     }
 
     if (!skip_fetcher) {
@@ -678,12 +680,14 @@ rcv_continuation_frame(Http2ConnectionState &cstate, 
const Http2Frame &frame)
       return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, 
HTTP2_ERROR_PROTOCOL_ERROR);
     }
 
-    const int64_t decoded_bytes = 
stream->decode_header_blocks(*cstate.local_indexing_table);
+    Http2ErrorCode result = 
stream->decode_header_blocks(*cstate.local_hpack_handle);
 
-    if (decoded_bytes == 0 || decoded_bytes == HPACK_ERROR_COMPRESSION_ERROR) {
-      return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, 
HTTP2_ERROR_COMPRESSION_ERROR);
-    } else if (decoded_bytes == HPACK_ERROR_HTTP2_PROTOCOL_ERROR) {
-      return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, 
HTTP2_ERROR_PROTOCOL_ERROR);
+    if (result != HTTP2_ERROR_NO_ERROR) {
+      if (result == HTTP2_ERROR_COMPRESSION_ERROR) {
+        return Http2Error(HTTP2_ERROR_CLASS_CONNECTION, 
HTTP2_ERROR_COMPRESSION_ERROR);
+      } else {
+        return Http2Error(HTTP2_ERROR_CLASS_STREAM, 
HTTP2_ERROR_PROTOCOL_ERROR);
+      }
     }
 
     stream->init_fetcher(cstate);
@@ -991,9 +995,11 @@ Http2ConnectionState::send_data_frame(FetchSM *fetch_sm)
 void
 Http2ConnectionState::send_headers_frame(FetchSM *fetch_sm)
 {
-  const size_t buf_len = 
BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_HEADERS]) - 
HTTP2_FRAME_HEADER_LEN;
-  uint8_t payload_buffer[buf_len];
-  size_t payload_length = 0;
+  uint8_t *buf = NULL;
+  uint32_t buf_len = 0;
+  uint32_t header_blocks_size = 0;
+  int payload_length = 0;
+  uint64_t sent = 0;
   uint8_t flags = 0x00;
 
   Http2Stream *stream = static_cast<Http2Stream 
*>(fetch_sm->ext_get_user_data());
@@ -1001,43 +1007,57 @@ Http2ConnectionState::send_headers_frame(FetchSM 
*fetch_sm)
 
   DebugHttp2Stream(ua_session, stream->get_id(), "Send HEADERS frame");
 
-  // Write pseudo headers
-  payload_length += http2_write_psuedo_headers(resp_header, payload_buffer, 
buf_len, *(this->remote_indexing_table));
-
-  // If response body is empty, set END_STREAM flag to HEADERS frame
-  // Must check to ensure content-length is there.  Otherwise the value 
defaults
-  // to 0
-  if (resp_header->presence(MIME_PRESENCE_CONTENT_LENGTH) && 
resp_header->get_content_length() == 0) {
-    flags |= HTTP2_FLAGS_HEADERS_END_STREAM;
+  http2_convert_header_from_1_1_to_2(resp_header);
+  buf_len = resp_header->length_get() * 2; // Make it double just in case
+  buf = (uint8_t *)ats_malloc(buf_len);
+  if (buf == NULL) {
+    return;
+  }
+  Http2ErrorCode result = http2_encode_header_blocks(resp_header, buf, 
buf_len, &header_blocks_size, *(this->remote_hpack_handle));
+  if (result != HTTP2_ERROR_NO_ERROR) {
+    ats_free(buf);
+    return;
   }
 
-  MIMEFieldIter field_iter;
-  bool cont = false;
-  do {
-    // Handle first sending frame is as HEADERS
-    Http2FrameType type = cont ? HTTP2_FRAME_TYPE_CONTINUATION : 
HTTP2_FRAME_TYPE_HEADERS;
-
-    // Encode by HPACK naive
-    payload_length += http2_write_header_fragment(resp_header, field_iter, 
payload_buffer + payload_length,
-                                                  buf_len - payload_length, 
*(this->remote_indexing_table), cont);
-
-    // If buffer size is enough to send rest of headers, set END_HEADERS flag
-    if (buf_len >= payload_length && !cont) {
-      flags |= HTTP2_FLAGS_HEADERS_END_HEADERS;
+  // Send a HEADERS frame
+  if (header_blocks_size <= 
BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_HEADERS]) - 
HTTP2_FRAME_HEADER_LEN) {
+    payload_length = header_blocks_size;
+    flags |= HTTP2_FLAGS_HEADERS_END_HEADERS;
+    if (resp_header->presence(MIME_PRESENCE_CONTENT_LENGTH) && 
resp_header->get_content_length() == 0) {
+      flags |= HTTP2_FLAGS_HEADERS_END_STREAM;
     }
-
-    // Create HEADERS or CONTINUATION frame
-    Http2Frame headers(type, stream->get_id(), flags);
-    headers.alloc(buffer_size_index[type]);
-    http2_write_headers(payload_buffer, payload_length, headers.write());
+  } else {
+    payload_length = 
BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_HEADERS]) - 
HTTP2_FRAME_HEADER_LEN;
+  }
+  Http2Frame headers(HTTP2_FRAME_TYPE_HEADERS, stream->get_id(), flags);
+  headers.alloc(buffer_size_index[HTTP2_FRAME_TYPE_HEADERS]);
+  http2_write_headers(buf, payload_length, headers.write());
+  headers.finalize(payload_length);
+  // xmit event
+  SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread());
+  this->ua_session->handleEvent(HTTP2_SESSION_EVENT_XMIT, &headers);
+  sent += payload_length;
+
+  // Send CONTINUATION frames
+  flags = 0;
+  while (sent < header_blocks_size) {
+    DebugHttp2Stream(ua_session, stream->get_id(), "Send CONTINUATION frame");
+    payload_length = 
MIN(BUFFER_SIZE_FOR_INDEX(buffer_size_index[HTTP2_FRAME_TYPE_CONTINUATION]) - 
HTTP2_FRAME_HEADER_LEN,
+                         header_blocks_size - sent);
+    if (sent + payload_length == header_blocks_size) {
+      flags |= HTTP2_FLAGS_CONTINUATION_END_HEADERS;
+    }
+    Http2Frame headers(HTTP2_FRAME_TYPE_CONTINUATION, stream->get_id(), flags);
+    headers.alloc(buffer_size_index[HTTP2_FRAME_TYPE_CONTINUATION]);
+    http2_write_headers(buf + sent, payload_length, headers.write());
     headers.finalize(payload_length);
-
     // xmit event
     SCOPED_MUTEX_LOCK(lock, this->ua_session->mutex, this_ethread());
     this->ua_session->handleEvent(HTTP2_SESSION_EVENT_XMIT, &headers);
+    sent += payload_length;
+  }
 
-    payload_length = 0; // we will reuse the same buffer for more headers
-  } while (cont);
+  ats_free(buf);
 }
 
 void

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/Http2ConnectionState.h
----------------------------------------------------------------------
diff --git a/proxy/http2/Http2ConnectionState.h 
b/proxy/http2/Http2ConnectionState.h
index afd0cf2..a80fc9d 100644
--- a/proxy/http2/Http2ConnectionState.h
+++ b/proxy/http2/Http2ConnectionState.h
@@ -112,8 +112,8 @@ public:
   }
 
   Http2ClientSession *ua_session;
-  Http2IndexingTable *local_indexing_table;
-  Http2IndexingTable *remote_indexing_table;
+  HpackHandle *local_hpack_handle;
+  HpackHandle *remote_hpack_handle;
 
   // Settings.
   Http2ConnectionSettings server_settings;
@@ -122,8 +122,8 @@ public:
   void
   init()
   {
-    local_indexing_table = new Http2IndexingTable();
-    remote_indexing_table = new Http2IndexingTable();
+    local_hpack_handle = new HpackHandle(HTTP2_HEADER_TABLE_SIZE);
+    remote_hpack_handle = new HpackHandle(HTTP2_HEADER_TABLE_SIZE);
 
     continued_buffer.iov_base = NULL;
     continued_buffer.iov_len = 0;
@@ -135,8 +135,8 @@ public:
     cleanup_streams();
 
     mutex = NULL; // magic happens - assigning to NULL frees the ProxyMutex
-    delete local_indexing_table;
-    delete remote_indexing_table;
+    delete local_hpack_handle;
+    delete remote_hpack_handle;
 
     ats_free(continued_buffer.iov_base);
   }

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/Http2Stream.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/Http2Stream.cc b/proxy/http2/Http2Stream.cc
index 30c175f..b998be7 100644
--- a/proxy/http2/Http2Stream.cc
+++ b/proxy/http2/Http2Stream.cc
@@ -34,7 +34,7 @@ Http2Stream::init_fetcher(Http2ConnectionState &cstate)
   extern ClassAllocator<FetchSM> FetchSMAllocator;
 
   // Convert header to HTTP/1.1 format
-  if (convert_from_2_to_1_1_header(&_req_header) == PARSE_ERROR) {
+  if (http2_convert_header_from_2_to_1_1(&_req_header) == PARSE_ERROR) {
     return false;
   }
 

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/Http2Stream.h
----------------------------------------------------------------------
diff --git a/proxy/http2/Http2Stream.h b/proxy/http2/Http2Stream.h
index b89fb02..311733c 100644
--- a/proxy/http2/Http2Stream.h
+++ b/proxy/http2/Http2Stream.h
@@ -98,11 +98,11 @@ public:
     return trailing_header;
   }
 
-  int64_t
-  decode_header_blocks(Http2IndexingTable &indexing_table)
+  Http2ErrorCode
+  decode_header_blocks(HpackHandle &hpack_handle)
   {
-    return http2_decode_header_blocks(&_req_header, (const uint8_t 
*)header_blocks,
-                                      (const uint8_t *)header_blocks + 
header_blocks_length, indexing_table, trailing_header);
+    return http2_decode_header_blocks(&_req_header, (const uint8_t 
*)header_blocks, header_blocks_length, NULL, hpack_handle,
+                                      trailing_header);
   }
 
   // Check entire DATA payload length if content-length: header is exist

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/a39dd9d7/proxy/http2/RegressionHPACK.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/RegressionHPACK.cc b/proxy/http2/RegressionHPACK.cc
index 5e52f15..779d576 100644
--- a/proxy/http2/RegressionHPACK.cc
+++ b/proxy/http2/RegressionHPACK.cc
@@ -21,7 +21,6 @@
  *  limitations under the License.
  */
 
-#include "HTTP2.h"
 #include "HPACK.h"
 #include "HuffmanCodec.h"
 #include "ts/TestBox.h"
@@ -362,7 +361,7 @@ 
REGRESSION_TEST(HPACK_EncodeLiteralHeaderField)(RegressionTest *t, int, int *pst
 
   uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
   int len;
-  Http2IndexingTable indexing_table;
+  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);
@@ -395,8 +394,8 @@ REGRESSION_TEST(HPACK_Encode)(RegressionTest *t, int, int 
*pstatus)
   box = REGRESSION_TEST_PASSED;
 
   uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
-  Http2IndexingTable indexing_table;
-  
indexing_table.set_dynamic_table_size(DYNAMIC_TABLE_SIZE_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);
@@ -408,30 +407,21 @@ REGRESSION_TEST(HPACK_Encode)(RegressionTest *t, int, int 
*pstatus)
       if (strlen(expected_name) == 0)
         break;
 
-      if (strlen(expected_name) == HPACK_LEN_STATUS && 
strncasecmp(expected_name, HPACK_VALUE_STATUS, HPACK_LEN_STATUS) == 0) {
-        headers->status_set(http_parse_status(expected_value, expected_value + 
strlen(expected_value)));
-      } else {
-        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, NULL);
-      }
+      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, NULL);
     }
 
     memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
     uint64_t buf_len = BUFSIZE_FOR_REGRESSION_TEST;
-    int64_t len = http2_write_psuedo_headers(headers, buf, buf_len, 
indexing_table);
-    buf_len -= len;
+    int64_t len = hpack_encode_header_block(indexing_table, buf, buf_len, 
headers);
 
     if (len < 0) {
-      box.check(false, "http2_write_psuedo_headers returned negative value: %" 
PRId64, len);
+      box.check(false, "hpack_encode_header_blocks returned negative value: %" 
PRId64, len);
       break;
     }
 
-    MIMEFieldIter field_iter;
-    bool cont = false;
-    len += http2_write_header_fragment(headers, field_iter, buf + len, 
buf_len, indexing_table, cont);
-
     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");
@@ -442,16 +432,19 @@ REGRESSION_TEST(HPACK_Encode)(RegressionTest *t, int, int 
*pstatus)
          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 (strlen(expected_name) == 0)
+      if (expected_name_len == 0)
         break;
 
-      box.check(indexing_table.is_header_in_dynamic_table(expected_name, 
expected_value), "dynamic table has unexpected entries");
+      HpackLookupResult lookupResult = indexing_table.lookup(expected_name, 
expected_name_len, expected_value, expected_value_len);
+      box.check(lookupResult.match_type == HPACK_EXACT_MATCH && 
lookupResult.index_type == HPACK_INDEX_TYPE_DYNAMIC,
+                "the header field is not indexed");
 
       expected_dynamic_table_size += 
dynamic_table_response_test_case[i][j].size;
     }
-    box.check(indexing_table.get_dynamic_table_size() == 
expected_dynamic_table_size, "dynamic table is unexpected size: %d",
-              indexing_table.get_dynamic_table_size());
+    box.check(indexing_table.size() == expected_dynamic_table_size, "dynamic 
table is unexpected size: %d", indexing_table.size());
   }
 }
 
@@ -502,7 +495,7 @@ 
REGRESSION_TEST(HPACK_DecodeIndexedHeaderField)(RegressionTest *t, int, int *pst
   TestBox box(t, pstatus);
   box = REGRESSION_TEST_PASSED;
 
-  Http2IndexingTable indexing_table;
+  HpackIndexingTable indexing_table(4096);
 
   for (unsigned int i = 0; i < sizeof(indexed_test_case) / 
sizeof(indexed_test_case[0]); i++) {
     ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
@@ -532,7 +525,7 @@ 
REGRESSION_TEST(HPACK_DecodeLiteralHeaderField)(RegressionTest *t, int, int *pst
   TestBox box(t, pstatus);
   box = REGRESSION_TEST_PASSED;
 
-  Http2IndexingTable indexing_table;
+  HpackIndexingTable indexing_table(4096);
 
   for (unsigned int i = 0; i < sizeof(literal_test_case) / 
sizeof(literal_test_case[0]); i++) {
     ats_scoped_obj<HTTPHdr> headers(new HTTPHdr);
@@ -563,17 +556,14 @@ REGRESSION_TEST(HPACK_Decode)(RegressionTest *t, int, int 
*pstatus)
   TestBox box(t, pstatus);
   box = REGRESSION_TEST_PASSED;
 
-  Http2IndexingTable indexing_table;
-  bool trailing_header = false;
+  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);
 
-    http2_decode_header_blocks(headers, 
encoded_field_request_test_case[i].encoded_field,
-                               
encoded_field_request_test_case[i].encoded_field +
-                                 
encoded_field_request_test_case[i].encoded_field_len,
-                               indexing_table, trailing_header);
+    hpack_decode_header_block(indexing_table, headers, 
encoded_field_request_test_case[i].encoded_field,
+                              
encoded_field_request_test_case[i].encoded_field_len);
 
     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;

Reply via email to