14 const http_header static_table_entries[] = {
20 {
":path",
"/index.html"},
30 {
"accept-charset",
""},
31 {
"accept-encoding",
"gzip, deflate"},
32 {
"accept-language",
""},
33 {
"accept-ranges",
""},
35 {
"access-control-allow-origin",
""},
38 {
"authorization",
""},
39 {
"cache-control",
""},
40 {
"content-disposition",
""},
41 {
"content-encoding",
""},
42 {
"content-language",
""},
43 {
"content-length",
""},
44 {
"content-location",
""},
45 {
"content-range",
""},
55 {
"if-modified-since",
""},
56 {
"if-none-match",
""},
58 {
"if-unmodified-since",
""},
59 {
"last-modified",
""},
63 {
"proxy-authenticate",
""},
64 {
"proxy-authorization",
""},
71 {
"strict-transport-security",
""},
72 {
"transfer-encoding",
""},
76 {
"www-authenticate",
""}
79 constexpr size_t static_table_size = 61;
85 if (index == 0 || index > static_table_size)
89 return static_table_entries[index];
95 for (
size_t i = 1; i <= static_table_size; ++i)
97 const auto& entry = static_table_entries[i];
98 if (entry.name == name)
100 if (value.empty() || entry.value == value)
111 : max_size_(max_size)
117 http_header header{std::string(name), std::string(value)};
118 size_t entry_size = header.
size();
121 evict_to_size(max_size_ - entry_size);
124 entries_.push_front(std::move(header));
125 current_size_ += entry_size;
130 if (index >= entries_.size())
134 return entries_[index];
138 -> std::optional<size_t>
140 for (
size_t i = 0; i < entries_.size(); ++i)
142 const auto& entry = entries_[i];
143 if (entry.name == name)
145 if (value.empty() || entry.value == value)
157 evict_to_size(max_size_);
183 while (current_size_ > target_size && !entries_.empty())
185 current_size_ -= entries_.back().size();
192 : table_(max_table_size)
197 -> std::vector<uint8_t>
199 std::vector<uint8_t> result;
201 for (
const auto& header :
headers)
205 if (static_index > 0)
208 auto encoded = encode_indexed(static_index);
209 result.insert(result.end(), encoded.begin(), encoded.end());
214 auto dynamic_index = table_.find(header.name, header.value);
215 if (dynamic_index.has_value())
219 auto encoded = encode_indexed(index);
220 result.insert(result.end(), encoded.begin(), encoded.end());
229 auto encoded = encode_literal_with_indexing(name_index, header.value);
230 result.insert(result.end(), encoded.begin(), encoded.end());
231 table_.insert(header.name, header.value);
236 auto dynamic_name_index = table_.find(header.name,
"");
237 if (dynamic_name_index.has_value())
240 auto encoded = encode_literal_with_indexing(index, header.value);
241 result.insert(result.end(), encoded.begin(), encoded.end());
242 table_.insert(header.name, header.value);
247 auto encoded = encode_literal_with_indexing(header.name, header.value);
248 result.insert(result.end(), encoded.begin(), encoded.end());
249 table_.insert(header.name, header.value);
259 table_.set_max_size(size);
268 -> std::vector<uint8_t>
270 std::vector<uint8_t> result;
271 uint8_t max_prefix = (1 << prefix_bits) - 1;
273 if (value < max_prefix)
275 result.push_back(
static_cast<uint8_t
>(value));
279 result.push_back(max_prefix);
284 result.push_back(
static_cast<uint8_t
>((value % 128) + 128));
287 result.push_back(
static_cast<uint8_t
>(value));
294 -> std::vector<uint8_t>
296 std::vector<uint8_t> result;
299 auto length_bytes = encode_integer(str.size(), 7);
302 result.insert(result.end(), length_bytes.begin(), length_bytes.end());
308 length_bytes[0] |= 0x80;
309 result.insert(result.end(), length_bytes.begin(), length_bytes.end());
313 result.insert(result.end(), str.begin(), str.end());
320 auto result = encode_integer(index, 7);
326 std::string_view value)
327 -> std::vector<uint8_t>
329 std::vector<uint8_t> result;
332 result.push_back(0x40);
335 auto name_bytes = encode_string(name);
336 result.insert(result.end(), name_bytes.begin(), name_bytes.end());
339 auto value_bytes = encode_string(value);
340 result.insert(result.end(), value_bytes.begin(), value_bytes.end());
346 std::string_view value)
347 -> std::vector<uint8_t>
349 std::vector<uint8_t> result;
352 auto index_bytes = encode_integer(name_index, 6);
353 index_bytes[0] |= 0x40;
354 result.insert(result.end(), index_bytes.begin(), index_bytes.end());
357 auto value_bytes = encode_string(value);
358 result.insert(result.end(), value_bytes.begin(), value_bytes.end());
364 std::string_view value)
365 -> std::vector<uint8_t>
367 std::vector<uint8_t> result;
370 result.push_back(0x00);
373 auto name_bytes = encode_string(name);
374 result.insert(result.end(), name_bytes.begin(), name_bytes.end());
377 auto value_bytes = encode_string(value);
378 result.insert(result.end(), value_bytes.begin(), value_bytes.end());
384 std::string_view value)
385 -> std::vector<uint8_t>
387 std::vector<uint8_t> result;
390 auto index_bytes = encode_integer(name_index, 4);
392 result.insert(result.end(), index_bytes.begin(), index_bytes.end());
395 auto value_bytes = encode_string(value);
396 result.insert(result.end(), value_bytes.begin(), value_bytes.end());
403 : table_(max_table_size)
410 std::vector<http_header>
headers;
411 auto remaining =
data;
413 while (!remaining.empty())
415 uint8_t first_byte = remaining[0];
417 if (first_byte & 0x80)
420 auto index_result = decode_integer(remaining, 7);
421 if (index_result.is_err())
423 return index_result.error();
425 size_t index = index_result.value();
427 auto header_result = get_indexed_header(index);
428 if (header_result.is_err())
430 return header_result.error();
433 headers.push_back(header_result.value());
435 else if (first_byte & 0x40)
438 auto name_index_result = decode_integer(remaining, 6);
439 if (name_index_result.is_err())
441 return name_index_result.error();
443 size_t name_index = name_index_result.value();
449 auto name_result = decode_string(remaining);
450 if (name_result.is_err())
452 return name_result.error();
454 name = name_result.value();
459 auto header_result = get_indexed_header(name_index);
460 if (header_result.is_err())
462 return header_result.error();
464 name = header_result.value().name;
468 auto value_result = decode_string(remaining);
469 if (value_result.is_err())
471 return value_result.error();
473 std::string value = value_result.value();
475 headers.emplace_back(name, value);
476 table_.insert(name, value);
481 uint8_t prefix_bits = (first_byte & 0x10) ? 4 : 4;
483 auto name_index_result = decode_integer(remaining, prefix_bits);
484 if (name_index_result.is_err())
486 return name_index_result.error();
488 size_t name_index = name_index_result.value();
494 auto name_result = decode_string(remaining);
495 if (name_result.is_err())
497 return name_result.error();
499 name = name_result.value();
504 auto header_result = get_indexed_header(name_index);
505 if (header_result.is_err())
507 return header_result.error();
509 name = header_result.value().name;
513 auto value_result = decode_string(remaining);
514 if (value_result.is_err())
516 return value_result.error();
519 headers.emplace_back(name, value_result.value());
528 table_.set_max_size(size);
542 return error_info(100,
"Insufficient data for integer",
"hpack");
545 uint8_t prefix_mask = (1 << prefix_bits) - 1;
546 uint64_t value =
data[0] & prefix_mask;
549 if (value < prefix_mask)
560 return error_info(101,
"Incomplete integer encoding",
"hpack");
563 uint8_t
byte =
data[0];
566 value += (
byte & 0x7F) << m;
571 return error_info(102,
"Integer overflow",
"hpack");
574 if ((
byte & 0x80) == 0)
588 return error_info(103,
"Insufficient data for string",
"hpack");
593 auto length_result = decode_integer(
data, 7);
594 if (length_result.is_err())
596 return length_result.error();
599 size_t length = length_result.value();
601 if (
data.size() < length)
603 return error_info(104,
"Insufficient data for string value",
"hpack");
610 result.assign(
data.begin(),
data.begin() + length);
614 result.assign(
data.begin(),
data.begin() + length);
626 return error_info(105,
"Invalid index 0",
"hpack");
633 if (header.has_value())
635 return std::move(header.value());
637 return error_info(106,
"Invalid static table index",
"hpack");
642 auto header = table_.get(dynamic_index);
643 if (header.has_value())
645 return std::move(header.value());
648 return error_info(107,
"Invalid dynamic table index",
"hpack");
654 auto encode(std::string_view input) -> std::vector<uint8_t>
657 return std::vector<uint8_t>(input.begin(), input.end());
663 return std::string(
data.begin(),
data.end());
auto entry_count() const -> size_t
Get number of entries.
auto max_size() const -> size_t
Get maximum table size.
auto clear() -> void
Clear all entries.
std::deque< http_header > entries_
auto set_max_size(size_t size) -> void
Set maximum table size.
auto evict_to_size(size_t target_size) -> void
auto get(size_t index) const -> std::optional< http_header >
Get header by dynamic table index.
auto find(std::string_view name, std::string_view value="") const -> std::optional< size_t >
Find header in dynamic table.
auto insert(std::string_view name, std::string_view value) -> void
Insert header at beginning of table.
auto current_size() const -> size_t
Get current table size.
dynamic_table(size_t max_size=4096)
Construct dynamic table with max size.
auto decode(std::span< const uint8_t > data) -> Result< std::vector< http_header > >
Decode HPACK binary to headers.
auto decode_string(std::span< const uint8_t > &data) -> Result< std::string >
auto set_max_table_size(size_t size) -> void
Set maximum dynamic table size.
auto table_size() const -> size_t
Get current dynamic table size.
auto decode_integer(std::span< const uint8_t > &data, uint8_t prefix_bits) -> Result< uint64_t >
auto get_indexed_header(size_t index) const -> Result< http_header >
hpack_decoder(size_t max_table_size=4096)
Construct decoder with max table size.
auto encode_literal_with_indexing(std::string_view name, std::string_view value) -> std::vector< uint8_t >
auto set_max_table_size(size_t size) -> void
Set maximum dynamic table size.
auto encode(const std::vector< http_header > &headers) -> std::vector< uint8_t >
Encode headers to HPACK binary format.
hpack_encoder(size_t max_table_size=4096)
Construct encoder with max table size.
auto table_size() const -> size_t
Get current dynamic table size.
auto encode_indexed(size_t index) -> std::vector< uint8_t >
auto encode_literal_without_indexing(std::string_view name, std::string_view value) -> std::vector< uint8_t >
auto encode_integer(uint64_t value, uint8_t prefix_bits) -> std::vector< uint8_t >
auto encode_string(std::string_view str, bool huffman=false) -> std::vector< uint8_t >
static constexpr auto size() -> size_t
Get static table size.
static auto get(size_t index) -> std::optional< http_header >
Get static table entry by index.
static auto find(std::string_view name, std::string_view value="") -> size_t
Find index of header in static table.
Huffman coding for HPACK string compression.
auto decode(std::span< const uint8_t > data) -> Result< std::string >
Decode Huffman encoded string.
auto encode(std::string_view input) -> std::vector< uint8_t >
Encode string using Huffman coding.
auto encoded_size(std::string_view input) -> size_t
Get encoded size for string.