You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by jp...@apache.org on 2014/10/31 23:40:35 UTC
[2/3] git commit: TS-2729: move HPACK and Huffman code to libhttp2
TS-2729: move HPACK and Huffman code to libhttp2
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo
Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/fa6c830f
Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/fa6c830f
Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/fa6c830f
Branch: refs/heads/master
Commit: fa6c830f4b5742404b1c6d31ba9345f98f587e3d
Parents: 53e56ff
Author: James Peach <jp...@apache.org>
Authored: Fri Oct 24 14:04:46 2014 -0700
Committer: James Peach <jp...@apache.org>
Committed: Fri Oct 31 15:25:47 2014 -0700
----------------------------------------------------------------------
proxy/hdrs/HPACK.cc | 945 ---------------------------------------
proxy/hdrs/HPACK.h | 120 -----
proxy/hdrs/HPACKHuffman.cc | 388 ----------------
proxy/hdrs/HPACKHuffman.h | 34 --
proxy/hdrs/HTTP.cc | 149 ------
proxy/hdrs/HTTP.h | 26 --
proxy/hdrs/Makefile.am | 4 +-
proxy/http2/HPACK.cc | 599 +++++++++++++++++++++++++
proxy/http2/HPACK.h | 142 ++++++
proxy/http2/HTTP2.cc | 505 +++++++++++++++++++++
proxy/http2/HTTP2.h | 13 +
proxy/http2/HuffmanCodec.cc | 389 ++++++++++++++++
proxy/http2/HuffmanCodec.h | 34 ++
proxy/http2/Makefile.am | 10 +-
14 files changed, 1692 insertions(+), 1666 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/hdrs/HPACK.cc
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HPACK.cc b/proxy/hdrs/HPACK.cc
deleted file mode 100644
index 9d8d337..0000000
--- a/proxy/hdrs/HPACK.cc
+++ /dev/null
@@ -1,945 +0,0 @@
-/** @file
-
- A brief file description
-
- @section license License
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "HPACK.h"
-#include "HPACKHuffman.h"
-
-// 5.1. Maximum Table Size
-// The size of an entry is the sum of its name's length in octets (as
-// defined in Section 6.2), its value's length in octets (see
-// Section 6.2), plus 32.
-const static unsigned ADDITIONAL_OCTETS = 32;
-
-const static uint32_t HEADER_FIELD_LIMIT_LENGTH = 4096;
-
-// Constants for regression test
-const static int BUFSIZE_FOR_REGRESSION_TEST = 128;
-const static int MAX_TEST_FIELD_NUM = 8;
-
-typedef enum {
- TS_HPACK_STATIC_TABLE_0 = 0,
- TS_HPACK_STATIC_TABLE_AUTHORITY,
- TS_HPACK_STATIC_TABLE_METHOD_GET,
- TS_HPACK_STATIC_TABLE_METHOD_POST,
- TS_HPACK_STATIC_TABLE_PATH_ROOT,
- TS_HPACK_STATIC_TABLE_PATH_INDEX,
- TS_HPACK_STATIC_TABLE_SCHEME_HTTP,
- TS_HPACK_STATIC_TABLE_SCHEME_HTTPS,
- TS_HPACK_STATIC_TABLE_STATUS_200,
- TS_HPACK_STATIC_TABLE_STATUS_204,
- TS_HPACK_STATIC_TABLE_STATUS_206,
- TS_HPACK_STATIC_TABLE_STATUS_304,
- TS_HPACK_STATIC_TABLE_STATUS_400,
- TS_HPACK_STATIC_TABLE_STATUS_404,
- TS_HPACK_STATIC_TABLE_STATUS_500,
- TS_HPACK_STATIC_TABLE_ACCEPT_CHARSET,
- TS_HPACK_STATIC_TABLE_ACCEPT_ENCODING,
- TS_HPACK_STATIC_TABLE_ACCEPT_LANGUAGE,
- TS_HPACK_STATIC_TABLE_ACCEPT_RANGES,
- TS_HPACK_STATIC_TABLE_ACCEPT,
- TS_HPACK_STATIC_TABLE_ACCESS_CONTROL_ALLOW_ORIGIN,
- TS_HPACK_STATIC_TABLE_AGE,
- TS_HPACK_STATIC_TABLE_ALLOW,
- TS_HPACK_STATIC_TABLE_AUTHORIZATION,
- TS_HPACK_STATIC_TABLE_CACHE_CONTROL,
- TS_HPACK_STATIC_TABLE_CONTENT_DISPOSITION,
- TS_HPACK_STATIC_TABLE_CONTENT_ENCODING,
- TS_HPACK_STATIC_TABLE_CONTENT_LANGUAGE,
- TS_HPACK_STATIC_TABLE_CONTENT_LENGTH,
- TS_HPACK_STATIC_TABLE_CONTENT_LOCATION,
- TS_HPACK_STATIC_TABLE_CONTENT_RANGE,
- TS_HPACK_STATIC_TABLE_CONTENT_TYPE,
- TS_HPACK_STATIC_TABLE_COOKIE,
- TS_HPACK_STATIC_TABLE_DATE,
- TS_HPACK_STATIC_TABLE_ETAG,
- TS_HPACK_STATIC_TABLE_EXPECT,
- TS_HPACK_STATIC_TABLE_EXPIRES,
- TS_HPACK_STATIC_TABLE_FROM,
- TS_HPACK_STATIC_TABLE_HOST,
- TS_HPACK_STATIC_TABLE_IF_MATCH,
- TS_HPACK_STATIC_TABLE_IF_MODIFIED_SINCE,
- TS_HPACK_STATIC_TABLE_IF_NONE_MATCH,
- TS_HPACK_STATIC_TABLE_IF_RANGE,
- TS_HPACK_STATIC_TABLE_IF_UNMODIFIED_SINCE,
- TS_HPACK_STATIC_TABLE_LAST_MODIFIED,
- TS_HPACK_STATIC_TABLE_LINK,
- TS_HPACK_STATIC_TABLE_LOCATION,
- TS_HPACK_STATIC_TABLE_MAX_FORWARDS,
- TS_HPACK_STATIC_TABLE_PROXY_AUTHENTICATE,
- TS_HPACK_STATIC_TABLE_PROXY_AUTHORIZATION,
- TS_HPACK_STATIC_TABLE_RANGE,
- TS_HPACK_STATIC_TABLE_REFERER,
- TS_HPACK_STATIC_TABLE_REFRESH,
- TS_HPACK_STATIC_TABLE_RETRY_AFTER,
- TS_HPACK_STATIC_TABLE_SERVER,
- TS_HPACK_STATIC_TABLE_SET_COOKIE,
- TS_HPACK_STATIC_TABLE_STRICT_TRANSPORT_SECURITY,
- TS_HPACK_STATIC_TABLE_TRANSFER_ENCODING,
- TS_HPACK_STATIC_TABLE_USER_AGENT,
- TS_HPACK_STATIC_TABLE_VARY,
- TS_HPACK_STATIC_TABLE_VIA,
- TS_HPACK_STATIC_TABLE_WWW_AUTHENTICATE,
- TS_HPACK_STATIC_TABLE_ENTRY_NUM
-} TS_HPACK_STATIC_TABLE_ENTRY;
-
-const static struct {
- const char* name;
- const char* value;
-} STATIC_TABLE[] = {
- {"", ""},
- {":authority", ""},
- {":method", "GET"},
- {":method", "POST"},
- {":path", "/"},
- {":path", "/index.html"},
- {":scheme", "http"},
- {":scheme", "https"},
- {":status", "200"},
- {":status", "204"},
- {":status", "206"},
- {":status", "304"},
- {":status", "400"},
- {":status", "404"},
- {":status", "500"},
- {"accept-charset", ""},
- {"accept-encoding", "gzip, deflate"},
- {"accept-language", ""},
- {"accept-ranges", ""},
- {"accept", ""},
- {"access-control-allow-origin", ""},
- {"age", ""},
- {"allow", ""},
- {"authorization", ""},
- {"cache-control", ""},
- {"content-disposition", ""},
- {"content-encoding", ""},
- {"content-language", ""},
- {"content-length", ""},
- {"content-location", ""},
- {"content-range", ""},
- {"content-type", ""},
- {"cookie", ""},
- {"date", ""},
- {"etag", ""},
- {"expect", ""},
- {"expires", ""},
- {"from", ""},
- {"host", ""},
- {"if-match", ""},
- {"if-modified-since", ""},
- {"if-none-match", ""},
- {"if-range", ""},
- {"if-unmodified-since", ""},
- {"last-modified", ""},
- {"link", ""},
- {"location", ""},
- {"max-forwards", ""},
- {"proxy-authenticate", ""},
- {"proxy-authorization", ""},
- {"range", ""},
- {"referer", ""},
- {"refresh", ""},
- {"retry-after", ""},
- {"server", ""},
- {"set-cookie", ""},
- {"strict-transport-security", ""},
- {"transfer-encoding", ""},
- {"user-agent", ""},
- {"vary", ""},
- {"via", ""},
- {"www-authenticate", ""}
-};
-
-int
-Http2HeaderTable::get_header_from_indexing_tables(uint32_t index, MIMEFieldWrapper& field) const
-{
- // Index Address Space starts at 1, so index == 0 is invalid.
- if (!index) return -1;
-
- if (index < TS_HPACK_STATIC_TABLE_ENTRY_NUM) {
- 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 + get_current_entry_num()) {
- const MIMEField* m_field = get_header(index - TS_HPACK_STATIC_TABLE_ENTRY_NUM + 1);
-
- int name_len, value_len;
- const char* name = m_field->name_get(&name_len);
- const char* value = m_field->value_get(&value_len);
-
- field.name_set(name, name_len);
- field.value_set(value, value_len);
- } else {
- // 3.3.3. Index Address Space
- // Indices strictly greater than the sum of the lengths of both tables
- // MUST be treated as a decoding error.
- return -1;
- }
-
- return 0;
-}
-
-// 5.2. Entry Eviction when Header Table Size Changes
-// Whenever the maximum size for the header table is reduced, entries
-// are evicted from the end of the header table until the size of the
-// header table is less than or equal to the maximum size.
-void
-Http2HeaderTable::set_header_table_size(uint32_t new_size)
-{
- uint32_t old_size = _settings_header_table_size;
- while (old_size > new_size) {
- int last_name_len, last_value_len;
- MIMEField* last_field = _headers.last();
-
- last_field->name_get(&last_name_len);
- last_field->value_get(&last_value_len);
- old_size -= ADDITIONAL_OCTETS + last_name_len + last_value_len;
-
- _headers.remove_index(_headers.length()-1);
- _mhdr->field_delete(last_field, false);
- }
-
- _settings_header_table_size = new_size;
-}
-
-void
-Http2HeaderTable::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_header_table_size) {
- // 5.3. 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 table causes the table to be emptied of all existing entries.
- _headers.clear();
- _mhdr->fields_clear();
- } else {
- _current_size += header_size;
- while (_current_size > _settings_header_table_size) {
- int last_name_len, last_value_len;
- MIMEField* last_field = _headers.last();
-
- last_field->name_get(&last_name_len);
- last_field->value_get(&last_value_len);
- _current_size -= ADDITIONAL_OCTETS + last_name_len + last_value_len;
-
- _headers.remove_index(_headers.length()-1);
- _mhdr->field_delete(last_field, false);
- }
-
- MIMEField* new_field = _mhdr->field_create(name, name_len);
- new_field->value_set(_mhdr->m_heap, _mhdr->m_mime, value, value_len);
- // XXX Because entire Vec instance is copied, Its too expensive!
- _headers.insert(0, new_field);
- }
-}
-
-/*
- * Pseudo code
- *
- * if I < 2^N - 1, encode I on N bits
- * else
- * encode (2^N - 1) on N bits
- * I = I - (2^N - 1)
- * while I >= 128
- * encode (I % 128 + 128) on 8 bits
- * I = I / 128
- * encode I on 8 bits
- */
-int64_t
-encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint32_t value, uint8_t n)
-{
- if (buf_start >= buf_end) return -1;
-
- uint8_t *p = buf_start;
-
- if (value < (static_cast<uint32_t>(1 << n) - 1)) {
- *(p++) |= value;
- } else {
- *(p++) |= (1 << n) - 1;
- value -= (1 << n) - 1;
- while (value >= 128) {
- if (p >= buf_end) {
- return -1;
- }
- *(p++) = (value & 0x7F) | 0x80;
- value = value >> 7;
- }
- if (p+1 >= buf_end) {
- return -1;
- }
- *(p++) = value;
- }
- return p - buf_start;
-}
-
-int64_t
-encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char* value, size_t value_len)
-{
- uint8_t *p = buf_start;
-
- // Length
- const int64_t len = encode_integer(p, buf_end, value_len, 7);
- if (len == -1) return -1;
- p += len;
- if (buf_end < p || static_cast<size_t>(buf_end - p) < value_len) return -1;
-
- // Value String
- memcpy(p, value, value_len);
- p += value_len;
- return p - buf_start;
-}
-
-int64_t
-encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index)
-{
- if (buf_start >= buf_end) return -1;
-
- uint8_t *p = buf_start;
-
- // Index
- const int64_t len = encode_integer(p, buf_end, index, 7);
- if (len == -1) return -1;
-
- // Representation type
- if (p+1 >= buf_end) {
- return -1;
- }
- *p |= '\x80';
- p += len;
-
- return p - buf_start;
-}
-
-int64_t
-encode_literal_header_field(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper& header, uint32_t index, HEADER_INDEXING_TYPE type)
-{
- uint8_t *p = buf_start;
- int64_t len;
- uint8_t prefix = 0, flag = 0;
-
- switch (type) {
- case INC_INDEXING:
- prefix = 6;
- flag = 0x40;
- break;
- case WITHOUT_INDEXING:
- prefix = 4;
- flag = 0x00;
- break;
- case NEVER_INDEXED:
- prefix = 4;
- flag = 0x10;
- break;
- default:
- return -1;
- }
-
- // Index
- len = encode_integer(p, buf_end, index, prefix);
- if (len == -1) return -1;
-
- // Representation type
- if (p+1 >= buf_end) {
- return -1;
- }
- *p |= flag;
- p += len;
-
- // Value String
- int value_len;
- const char* value = header.value_get(&value_len);
- len = encode_string(p, buf_end, value, value_len);
- if (len == -1) return -1;
- p += len;
-
- return p - buf_start;
-}
-
-int64_t
-encode_literal_header_field(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper& header, HEADER_INDEXING_TYPE type)
-{
- uint8_t *p = buf_start;
- int64_t len;
- uint8_t flag = 0;
-
- ink_assert(type >= INC_INDEXING && type <= NEVER_INDEXED);
- switch (type) {
- case INC_INDEXING:
- flag = 0x40;
- break;
- case WITHOUT_INDEXING:
- flag = 0x00;
- break;
- case NEVER_INDEXED:
- flag = 0x10;
- break;
- default:
- return -1;
- }
- if (p+1 >= buf_end) {
- return -1;
- }
- *(p++) = flag;
-
- // Name String
- int name_len;
- const char* name = header.name_get(&name_len);
- len = encode_string(p, buf_end, name, name_len);
- if (len == -1) return -1;
- p += len;
-
- // Value String
- int value_len;
- const char* value = header.value_get(&value_len);
- len = encode_string(p, buf_end, value, value_len);
- if (len == -1) {
- return -1;
- }
-
- p += len;
-
- return p - buf_start;
-}
-
-/*
- * 6.1. Integer representation
- *
- * Pseudo code
- *
- * decode I from the next N bits
- * if I < 2^N - 1, return I
- * else
- * M = 0
- * repeat
- * B = next octet
- * I = I + (B & 127) * 2^M
- * M = M + 7
- * while B & 128 == 128
- * return I
- *
- */
-inline int64_t
-decode_integer(uint32_t& dst, const uint8_t *buf_start, const uint8_t *buf_end, uint8_t n)
-{
- const uint8_t *p = buf_start;
-
- dst = (*p & ((1 << n) - 1));
- if (dst == static_cast<uint32_t>(1 << n) - 1) {
- int m = 0;
- do {
- if (++p >= buf_end) return -1;
-
- uint32_t added_value = *p & 0x7f;
- if ((UINT32_MAX >> m) < added_value) {
- // Excessively large integer encodings - in value or octet
- // length - MUST be treated as a decoding error.
- return -1;
- }
- dst += added_value << m;
- m += 7;
- } while (*p & 0x80);
- }
-
- return p - buf_start + 1;
-}
-
-// 6.2 return content from String Data (Length octets)
-// with huffman decoding if it is encoded
-int64_t
-decode_string(char **c_str, uint32_t& c_str_length, const uint8_t *buf_start, const uint8_t *buf_end)
-{
- const uint8_t *p = buf_start;
- bool isHuffman = *p & 0x80;
- uint32_t encoded_string_len = 0;
- int64_t len = 0;
-
- len = decode_integer(encoded_string_len, p, buf_end, 7);
- if (len == -1) return -1;
- p += len;
-
- if (encoded_string_len > HEADER_FIELD_LIMIT_LENGTH || buf_start + encoded_string_len >= buf_end) {
- return -1;
- }
-
- if (isHuffman) {
- // Allocate temporary area twice the size of before decoded data
- *c_str = static_cast<char*>(ats_malloc(encoded_string_len * 2));
-
- len = huffman_decode(*c_str, p, encoded_string_len);
- if (len == -1) return -1;
- c_str_length = len;
- } else {
- *c_str = static_cast<char*>(ats_malloc(encoded_string_len));
-
- memcpy(*c_str, reinterpret_cast<const char*>(p), encoded_string_len);
-
- c_str_length = encoded_string_len;
- }
-
- return p + encoded_string_len - buf_start;
-}
-
-// 7.1. Indexed Header Field Representation
-int64_t
-decode_indexed_header_field(MIMEFieldWrapper& header, const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table)
-{
- uint32_t index = 0;
- int64_t len = 0;
- len = decode_integer(index, buf_start, buf_end, 7);
- if (len == -1) return -1;
-
- if (header_table.get_header_from_indexing_tables(index, header) == -1) {
- return -1;
- }
-
- return len;
-}
-
-// 7.2. Literal Header Field Representation
-int64_t
-decode_literal_header_field(MIMEFieldWrapper& header, const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table)
-{
- const uint8_t *p = buf_start;
- bool isIncremental = false;
- uint32_t index = 0;
- int64_t len = 0;
-
- if (*p & 0x40) {
- // 7.2.1. index extraction based on Literal Header Field with Incremental Indexing
- len = decode_integer(index, p, buf_end, 6);
- if (len == -1) return -1;
- isIncremental = true;
- } else if (*p & 0x10) {
- // 7.2.3. index extraction Literal Header Field Never Indexed
- len = decode_integer(index, p, buf_end, 4);
- if (len == -1) return -1;
- } else {
- // 7.2.2. index extraction Literal Header Field without Indexing
- len = decode_integer(index, p, buf_end, 4);
- if (len == -1) return -1;
- }
- p += len;
-
- if (index) {
- header_table.get_header_from_indexing_tables(index, header);
- } else {
- char *c_name = NULL;
- uint32_t c_name_len = 0;
- len = decode_string(&c_name, c_name_len, p, buf_end);
- if (len == -1) return -1;
- p += len;
- header.name_set(c_name, c_name_len);
- ats_free(c_name);
- }
- char *c_value = NULL;
- uint32_t c_value_len = 0;
- len = decode_string(&c_value, c_value_len, p, buf_end);
- if (len == -1) return -1;
- p += len;
- header.value_set(c_value, c_value_len);
- ats_free(c_value);
-
- // Incremental Indexing adds header to header table as new entry
- if (isIncremental) {
- header_table.add_header_field(header.field_get());
- }
-
- return p - buf_start;
-}
-
-// 7.3. Header Table Size Update
-int64_t
-update_header_table_size(const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table)
-{
- if (buf_start == buf_end) return -1;
-
- int64_t len = 0;
-
- // Update header table size if its required.
- if ((*buf_start & 0xe0) == 0x20) {
- uint32_t size = 0;
- len = decode_integer(size, buf_start, buf_end, 5);
- if (len == -1) return -1;
-
- header_table.set_header_table_size(size);
- }
-
- return len;
-}
-
-#if TS_HAS_TESTS
-
-#include "TestBox.h"
-
-/***********************************************************************************
- * *
- * Test cases for regression test *
- * *
- * Some test cases are based on examples of specification. *
- * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09#appendix-D *
- * *
- ***********************************************************************************/
-
-// D.1. Integer Representation Examples
-const static struct {
- uint32_t raw_integer;
- uint8_t* encoded_field;
- int encoded_field_len;
- int prefix;
-} integer_test_case[] = {
- { 10, (uint8_t*)"\x0A", 1, 5 },
- { 1337, (uint8_t*)"\x1F\x9A\x0A", 3, 5 },
- { 42, (uint8_t*)"\x2A", 1, 8 }
-};
-
-// Example: custom-key: custom-header
-const static struct {
- char* raw_string;
- uint32_t raw_string_len;
- uint8_t* encoded_field;
- int encoded_field_len;
-} string_test_case[] = {
- { (char*)"custom-key", 10, (uint8_t*)"\xA" "custom-key", 11 },
- { (char*)"custom-key", 10, (uint8_t*)"\x88" "\x25\xa8\x49\xe9\x5b\xa9\x7d\x7f", 9 }
-};
-
-// D.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 }
-};
-
-// D.2. Header Field Representation Examples
-const static struct {
- char* raw_name;
- char* raw_value;
- int index;
- HEADER_INDEXING_TYPE type;
- uint8_t* encoded_field;
- int encoded_field_len;
-} literal_test_case[] = {
- { (char*)"custom-key", (char*)"custom-header", 0, INC_INDEXING, (uint8_t*)"\x40\x0a" "custom-key\x0d" "custom-header", 26 },
- { (char*)"custom-key", (char*)"custom-header", 0, WITHOUT_INDEXING, (uint8_t*)"\x00\x0a" "custom-key\x0d" "custom-header", 26 },
- { (char*)"custom-key", (char*)"custom-header", 0, NEVER_INDEXED, (uint8_t*)"\x10\x0a" "custom-key\x0d" "custom-header", 26 },
- { (char*)":path", (char*)"/sample/path", 4, INC_INDEXING, (uint8_t*)"\x44\x0c" "/sample/path", 14 },
- { (char*)":path", (char*)"/sample/path", 4, WITHOUT_INDEXING, (uint8_t*)"\x04\x0c" "/sample/path", 14 },
- { (char*)":path", (char*)"/sample/path", 4, NEVER_INDEXED, (uint8_t*)"\x14\x0c" "/sample/path", 14 },
- { (char*)"password", (char*)"secret", 0, INC_INDEXING, (uint8_t*)"\x40\x08" "password\x06" "secret", 17 },
- { (char*)"password", (char*)"secret", 0, WITHOUT_INDEXING, (uint8_t*)"\x00\x08" "password\x06" "secret", 17 },
- { (char*)"password", (char*)"secret", 0, NEVER_INDEXED, (uint8_t*)"\x10\x08" "password\x06" "secret", 17 }
-};
-
-// D.3. Request Examples without Huffman Coding - D.3.1. First Request
-const static struct {
- char* raw_name;
- char* raw_value;
-} raw_field_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
- }
-};
-const static struct {
- uint8_t* encoded_field;
- int encoded_field_len;
-} encoded_field_test_case[] = {
- {
- (uint8_t*)"\x40" "\x7:method" "\x3GET"
- "\x40" "\x7:scheme" "\x4http"
- "\x40" "\x5:path" "\x1/"
- "\x40" "\xa:authority" "\xfwww.example.com",
- 64
- }
-};
-
-/***********************************************************************************
- * *
- * Regression test codes *
- * *
- ***********************************************************************************/
-
-REGRESSION_TEST(HPACK_EncodeInteger)(RegressionTest * t, int, int *pstatus)
-{
- TestBox box(t, pstatus);
- box = REGRESSION_TEST_PASSED;
- uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
-
- for (unsigned int i=0; i<sizeof(integer_test_case)/sizeof(integer_test_case[0]); i++) {
- memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
-
- int len = encode_integer(buf, buf+BUFSIZE_FOR_REGRESSION_TEST, integer_test_case[i].raw_integer, integer_test_case[i].prefix);
-
- box.check(len == integer_test_case[i].encoded_field_len, "encoded length was %d, expecting %d",
- len, integer_test_case[i].encoded_field_len);
- box.check(memcmp(buf, integer_test_case[i].encoded_field, len) == 0, "encoded value was invalid");
- }
-}
-
-REGRESSION_TEST(HPACK_EncodeString)(RegressionTest * t, int, int *pstatus)
-{
- TestBox box(t, pstatus);
- box = REGRESSION_TEST_PASSED;
-
- uint8_t buf[BUFSIZE_FOR_REGRESSION_TEST];
- int len;
-
- // FIXME Current encoder don't support huffman conding.
- for (unsigned int i=0; i<1; i++) {
- memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
-
- len = encode_string(buf, buf+BUFSIZE_FOR_REGRESSION_TEST, string_test_case[i].raw_string, string_test_case[i].raw_string_len);
-
- box.check(len == string_test_case[i].encoded_field_len, "encoded length was %d, expecting %d",
- len, integer_test_case[i].encoded_field_len);
- box.check(memcmp(buf, string_test_case[i].encoded_field, len) == 0, "encoded string was invalid");
- }
-}
-
-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 (unsigned int i=0; i<sizeof(indexed_test_case)/sizeof(indexed_test_case[0]); i++) {
- memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
-
- int len = encode_indexed_header_field(buf, buf+BUFSIZE_FOR_REGRESSION_TEST, indexed_test_case[i].index);
-
- box.check(len == indexed_test_case[i].encoded_field_len, "encoded length was %d, expecting %d",
- len, indexed_test_case[i].encoded_field_len);
- box.check(memcmp(buf, indexed_test_case[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;
-
- for (unsigned int i=0; i<sizeof(literal_test_case)/sizeof(literal_test_case[0]); i++) {
- memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
-
- 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.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(buf, buf+BUFSIZE_FOR_REGRESSION_TEST, header, literal_test_case[i].index, 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(buf, buf+BUFSIZE_FOR_REGRESSION_TEST, header, 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(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];
- Http2HeaderTable header_table;
-
- // FIXME Current encoder don't support indexing.
- for (unsigned int i=0; i<sizeof(encoded_field_test_case)/sizeof(encoded_field_test_case[0]); i++) {
- HTTPHdr* headers = new HTTPHdr();
- headers->create(HTTP_TYPE_REQUEST);
-
- for (unsigned int j=0; j<sizeof(raw_field_test_case[i])/sizeof(raw_field_test_case[i][0]); j++) {
- const char* expected_name = raw_field_test_case[i][j].raw_name;
- const char* expected_value = raw_field_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);
- mime_field_name_value_set(headers->m_heap, headers->m_http->m_fields_impl, field, -1,
- expected_name, strlen(expected_name), expected_value, strlen(expected_value),
- true, strlen(expected_name) + strlen(expected_value), 1);
- mime_hdr_field_attach(headers->m_http->m_fields_impl, field, 1, NULL);
- }
-
- memset(buf, 0, BUFSIZE_FOR_REGRESSION_TEST);
- int len = convert_from_1_1_to_2_header(headers, buf, BUFSIZE_FOR_REGRESSION_TEST, header_table);
-
- box.check(len == encoded_field_test_case[i].encoded_field_len, "encoded length was %d, expecting %d",
- len, encoded_field_test_case[i].encoded_field_len);
- box.check(memcmp(buf, encoded_field_test_case[i].encoded_field, len) == 0, "encoded value was invalid");
- }
-}
-
-REGRESSION_TEST(HPACK_DecodeInteger)(RegressionTest * t, int, int *pstatus)
-{
- TestBox box(t, pstatus);
- box = REGRESSION_TEST_PASSED;
-
- uint32_t actual;
-
- for (unsigned int i=0; i<sizeof(integer_test_case)/sizeof(integer_test_case[0]); i++) {
- int len = decode_integer(actual, integer_test_case[i].encoded_field,
- integer_test_case[i].encoded_field + integer_test_case[i].encoded_field_len,
- integer_test_case[i].prefix);
-
- box.check(len == integer_test_case[i].encoded_field_len, "decoded length was %d, expecting %d",
- len, integer_test_case[i].encoded_field_len);
- box.check(actual == integer_test_case[i].raw_integer, "decoded value was %d, expected %d",
- actual, integer_test_case[i].raw_integer);
- }
-}
-
-REGRESSION_TEST(HPACK_DecodeString)(RegressionTest * t, int, int *pstatus)
-{
- TestBox box(t, pstatus);
- box = REGRESSION_TEST_PASSED;
-
- char* actual;
- uint32_t actual_len;
-
- hpack_huffman_init();
-
- for (unsigned int i=0; i<sizeof(string_test_case)/sizeof(string_test_case[0]); i++) {
- int len = decode_string(&actual, actual_len, string_test_case[i].encoded_field,
- string_test_case[i].encoded_field + string_test_case[i].encoded_field_len);
-
- box.check(len == string_test_case[i].encoded_field_len, "decoded length was %d, expecting %d",
- len, string_test_case[i].encoded_field_len);
- box.check(actual_len == string_test_case[i].raw_string_len, "length of decoded string was %d, expecting %d",
- actual_len, string_test_case[i].raw_string_len);
- box.check(memcmp(actual, string_test_case[i].raw_string, actual_len) == 0, "decoded string was invalid");
-
- ats_free(actual);
- }
-}
-
-REGRESSION_TEST(HPACK_DecodeIndexedHeaderField)(RegressionTest * t, int, int *pstatus)
-{
- TestBox box(t, pstatus);
- box = REGRESSION_TEST_PASSED;
-
- Http2HeaderTable header_table;
-
- for (unsigned int i=0; i<sizeof(indexed_test_case)/sizeof(indexed_test_case[0]); i++) {
- 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, indexed_test_case[i].encoded_field,
- indexed_test_case[i].encoded_field+indexed_test_case[i].encoded_field_len, header_table);
-
- box.check(len == indexed_test_case[i].encoded_field_len, "decoded length was %d, expecting %d",
- len, indexed_test_case[i].encoded_field_len);
-
- int name_len;
- const char* name = header.name_get(&name_len);
- box.check(memcmp(name, indexed_test_case[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, indexed_test_case[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;
-
- Http2HeaderTable header_table;
-
- for (unsigned int i=0; i<sizeof(literal_test_case)/sizeof(literal_test_case[0]); i++) {
- 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, literal_test_case[i].encoded_field,
- literal_test_case[i].encoded_field+literal_test_case[i].encoded_field_len, header_table);
-
- box.check(len == literal_test_case[i].encoded_field_len, "decoded length was %d, expecting %d",
- len, literal_test_case[i].encoded_field_len);
-
- int name_len;
- const char* name = header.name_get(&name_len);
- box.check(memcmp(name, literal_test_case[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, literal_test_case[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;
-
- Http2HeaderTable header_table;
-
- for (unsigned int i=0; i<sizeof(encoded_field_test_case)/sizeof(encoded_field_test_case[0]); i++) {
- HTTPHdr* headers = new HTTPHdr();
- headers->create(HTTP_TYPE_REQUEST);
-
- headers->hpack_parse_req(encoded_field_test_case[i].encoded_field,
- encoded_field_test_case[i].encoded_field + encoded_field_test_case[i].encoded_field_len,
- true, header_table);
-
- for (unsigned int j=0; j<sizeof(raw_field_test_case[i])/sizeof(raw_field_test_case[i][0]); j++) {
- const char* expected_name = raw_field_test_case[i][j].raw_name;
- const char* expected_value = raw_field_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 != NULL, "A MIMEField that has \"%s\" as name doesn't exist", expected_name);
-
- 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);
- }
- }
-}
-
-#endif /* TS_HAS_TESTS */
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/hdrs/HPACK.h
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HPACK.h b/proxy/hdrs/HPACK.h
deleted file mode 100644
index 341023a..0000000
--- a/proxy/hdrs/HPACK.h
+++ /dev/null
@@ -1,120 +0,0 @@
-/** @file
-
- A brief file description
-
- @section license License
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef __HPACK_H__
-#define __HPACK_H__
-
-#include "libts.h"
-#include "HTTP.h"
-
-enum HEADER_INDEXING_TYPE {
- INC_INDEXING,
- WITHOUT_INDEXING,
- NEVER_INDEXED,
-};
-
-class MIMEFieldWrapper
-{
-public:
-
- MIMEFieldWrapper(MIMEField * f, HdrHeap * hh, MIMEHdrImpl * impl)
- : _field(f), _heap(hh), _mh(impl) {
- }
-
- void name_set(const char * name, int name_len) {
- _field->name_set(_heap, _mh, name, name_len);
- }
-
- void value_set(const char * value, int value_len) {
- _field->value_set(_heap, _mh, value, value_len);
- }
-
- const char * name_get(int * length) const {
- return _field->name_get(length);
- }
-
- const char * value_get(int * length) const {
- return _field->value_get(length);
- }
-
- const MIMEField * field_get() const {
- return _field;
- }
-
-private:
- MIMEField * _field;
- HdrHeap * _heap;
- MIMEHdrImpl * _mh;
-};
-
-// 3.2 Header Table
-class Http2HeaderTable
-{
-public:
-
- Http2HeaderTable() : _current_size(0), _settings_header_table_size(4096) {
- _mhdr = new MIMEHdr();
- _mhdr->create();
- }
-
- ~Http2HeaderTable() {
- _headers.clear();
- _mhdr->fields_clear();
- }
-
- void add_header_field(const MIMEField * field);
- int get_header_from_indexing_tables(uint32_t index, MIMEFieldWrapper& header_field) const;
- void set_header_table_size(uint32_t new_size);
-
-private:
-
- const MIMEField * get_header(uint32_t index) const {
- return _headers.get(index-1);
- }
-
- const uint32_t get_current_entry_num() const {
- return _headers.length();
- }
-
- uint32_t _current_size;
- uint32_t _settings_header_table_size;
-
- MIMEHdr * _mhdr;
- Vec<MIMEField *> _headers;
-};
-
-int64_t
-encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index);
-int64_t
-encode_literal_header_field(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper& header, uint32_t index, HEADER_INDEXING_TYPE type);
-int64_t
-encode_literal_header_field(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper& header, HEADER_INDEXING_TYPE type);
-
-int64_t
-decode_indexed_header_field(MIMEFieldWrapper& header, const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table);
-int64_t
-decode_literal_header_field(MIMEFieldWrapper& header, const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table);
-int64_t
-update_header_table_size(const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table);
-
-#endif /* __HPACK_H__ */
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/hdrs/HPACKHuffman.cc
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HPACKHuffman.cc b/proxy/hdrs/HPACKHuffman.cc
deleted file mode 100644
index 02706ed..0000000
--- a/proxy/hdrs/HPACKHuffman.cc
+++ /dev/null
@@ -1,388 +0,0 @@
-/** @file
-
- A brief file description
-
- @section license License
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#include "HPACKHuffman.h"
-#include "libts.h"
-
-const size_t HUFFMAN_TABLE_ENTRY_NUM = 257;
-
-const static struct {
- uint32_t code_as_hex;
- uint32_t bit_len;
-} huffman_table[] = {
- {0x1ff8, 13},
- {0x7fffd8, 23},
- {0xfffffe2, 28},
- {0xfffffe3, 28},
- {0xfffffe4, 28},
- {0xfffffe5, 28},
- {0xfffffe6, 28},
- {0xfffffe7, 28},
- {0xfffffe8, 28},
- {0xffffea, 24},
- {0x3ffffffc, 30},
- {0xfffffe9, 28},
- {0xfffffea, 28},
- {0x3ffffffd, 30},
- {0xfffffeb, 28},
- {0xfffffec, 28},
- {0xfffffed, 28},
- {0xfffffee, 28},
- {0xfffffef, 28},
- {0xffffff0, 28},
- {0xffffff1, 28},
- {0xffffff2, 28},
- {0x3ffffffe, 30},
- {0xffffff3, 28},
- {0xffffff4, 28},
- {0xffffff5, 28},
- {0xffffff6, 28},
- {0xffffff7, 28},
- {0xffffff8, 28},
- {0xffffff9, 28},
- {0xffffffa, 28},
- {0xffffffb, 28},
- {0x14, 6},
- {0x3f8, 10},
- {0x3f9, 10},
- {0xffa, 12},
- {0x1ff9, 13},
- {0x15, 6},
- {0xf8, 8},
- {0x7fa, 11},
- {0x3fa, 10},
- {0x3fb, 10},
- {0xf9, 8},
- {0x7fb, 11},
- {0xfa, 8},
- {0x16, 6},
- {0x17, 6},
- {0x18, 6},
- {0x0, 5},
- {0x1, 5},
- {0x2, 5},
- {0x19, 6},
- {0x1a, 6},
- {0x1b, 6},
- {0x1c, 6},
- {0x1d, 6},
- {0x1e, 6},
- {0x1f, 6},
- {0x5c, 7},
- {0xfb, 8},
- {0x7ffc, 15},
- {0x20, 6},
- {0xffb, 12},
- {0x3fc, 10},
- {0x1ffa, 13},
- {0x21, 6},
- {0x5d, 7},
- {0x5e, 7},
- {0x5f, 7},
- {0x60, 7},
- {0x61, 7},
- {0x62, 7},
- {0x63, 7},
- {0x64, 7},
- {0x65, 7},
- {0x66, 7},
- {0x67, 7},
- {0x68, 7},
- {0x69, 7},
- {0x6a, 7},
- {0x6b, 7},
- {0x6c, 7},
- {0x6d, 7},
- {0x6e, 7},
- {0x6f, 7},
- {0x70, 7},
- {0x71, 7},
- {0x72, 7},
- {0xfc, 8},
- {0x73, 7},
- {0xfd, 8},
- {0x1ffb, 13},
- {0x7fff0, 19},
- {0x1ffc, 13},
- {0x3ffc, 14},
- {0x22, 6},
- {0x7ffd, 15},
- {0x3, 5},
- {0x23, 6},
- {0x4, 5},
- {0x24, 6},
- {0x5, 5},
- {0x25, 6},
- {0x26, 6},
- {0x27, 6},
- {0x6, 5},
- {0x74, 7},
- {0x75, 7},
- {0x28, 6},
- {0x29, 6},
- {0x2a, 6},
- {0x7, 5},
- {0x2b, 6},
- {0x76, 7},
- {0x2c, 6},
- {0x8, 5},
- {0x9, 5},
- {0x2d, 6},
- {0x77, 7},
- {0x78, 7},
- {0x79, 7},
- {0x7a, 7},
- {0x7b, 7},
- {0x7ffe, 15},
- {0x7fc, 11},
- {0x3ffd, 14},
- {0x1ffd, 13},
- {0xffffffc, 28},
- {0xfffe6, 20},
- {0x3fffd2, 22},
- {0xfffe7, 20},
- {0xfffe8, 20},
- {0x3fffd3, 22},
- {0x3fffd4, 22},
- {0x3fffd5, 22},
- {0x7fffd9, 23},
- {0x3fffd6, 22},
- {0x7fffda, 23},
- {0x7fffdb, 23},
- {0x7fffdc, 23},
- {0x7fffdd, 23},
- {0x7fffde, 23},
- {0xffffeb, 23},
- {0x7fffdf, 23},
- {0xffffec, 24},
- {0xffffed, 24},
- {0x3fffd7, 22},
- {0x7fffe0, 23},
- {0xffffee, 24},
- {0x7fffe1, 23},
- {0x7fffe2, 23},
- {0x7fffe3, 23},
- {0x7fffe4, 23},
- {0x1fffdc, 21},
- {0x3fffd8, 22},
- {0x7fffe5, 23},
- {0x3fffd9, 22},
- {0x7fffe6, 23},
- {0x7fffe7, 23},
- {0xffffef, 24},
- {0x3fffda, 22},
- {0x1fffdd, 21},
- {0xfffe9, 20},
- {0x3fffdb, 22},
- {0x3fffdc, 22},
- {0x7fffe8, 23},
- {0x7fffe9, 23},
- {0x1fffde, 21},
- {0x7fffde, 23},
- {0x3fffdd, 22},
- {0x3fffde, 22},
- {0xfffff0, 24},
- {0x1fffdf, 21},
- {0x3fffdf, 22},
- {0x7fffeb, 23},
- {0x7fffec, 23},
- {0x1fffe0, 21},
- {0x1fffe1, 21},
- {0x3fffe0, 22},
- {0x1fffe2, 21},
- {0x7fffed, 23},
- {0x3fffe1, 22},
- {0x7fffee, 23},
- {0x7fffef, 23},
- {0xfffea, 20},
- {0x3fffe2, 22},
- {0x3fffe3, 22},
- {0x3fffe4, 22},
- {0x7ffff0, 23},
- {0x3fffe5, 22},
- {0x3fffe6, 22},
- {0x7ffff1, 23},
- {0x3ffffe0, 26},
- {0x3ffffe1, 26},
- {0xfffeb, 20},
- {0x7fff1, 19},
- {0x3fffe7, 22},
- {0x7ffff2, 23},
- {0x3fffe8, 22},
- {0x1ffffec, 25},
- {0x3ffffe2, 26},
- {0x3ffffe3, 26},
- {0x3ffffe4, 26},
- {0x7ffffde, 27},
- {0x7ffffdf, 27},
- {0x3ffffe5, 26},
- {0xfffff1, 24},
- {0x1ffffed, 25},
- {0x7fff2, 19},
- {0x1fffe3, 21},
- {0x3ffffe6, 26},
- {0x7ffffe0, 27},
- {0x7ffffe1, 27},
- {0x3ffffe7, 26},
- {0x3ffffe2, 27},
- {0xfffff2, 24},
- {0x1fffe4, 21},
- {0x1fffe5, 21},
- {0x3ffffe8, 26},
- {0x3ffffe9, 26},
- {0xffffffd, 28},
- {0x7ffffe3, 27},
- {0x7ffffe4, 27},
- {0x7ffffe5, 27},
- {0xfffec, 20},
- {0xfffff3, 24},
- {0xfffed, 20},
- {0x1fffe6, 21},
- {0x3fffe9, 22},
- {0x1fffe7, 21},
- {0x1fffe8, 21},
- {0x7ffff3, 23},
- {0x3fffea, 22},
- {0x3fffeb, 22},
- {0x1ffffee, 25},
- {0x1ffffef, 25},
- {0xfffff4, 24},
- {0xfffff5, 24},
- {0x3ffffea, 26},
- {0x7ffff4, 23},
- {0x3ffffeb, 26},
- {0x7ffffe6, 27},
- {0x3ffffec, 26},
- {0x3ffffed, 26},
- {0x7ffffe7, 27},
- {0x7ffffe8, 27},
- {0x7ffffe9, 27},
- {0x7ffffea, 27},
- {0x7ffffeb, 27},
- {0xffffffe, 28},
- {0x7ffffec, 27},
- {0x7ffffed, 27},
- {0x7ffffee, 27},
- {0x7ffffef, 27},
- {0x7fffff0, 27},
- {0x3ffffee, 26},
- {0x3fffffff, 30}
-};
-
-typedef struct node {
- node *left, *right;
- char ascii_code;
-} Node;
-
-Node* HUFFMAN_TREE_ROOT;
-
-static Node*
-make_huffman_tree_node()
-{
- Node *n = static_cast<Node *>(ats_malloc(sizeof(Node)));
- n->left = NULL;
- n->right = NULL;
- n->ascii_code = '\0';
- return n;
-}
-
-static Node*
-make_huffman_tree()
-{
- Node* root = make_huffman_tree_node();
- Node* current;
- uint32_t bit_len;
- // insert leafs for each ascii code
- for (unsigned i = 0; i < HUFFMAN_TABLE_ENTRY_NUM; i++){
- bit_len = huffman_table[i].bit_len;
- current = root;
- while (bit_len > 0){
- if (huffman_table[i].code_as_hex & (1 << (bit_len-1))) {
- if (!current->right)
- current->right = make_huffman_tree_node();
- current = current->right;
- } else {
- if (!current->left)
- current->left = make_huffman_tree_node();
- current = current->left;
- }
- bit_len--;
- }
- current->ascii_code = i;
- }
- return root;
-}
-
-static void
-free_huffman_tree(Node* node)
-{
- if (node->left)
- free_huffman_tree(node->left);
- if (node->right)
- free_huffman_tree(node->right);
-
- ats_free(node);
-}
-
-void hpack_huffman_init()
-{
- if (!HUFFMAN_TREE_ROOT)
- HUFFMAN_TREE_ROOT = make_huffman_tree();
-}
-
-void hpack_huffman_fin()
-{
- if (HUFFMAN_TREE_ROOT)
- free_huffman_tree(HUFFMAN_TREE_ROOT);
-}
-
-int64_t
-huffman_decode(char* dst_start, const uint8_t* src, uint32_t src_len)
-{
- char* dst_end = dst_start;
- uint8_t shift = 7;
- Node* current = HUFFMAN_TREE_ROOT;
-
- while (src_len) {
- if (*src & (1 << shift)) {
- current = current->right;
- } else {
- current = current->left;
- }
-
- if (current->ascii_code) {
- *dst_end = current->ascii_code;
- ++dst_end;
- current = HUFFMAN_TREE_ROOT;
- }
- if (shift) {
- --shift;
- } else {
- shift = 7;
- ++src;
- --src_len;
- }
- }
-
- return dst_end - dst_start;
-}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/hdrs/HPACKHuffman.h
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HPACKHuffman.h b/proxy/hdrs/HPACKHuffman.h
deleted file mode 100644
index 0037a72..0000000
--- a/proxy/hdrs/HPACKHuffman.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/** @file
-
- A brief file description
-
- @section license License
-
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-#ifndef __HPACK_HUFFMAN_H__
-#define __HPACK_HUFFMAN_H__
-
-#include <stddef.h>
-#include <stdint.h>
-
-void hpack_huffman_init();
-void hpack_huffman_fin();
-int64_t huffman_decode(char* dst_start, const uint8_t* src, uint32_t src_len);
-
-#endif /* __HPACK_Huffman_H__ */
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/hdrs/HTTP.cc
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HTTP.cc b/proxy/hdrs/HTTP.cc
index cf00d71..e637826 100644
--- a/proxy/hdrs/HTTP.cc
+++ b/proxy/hdrs/HTTP.cc
@@ -145,13 +145,6 @@ int HTTP_LEN_S_MAXAGE;
int HTTP_LEN_NEED_REVALIDATE_ONCE;
int HTTP_LEN_100_CONTINUE;
-// Constant strings for pseudo headers of HPACK
-const static char* HPACK_HEADER_SCHEME_STRING = ":scheme";
-const static char* HPACK_HEADER_METHOD_STRING = ":method";
-const static char* HPACK_HEADER_AUTHORITY_STRING = ":authority";
-const static char* HPACK_HEADER_PATH_STRING = ":path";
-const static char* HPACK_HEADER_STATUS_STRING = ":status";
-
Arena* const HTTPHdr::USE_HDR_HEAP_MAGIC = reinterpret_cast<Arena*>(1);
/***********************************************************************
@@ -1095,148 +1088,6 @@ http_parser_parse_req(HTTPParser *parser, HdrHeap *heap, HTTPHdrImpl *hh, const
return mime_parser_parse(&parser->m_mime_parser, heap, hh->m_fields_impl, start, end, must_copy_strings, eof);
}
-MIMEParseResult
-convert_from_2_to_1_1_header(HTTPHdr* headers)
-{
- MIMEField* field;
-
- ink_assert(http_hdr_type_get(headers->m_http) != HTTP_TYPE_UNKNOWN);
-
- if (http_hdr_type_get(headers->m_http) == HTTP_TYPE_REQUEST) {
- const char *scheme, *authority, *path, *method;
- 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_HEADER_SCHEME_STRING, strlen(HPACK_HEADER_SCHEME_STRING))) != NULL) {
- scheme = field->value_get(&scheme_len);
- } else {
- return PARSE_ERROR;
- }
- if ((field = headers->field_find(HPACK_HEADER_AUTHORITY_STRING, strlen(HPACK_HEADER_AUTHORITY_STRING))) != NULL) {
- authority = field->value_get(&authority_len);
- } else {
- return PARSE_ERROR;
- }
- if ((field = headers->field_find(HPACK_HEADER_PATH_STRING, strlen(HPACK_HEADER_PATH_STRING))) != NULL) {
- path = field->value_get(&path_len);
- } else {
- return PARSE_ERROR;
- }
-
- // Parse URL
- Arena arena;
- size_t url_length = scheme_len + 3 + authority_len + path_len;
- char* url = arena.str_alloc(url_length);
- const char* url_start = url;
- strncpy(url, scheme, scheme_len);
- strncpy(url+scheme_len, "://", 3);
- strncpy(url+scheme_len+3, authority, authority_len);
- strncpy(url+scheme_len+3+authority_len, path, path_len);
- url_parse(headers->m_heap, headers->m_http->u.req.m_url_impl, &url_start, url + url_length, 1);
- arena.str_free(url);
-
- // Get value of :method
- if ((field = headers->field_find(HPACK_HEADER_METHOD_STRING, strlen(HPACK_HEADER_METHOD_STRING))) != NULL) {
- method = field->value_get(&method_len);
-
- int method_wks_idx = hdrtoken_tokenize(method, method_len);
- http_hdr_method_set(headers->m_heap, headers->m_http,
- method, method_wks_idx, method_len, 0);
- } else {
- return PARSE_ERROR;
- }
-
- // Convert HTTP version to 1.1
- int32_t version = HTTP_VERSION(1, 1);
- http_hdr_version_set(headers->m_http, version);
-
- // Remove HTTP/2 style headers
- headers->field_delete(HPACK_HEADER_SCHEME_STRING, strlen(HPACK_HEADER_SCHEME_STRING));
- headers->field_delete(HPACK_HEADER_METHOD_STRING, strlen(HPACK_HEADER_METHOD_STRING));
- headers->field_delete(HPACK_HEADER_AUTHORITY_STRING, strlen(HPACK_HEADER_AUTHORITY_STRING));
- headers->field_delete(HPACK_HEADER_PATH_STRING, strlen(HPACK_HEADER_PATH_STRING));
- } else {
- int status_len;
- const char* status;
-
- if ((field = headers->field_find(HPACK_HEADER_STATUS_STRING, strlen(HPACK_HEADER_STATUS_STRING))) != NULL) {
- status = field->value_get(&status_len);
- headers->status_set(http_parse_status(status, status + status_len));
- } else {
- return PARSE_ERROR;
- }
-
- // Remove HTTP/2 style headers
- headers->field_delete(HPACK_HEADER_STATUS_STRING, strlen(HPACK_HEADER_STATUS_STRING));
- }
-
- return PARSE_DONE;
-}
-
-int64_t
-convert_from_1_1_to_2_header(HTTPHdr* in, uint8_t* out, uint64_t out_len, Http2HeaderTable& /* header_table */)
-{
- 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 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.
-
- MIMEField* field;
- MIMEFieldIter field_iter;
- for (field = in->iter_get_first(&field_iter); field != NULL; field = in->iter_get_next(&field_iter)) {
- do {
- MIMEFieldWrapper header(field, in->m_heap, in->m_http->m_fields_impl);
- if ((len = encode_literal_header_field(p, end, header, INC_INDEXING)) == -1) {
- return -1;
- }
- p += len;
- } while (field->has_dups() && (field = field->m_next_dup) != NULL);
- }
-
- return p - out;
-}
-
-MIMEParseResult
-http2_parse_req(HdrHeap *heap, HTTPHdrImpl *hh, uint8_t* buf_start, uint8_t* buf_end, bool /* eof */, Http2HeaderTable& header_table)
-{
- uint8_t* cursor = buf_start;
-
- do {
- int64_t read_bytes = 0;
-
- if ((read_bytes = update_header_table_size(cursor, buf_end, header_table)) == -1) {
- return PARSE_ERROR;
- }
-
- // 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);
- if (*cursor & 0x80) {
- if ((read_bytes = decode_indexed_header_field(header, cursor, buf_end, header_table)) == -1) {
- return PARSE_ERROR;
- }
- cursor += read_bytes;
- } else {
- if ((read_bytes = decode_literal_header_field(header, cursor, buf_end, header_table)) == -1) {
- return PARSE_ERROR;
- }
- cursor += read_bytes;
- }
-
- // Store to HdrHeap
- mime_hdr_field_attach(hh->m_fields_impl, field, 1, NULL);
- } while (cursor < buf_end);
-
- // XXX I think that we need to check the eof flag so we can accurately report whether we parsed the whole
- // header, though perhaps that's better done at the framing layer .. jpeach
-
- return PARSE_DONE;
-}
-
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/hdrs/HTTP.h
----------------------------------------------------------------------
diff --git a/proxy/hdrs/HTTP.h b/proxy/hdrs/HTTP.h
index d531e83..f9175e5 100644
--- a/proxy/hdrs/HTTP.h
+++ b/proxy/hdrs/HTTP.h
@@ -29,7 +29,6 @@
#include "INK_MD5.h"
#include "MIME.h"
#include "URL.h"
-#include "HPACK.h"
#include "ink_apidefs.h"
@@ -472,7 +471,6 @@ MIMEParseResult http_parser_parse_resp(HTTPParser *parser, HdrHeap *heap,
HTTPHdrImpl *hh, const char **start,
const char *end, bool must_copy_strings, bool eof);
-MIMEParseResult http2_parse_req(HdrHeap *heap, HTTPHdrImpl *hh, uint8_t* buf_start, uint8_t* buf_end, bool eof, Http2HeaderTable& header_table);
HTTPStatus http_parse_status(const char *start, const char *end);
int32_t http_parse_version(const char *start, const char *end);
@@ -659,8 +657,6 @@ public:
MIMEParseResult parse_req(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof);
MIMEParseResult parse_resp(HTTPParser *parser, IOBufferReader *r, int *bytes_used, bool eof);
- MIMEParseResult hpack_parse_req(uint8_t* start, uint8_t* end, bool eof, Http2HeaderTable& header_table);
-
public:
// Utility routines
bool is_cache_control_set(const char *cc_directive_wks);
@@ -1226,21 +1222,6 @@ HTTPHdr::parse_req(HTTPParser *parser, const char **start, const char *end, bool
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
-/*
- * Parse HTTP/2 headers encoded by HPACK and convert to HTTPHdr object
- */
-inline MIMEParseResult
-HTTPHdr::hpack_parse_req(uint8_t* start, uint8_t* end, bool eof, Http2HeaderTable& header_table)
-{
- ink_assert(valid());
- ink_assert(m_http->m_polarity == HTTP_TYPE_REQUEST);
-
- return http2_parse_req(m_heap, m_http, start, end, eof, header_table);
-}
-
-/*-------------------------------------------------------------------------
- -------------------------------------------------------------------------*/
-
inline MIMEParseResult
HTTPHdr::parse_resp(HTTPParser *parser, const char **start, const char *end, bool eof)
{
@@ -1542,11 +1523,4 @@ HTTPInfo::get_frag_offset_count() {
return m_alt ? m_alt->m_frag_offset_count : 0;
}
-
-MIMEParseResult
-convert_from_2_to_1_1_header(HTTPHdr* header);
-
-int64_t
-convert_from_1_1_to_2_header(HTTPHdr* in, uint8_t* out, uint64_t out_len, Http2HeaderTable& header_table);
-
#endif /* __HTTP_H__ */
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/hdrs/Makefile.am
----------------------------------------------------------------------
diff --git a/proxy/hdrs/Makefile.am b/proxy/hdrs/Makefile.am
index 6a05299..a5be335 100644
--- a/proxy/hdrs/Makefile.am
+++ b/proxy/hdrs/Makefile.am
@@ -41,9 +41,7 @@ libhdrs_a_SOURCES = \
MIME.cc \
MIME.h \
URL.cc \
- URL.h \
- HPACKHuffman.cc \
- HPACK.cc
+ URL.h
if BUILD_TESTS
libhdrs_a_SOURCES += \
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/http2/HPACK.cc
----------------------------------------------------------------------
diff --git a/proxy/http2/HPACK.cc b/proxy/http2/HPACK.cc
new file mode 100644
index 0000000..95cbc71
--- /dev/null
+++ b/proxy/http2/HPACK.cc
@@ -0,0 +1,599 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "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;
+
+// 5.1. Maximum Table Size
+// The size of an entry is the sum of its name's length in octets (as
+// defined in Section 6.2), its value's length in octets (see
+// Section 6.2), plus 32.
+const static unsigned ADDITIONAL_OCTETS = 32;
+
+const static uint32_t HEADER_FIELD_LIMIT_LENGTH = 4096;
+
+typedef enum {
+ TS_HPACK_STATIC_TABLE_0 = 0,
+ TS_HPACK_STATIC_TABLE_AUTHORITY,
+ TS_HPACK_STATIC_TABLE_METHOD_GET,
+ TS_HPACK_STATIC_TABLE_METHOD_POST,
+ TS_HPACK_STATIC_TABLE_PATH_ROOT,
+ TS_HPACK_STATIC_TABLE_PATH_INDEX,
+ TS_HPACK_STATIC_TABLE_SCHEME_HTTP,
+ TS_HPACK_STATIC_TABLE_SCHEME_HTTPS,
+ TS_HPACK_STATIC_TABLE_STATUS_200,
+ TS_HPACK_STATIC_TABLE_STATUS_204,
+ TS_HPACK_STATIC_TABLE_STATUS_206,
+ TS_HPACK_STATIC_TABLE_STATUS_304,
+ TS_HPACK_STATIC_TABLE_STATUS_400,
+ TS_HPACK_STATIC_TABLE_STATUS_404,
+ TS_HPACK_STATIC_TABLE_STATUS_500,
+ TS_HPACK_STATIC_TABLE_ACCEPT_CHARSET,
+ TS_HPACK_STATIC_TABLE_ACCEPT_ENCODING,
+ TS_HPACK_STATIC_TABLE_ACCEPT_LANGUAGE,
+ TS_HPACK_STATIC_TABLE_ACCEPT_RANGES,
+ TS_HPACK_STATIC_TABLE_ACCEPT,
+ TS_HPACK_STATIC_TABLE_ACCESS_CONTROL_ALLOW_ORIGIN,
+ TS_HPACK_STATIC_TABLE_AGE,
+ TS_HPACK_STATIC_TABLE_ALLOW,
+ TS_HPACK_STATIC_TABLE_AUTHORIZATION,
+ TS_HPACK_STATIC_TABLE_CACHE_CONTROL,
+ TS_HPACK_STATIC_TABLE_CONTENT_DISPOSITION,
+ TS_HPACK_STATIC_TABLE_CONTENT_ENCODING,
+ TS_HPACK_STATIC_TABLE_CONTENT_LANGUAGE,
+ TS_HPACK_STATIC_TABLE_CONTENT_LENGTH,
+ TS_HPACK_STATIC_TABLE_CONTENT_LOCATION,
+ TS_HPACK_STATIC_TABLE_CONTENT_RANGE,
+ TS_HPACK_STATIC_TABLE_CONTENT_TYPE,
+ TS_HPACK_STATIC_TABLE_COOKIE,
+ TS_HPACK_STATIC_TABLE_DATE,
+ TS_HPACK_STATIC_TABLE_ETAG,
+ TS_HPACK_STATIC_TABLE_EXPECT,
+ TS_HPACK_STATIC_TABLE_EXPIRES,
+ TS_HPACK_STATIC_TABLE_FROM,
+ TS_HPACK_STATIC_TABLE_HOST,
+ TS_HPACK_STATIC_TABLE_IF_MATCH,
+ TS_HPACK_STATIC_TABLE_IF_MODIFIED_SINCE,
+ TS_HPACK_STATIC_TABLE_IF_NONE_MATCH,
+ TS_HPACK_STATIC_TABLE_IF_RANGE,
+ TS_HPACK_STATIC_TABLE_IF_UNMODIFIED_SINCE,
+ TS_HPACK_STATIC_TABLE_LAST_MODIFIED,
+ TS_HPACK_STATIC_TABLE_LINK,
+ TS_HPACK_STATIC_TABLE_LOCATION,
+ TS_HPACK_STATIC_TABLE_MAX_FORWARDS,
+ TS_HPACK_STATIC_TABLE_PROXY_AUTHENTICATE,
+ TS_HPACK_STATIC_TABLE_PROXY_AUTHORIZATION,
+ TS_HPACK_STATIC_TABLE_RANGE,
+ TS_HPACK_STATIC_TABLE_REFERER,
+ TS_HPACK_STATIC_TABLE_REFRESH,
+ TS_HPACK_STATIC_TABLE_RETRY_AFTER,
+ TS_HPACK_STATIC_TABLE_SERVER,
+ TS_HPACK_STATIC_TABLE_SET_COOKIE,
+ TS_HPACK_STATIC_TABLE_STRICT_TRANSPORT_SECURITY,
+ TS_HPACK_STATIC_TABLE_TRANSFER_ENCODING,
+ TS_HPACK_STATIC_TABLE_USER_AGENT,
+ TS_HPACK_STATIC_TABLE_VARY,
+ TS_HPACK_STATIC_TABLE_VIA,
+ TS_HPACK_STATIC_TABLE_WWW_AUTHENTICATE,
+ TS_HPACK_STATIC_TABLE_ENTRY_NUM
+} TS_HPACK_STATIC_TABLE_ENTRY;
+
+const static struct {
+ const char* name;
+ const char* value;
+} STATIC_TABLE[] = {
+ {"", ""},
+ {":authority", ""},
+ {":method", "GET"},
+ {":method", "POST"},
+ {":path", "/"},
+ {":path", "/index.html"},
+ {":scheme", "http"},
+ {":scheme", "https"},
+ {":status", "200"},
+ {":status", "204"},
+ {":status", "206"},
+ {":status", "304"},
+ {":status", "400"},
+ {":status", "404"},
+ {":status", "500"},
+ {"accept-charset", ""},
+ {"accept-encoding", "gzip, deflate"},
+ {"accept-language", ""},
+ {"accept-ranges", ""},
+ {"accept", ""},
+ {"access-control-allow-origin", ""},
+ {"age", ""},
+ {"allow", ""},
+ {"authorization", ""},
+ {"cache-control", ""},
+ {"content-disposition", ""},
+ {"content-encoding", ""},
+ {"content-language", ""},
+ {"content-length", ""},
+ {"content-location", ""},
+ {"content-range", ""},
+ {"content-type", ""},
+ {"cookie", ""},
+ {"date", ""},
+ {"etag", ""},
+ {"expect", ""},
+ {"expires", ""},
+ {"from", ""},
+ {"host", ""},
+ {"if-match", ""},
+ {"if-modified-since", ""},
+ {"if-none-match", ""},
+ {"if-range", ""},
+ {"if-unmodified-since", ""},
+ {"last-modified", ""},
+ {"link", ""},
+ {"location", ""},
+ {"max-forwards", ""},
+ {"proxy-authenticate", ""},
+ {"proxy-authorization", ""},
+ {"range", ""},
+ {"referer", ""},
+ {"refresh", ""},
+ {"retry-after", ""},
+ {"server", ""},
+ {"set-cookie", ""},
+ {"strict-transport-security", ""},
+ {"transfer-encoding", ""},
+ {"user-agent", ""},
+ {"vary", ""},
+ {"via", ""},
+ {"www-authenticate", ""}
+};
+
+int
+Http2HeaderTable::get_header_from_indexing_tables(uint32_t index, MIMEFieldWrapper& field) const
+{
+ // Index Address Space starts at 1, so index == 0 is invalid.
+ if (!index) return -1;
+
+ if (index < TS_HPACK_STATIC_TABLE_ENTRY_NUM) {
+ 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 + get_current_entry_num()) {
+ const MIMEField* m_field = get_header(index - TS_HPACK_STATIC_TABLE_ENTRY_NUM + 1);
+
+ int name_len, value_len;
+ const char* name = m_field->name_get(&name_len);
+ const char* value = m_field->value_get(&value_len);
+
+ field.name_set(name, name_len);
+ field.value_set(value, value_len);
+ } else {
+ // 3.3.3. Index Address Space
+ // Indices strictly greater than the sum of the lengths of both tables
+ // MUST be treated as a decoding error.
+ return -1;
+ }
+
+ return 0;
+}
+
+// 5.2. Entry Eviction when Header Table Size Changes
+// Whenever the maximum size for the header table is reduced, entries
+// are evicted from the end of the header table until the size of the
+// header table is less than or equal to the maximum size.
+void
+Http2HeaderTable::set_header_table_size(uint32_t new_size)
+{
+ uint32_t old_size = _settings_header_table_size;
+ while (old_size > new_size) {
+ int last_name_len, last_value_len;
+ MIMEField* last_field = _headers.last();
+
+ last_field->name_get(&last_name_len);
+ last_field->value_get(&last_value_len);
+ old_size -= ADDITIONAL_OCTETS + last_name_len + last_value_len;
+
+ _headers.remove_index(_headers.length()-1);
+ _mhdr->field_delete(last_field, false);
+ }
+
+ _settings_header_table_size = new_size;
+}
+
+void
+Http2HeaderTable::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_header_table_size) {
+ // 5.3. 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 table causes the table to be emptied of all existing entries.
+ _headers.clear();
+ _mhdr->fields_clear();
+ } else {
+ _current_size += header_size;
+ while (_current_size > _settings_header_table_size) {
+ int last_name_len, last_value_len;
+ MIMEField* last_field = _headers.last();
+
+ last_field->name_get(&last_name_len);
+ last_field->value_get(&last_value_len);
+ _current_size -= ADDITIONAL_OCTETS + last_name_len + last_value_len;
+
+ _headers.remove_index(_headers.length()-1);
+ _mhdr->field_delete(last_field, false);
+ }
+
+ MIMEField* new_field = _mhdr->field_create(name, name_len);
+ new_field->value_set(_mhdr->m_heap, _mhdr->m_mime, value, value_len);
+ // XXX Because entire Vec instance is copied, Its too expensive!
+ _headers.insert(0, new_field);
+ }
+}
+
+/*
+ * Pseudo code
+ *
+ * if I < 2^N - 1, encode I on N bits
+ * else
+ * encode (2^N - 1) on N bits
+ * I = I - (2^N - 1)
+ * while I >= 128
+ * encode (I % 128 + 128) on 8 bits
+ * I = I / 128
+ * encode I on 8 bits
+ */
+int64_t
+encode_integer(uint8_t *buf_start, const uint8_t *buf_end, uint32_t value, uint8_t n)
+{
+ if (buf_start >= buf_end) return -1;
+
+ uint8_t *p = buf_start;
+
+ if (value < (static_cast<uint32_t>(1 << n) - 1)) {
+ *(p++) |= value;
+ } else {
+ *(p++) |= (1 << n) - 1;
+ value -= (1 << n) - 1;
+ while (value >= 128) {
+ if (p >= buf_end) {
+ return -1;
+ }
+ *(p++) = (value & 0x7F) | 0x80;
+ value = value >> 7;
+ }
+ if (p+1 >= buf_end) {
+ return -1;
+ }
+ *(p++) = value;
+ }
+ return p - buf_start;
+}
+
+int64_t
+encode_string(uint8_t *buf_start, const uint8_t *buf_end, const char* value, size_t value_len)
+{
+ uint8_t *p = buf_start;
+
+ // Length
+ const int64_t len = encode_integer(p, buf_end, value_len, 7);
+ if (len == -1) return -1;
+ p += len;
+ if (buf_end < p || static_cast<size_t>(buf_end - p) < value_len) return -1;
+
+ // Value String
+ memcpy(p, value, value_len);
+ p += value_len;
+ return p - buf_start;
+}
+
+int64_t
+encode_indexed_header_field(uint8_t *buf_start, const uint8_t *buf_end, uint32_t index)
+{
+ if (buf_start >= buf_end) return -1;
+
+ uint8_t *p = buf_start;
+
+ // Index
+ const int64_t len = encode_integer(p, buf_end, index, 7);
+ if (len == -1) return -1;
+
+ // Representation type
+ if (p+1 >= buf_end) {
+ return -1;
+ }
+ *p |= '\x80';
+ p += len;
+
+ return p - buf_start;
+}
+
+int64_t
+encode_literal_header_field(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper& header, uint32_t index, HEADER_INDEXING_TYPE type)
+{
+ uint8_t *p = buf_start;
+ int64_t len;
+ uint8_t prefix = 0, flag = 0;
+
+ switch (type) {
+ case INC_INDEXING:
+ prefix = 6;
+ flag = 0x40;
+ break;
+ case WITHOUT_INDEXING:
+ prefix = 4;
+ flag = 0x00;
+ break;
+ case NEVER_INDEXED:
+ prefix = 4;
+ flag = 0x10;
+ break;
+ default:
+ return -1;
+ }
+
+ // Index
+ len = encode_integer(p, buf_end, index, prefix);
+ if (len == -1) return -1;
+
+ // Representation type
+ if (p+1 >= buf_end) {
+ return -1;
+ }
+ *p |= flag;
+ p += len;
+
+ // Value String
+ int value_len;
+ const char* value = header.value_get(&value_len);
+ len = encode_string(p, buf_end, value, value_len);
+ if (len == -1) return -1;
+ p += len;
+
+ return p - buf_start;
+}
+
+int64_t
+encode_literal_header_field(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper& header, HEADER_INDEXING_TYPE type)
+{
+ uint8_t *p = buf_start;
+ int64_t len;
+ uint8_t flag = 0;
+
+ ink_assert(type >= INC_INDEXING && type <= NEVER_INDEXED);
+ switch (type) {
+ case INC_INDEXING:
+ flag = 0x40;
+ break;
+ case WITHOUT_INDEXING:
+ flag = 0x00;
+ break;
+ case NEVER_INDEXED:
+ flag = 0x10;
+ break;
+ default:
+ return -1;
+ }
+ if (p+1 >= buf_end) {
+ return -1;
+ }
+ *(p++) = flag;
+
+ // Name String
+ int name_len;
+ const char* name = header.name_get(&name_len);
+ len = encode_string(p, buf_end, name, name_len);
+ if (len == -1) return -1;
+ p += len;
+
+ // Value String
+ int value_len;
+ const char* value = header.value_get(&value_len);
+ len = encode_string(p, buf_end, value, value_len);
+ if (len == -1) {
+ return -1;
+ }
+
+ p += len;
+
+ return p - buf_start;
+}
+
+/*
+ * 6.1. Integer representation
+ *
+ * Pseudo code
+ *
+ * decode I from the next N bits
+ * if I < 2^N - 1, return I
+ * else
+ * M = 0
+ * repeat
+ * B = next octet
+ * I = I + (B & 127) * 2^M
+ * M = M + 7
+ * while B & 128 == 128
+ * return I
+ *
+ */
+int64_t
+decode_integer(uint32_t& dst, const uint8_t *buf_start, const uint8_t *buf_end, uint8_t n)
+{
+ const uint8_t *p = buf_start;
+
+ dst = (*p & ((1 << n) - 1));
+ if (dst == static_cast<uint32_t>(1 << n) - 1) {
+ int m = 0;
+ do {
+ if (++p >= buf_end) return -1;
+
+ uint32_t added_value = *p & 0x7f;
+ if ((UINT32_MAX >> m) < added_value) {
+ // Excessively large integer encodings - in value or octet
+ // length - MUST be treated as a decoding error.
+ return -1;
+ }
+ dst += added_value << m;
+ m += 7;
+ } while (*p & 0x80);
+ }
+
+ return p - buf_start + 1;
+}
+
+// 6.2 return content from String Data (Length octets)
+// with huffman decoding if it is encoded
+int64_t
+decode_string(char **c_str, uint32_t& c_str_length, const uint8_t *buf_start, const uint8_t *buf_end)
+{
+ const uint8_t *p = buf_start;
+ bool isHuffman = *p & 0x80;
+ uint32_t encoded_string_len = 0;
+ int64_t len = 0;
+
+ len = decode_integer(encoded_string_len, p, buf_end, 7);
+ if (len == -1) return -1;
+ p += len;
+
+ if (encoded_string_len > HEADER_FIELD_LIMIT_LENGTH || buf_start + encoded_string_len >= buf_end) {
+ return -1;
+ }
+
+ if (isHuffman) {
+ // Allocate temporary area twice the size of before decoded data
+ *c_str = static_cast<char*>(ats_malloc(encoded_string_len * 2));
+
+ len = huffman_decode(*c_str, p, encoded_string_len);
+ if (len == -1) return -1;
+ c_str_length = len;
+ } else {
+ *c_str = static_cast<char*>(ats_malloc(encoded_string_len));
+
+ memcpy(*c_str, reinterpret_cast<const char*>(p), encoded_string_len);
+
+ c_str_length = encoded_string_len;
+ }
+
+ return p + encoded_string_len - buf_start;
+}
+
+// 7.1. Indexed Header Field Representation
+int64_t
+decode_indexed_header_field(MIMEFieldWrapper& header, const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table)
+{
+ uint32_t index = 0;
+ int64_t len = 0;
+ len = decode_integer(index, buf_start, buf_end, 7);
+ if (len == -1) return -1;
+
+ if (header_table.get_header_from_indexing_tables(index, header) == -1) {
+ return -1;
+ }
+
+ return len;
+}
+
+// 7.2. Literal Header Field Representation
+int64_t
+decode_literal_header_field(MIMEFieldWrapper& header, const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table)
+{
+ const uint8_t *p = buf_start;
+ bool isIncremental = false;
+ uint32_t index = 0;
+ int64_t len = 0;
+
+ if (*p & 0x40) {
+ // 7.2.1. index extraction based on Literal Header Field with Incremental Indexing
+ len = decode_integer(index, p, buf_end, 6);
+ if (len == -1) return -1;
+ isIncremental = true;
+ } else if (*p & 0x10) {
+ // 7.2.3. index extraction Literal Header Field Never Indexed
+ len = decode_integer(index, p, buf_end, 4);
+ if (len == -1) return -1;
+ } else {
+ // 7.2.2. index extraction Literal Header Field without Indexing
+ len = decode_integer(index, p, buf_end, 4);
+ if (len == -1) return -1;
+ }
+ p += len;
+
+ if (index) {
+ header_table.get_header_from_indexing_tables(index, header);
+ } else {
+ char *c_name = NULL;
+ uint32_t c_name_len = 0;
+ len = decode_string(&c_name, c_name_len, p, buf_end);
+ if (len == -1) return -1;
+ p += len;
+ header.name_set(c_name, c_name_len);
+ ats_free(c_name);
+ }
+ char *c_value = NULL;
+ uint32_t c_value_len = 0;
+ len = decode_string(&c_value, c_value_len, p, buf_end);
+ if (len == -1) return -1;
+ p += len;
+ header.value_set(c_value, c_value_len);
+ ats_free(c_value);
+
+ // Incremental Indexing adds header to header table as new entry
+ if (isIncremental) {
+ header_table.add_header_field(header.field_get());
+ }
+
+ return p - buf_start;
+}
+
+// 7.3. Header Table Size Update
+int64_t
+update_header_table_size(const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table)
+{
+ if (buf_start == buf_end) return -1;
+
+ int64_t len = 0;
+
+ // Update header table size if its required.
+ if ((*buf_start & 0xe0) == 0x20) {
+ uint32_t size = 0;
+ len = decode_integer(size, buf_start, buf_end, 5);
+ if (len == -1) return -1;
+
+ header_table.set_header_table_size(size);
+ }
+
+ return len;
+}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fa6c830f/proxy/http2/HPACK.h
----------------------------------------------------------------------
diff --git a/proxy/http2/HPACK.h b/proxy/http2/HPACK.h
new file mode 100644
index 0000000..4abccac
--- /dev/null
+++ b/proxy/http2/HPACK.h
@@ -0,0 +1,142 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef __HPACK_H__
+#define __HPACK_H__
+
+#include "libts.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;
+
+enum HEADER_INDEXING_TYPE {
+ INC_INDEXING,
+ WITHOUT_INDEXING,
+ NEVER_INDEXED,
+};
+
+class MIMEFieldWrapper
+{
+public:
+
+ MIMEFieldWrapper(MIMEField * f, HdrHeap * hh, MIMEHdrImpl * impl)
+ : _field(f), _heap(hh), _mh(impl) {
+ }
+
+ void name_set(const char * name, int name_len) {
+ _field->name_set(_heap, _mh, name, name_len);
+ }
+
+ void value_set(const char * value, int value_len) {
+ _field->value_set(_heap, _mh, value, value_len);
+ }
+
+ const char * name_get(int * length) const {
+ return _field->name_get(length);
+ }
+
+ const char * value_get(int * length) const {
+ return _field->value_get(length);
+ }
+
+ const MIMEField * field_get() const {
+ return _field;
+ }
+
+private:
+ MIMEField * _field;
+ HdrHeap * _heap;
+ MIMEHdrImpl * _mh;
+};
+
+// 3.2 Header Table
+class Http2HeaderTable
+{
+public:
+
+ Http2HeaderTable() : _current_size(0), _settings_header_table_size(4096) {
+ _mhdr = new MIMEHdr();
+ _mhdr->create();
+ }
+
+ ~Http2HeaderTable() {
+ _headers.clear();
+ _mhdr->fields_clear();
+ }
+
+ void add_header_field(const MIMEField * field);
+ int get_header_from_indexing_tables(uint32_t index, MIMEFieldWrapper& header_field) const;
+ void set_header_table_size(uint32_t new_size);
+
+private:
+
+ const MIMEField * get_header(uint32_t index) const {
+ return _headers.get(index-1);
+ }
+
+ const uint32_t get_current_entry_num() const {
+ return _headers.length();
+ }
+
+ uint32_t _current_size;
+ uint32_t _settings_header_table_size;
+
+ MIMEHdr * _mhdr;
+ Vec<MIMEField *> _headers;
+};
+
+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(char **c_str, uint32_t& c_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(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper& header, uint32_t index, HEADER_INDEXING_TYPE type);
+int64_t
+encode_literal_header_field(uint8_t *buf_start, const uint8_t *buf_end, const MIMEFieldWrapper& header, HEADER_INDEXING_TYPE type);
+
+int64_t
+decode_indexed_header_field(MIMEFieldWrapper& header, const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table);
+int64_t
+decode_literal_header_field(MIMEFieldWrapper& header, const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table);
+int64_t
+update_header_table_size(const uint8_t *buf_start, const uint8_t *buf_end, Http2HeaderTable& header_table);
+
+#endif /* __HPACK_H__ */