Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
kcenon::network::protocols::http2::hpack_decoder Class Reference

HPACK header decoder (RFC 7541) More...

#include <hpack.h>

Collaboration diagram for kcenon::network::protocols::http2::hpack_decoder:
Collaboration graph

Public Member Functions

 hpack_decoder (size_t max_table_size=4096)
 Construct decoder with max table size.
 
auto decode (std::span< const uint8_t > data) -> Result< std::vector< http_header > >
 Decode HPACK binary to headers.
 
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.
 

Private Member Functions

auto decode_integer (std::span< const uint8_t > &data, uint8_t prefix_bits) -> Result< uint64_t >
 
auto decode_string (std::span< const uint8_t > &data) -> Result< std::string >
 
auto get_indexed_header (size_t index) const -> Result< http_header >
 

Private Attributes

dynamic_table table_
 

Detailed Description

HPACK header decoder (RFC 7541)

Decodes HPACK compressed headers with dynamic table.

Definition at line 208 of file hpack.h.

Constructor & Destructor Documentation

◆ hpack_decoder()

kcenon::network::protocols::http2::hpack_decoder::hpack_decoder ( size_t max_table_size = 4096)
explicit

Construct decoder with max table size.

Parameters
max_table_sizeMaximum dynamic table size (default 4096)

Definition at line 406 of file hpack.cpp.

407 : table_(max_table_size)
408 {
409 }

Member Function Documentation

◆ decode()

auto kcenon::network::protocols::http2::hpack_decoder::decode ( std::span< const uint8_t > data) -> Result<std::vector<http_header>>

Decode HPACK binary to headers.

Parameters
dataEncoded HPACK data
Returns
Decoded headers or error

Definition at line 411 of file hpack.cpp.

413 {
414 std::vector<http_header> headers;
415 auto remaining = data;
416
417 while (!remaining.empty())
418 {
419 uint8_t first_byte = remaining[0];
420
421 if (first_byte & 0x80)
422 {
423 // Indexed header field representation
424 auto index_result = decode_integer(remaining, 7);
425 if (index_result.is_err())
426 {
427 return index_result.error();
428 }
429 size_t index = index_result.value();
430
431 auto header_result = get_indexed_header(index);
432 if (header_result.is_err())
433 {
434 return header_result.error();
435 }
436
437 headers.push_back(header_result.value());
438 }
439 else if (first_byte & 0x40)
440 {
441 // Literal with incremental indexing
442 auto name_index_result = decode_integer(remaining, 6);
443 if (name_index_result.is_err())
444 {
445 return name_index_result.error();
446 }
447 size_t name_index = name_index_result.value();
448
449 std::string name;
450 if (name_index == 0)
451 {
452 // New name
453 auto name_result = decode_string(remaining);
454 if (name_result.is_err())
455 {
456 return name_result.error();
457 }
458 name = name_result.value();
459 }
460 else
461 {
462 // Indexed name
463 auto header_result = get_indexed_header(name_index);
464 if (header_result.is_err())
465 {
466 return header_result.error();
467 }
468 name = header_result.value().name;
469 }
470
471 // Decode value
472 auto value_result = decode_string(remaining);
473 if (value_result.is_err())
474 {
475 return value_result.error();
476 }
477 std::string value = value_result.value();
478
479 headers.emplace_back(name, value);
480 table_.insert(name, value);
481 }
482 else
483 {
484 // Literal without indexing or never indexed
485 uint8_t prefix_bits = (first_byte & 0x10) ? 4 : 4;
486
487 auto name_index_result = decode_integer(remaining, prefix_bits);
488 if (name_index_result.is_err())
489 {
490 return name_index_result.error();
491 }
492 size_t name_index = name_index_result.value();
493
494 std::string name;
495 if (name_index == 0)
496 {
497 // New name
498 auto name_result = decode_string(remaining);
499 if (name_result.is_err())
500 {
501 return name_result.error();
502 }
503 name = name_result.value();
504 }
505 else
506 {
507 // Indexed name
508 auto header_result = get_indexed_header(name_index);
509 if (header_result.is_err())
510 {
511 return header_result.error();
512 }
513 name = header_result.value().name;
514 }
515
516 // Decode value
517 auto value_result = decode_string(remaining);
518 if (value_result.is_err())
519 {
520 return value_result.error();
521 }
522
523 headers.emplace_back(name, value_result.value());
524 }
525 }
526
527 return headers;
528 }
auto insert(std::string_view name, std::string_view value) -> void
Insert header at beginning of table.
Definition hpack.cpp:116
auto decode_string(std::span< const uint8_t > &data) -> Result< std::string >
Definition hpack.cpp:587
auto decode_integer(std::span< const uint8_t > &data, uint8_t prefix_bits) -> Result< uint64_t >
Definition hpack.cpp:540
auto get_indexed_header(size_t index) const -> Result< http_header >
Definition hpack.cpp:629

References kcenon::network::protocols::http2::data, and kcenon::network::protocols::http2::headers.

◆ decode_integer()

auto kcenon::network::protocols::http2::hpack_decoder::decode_integer ( std::span< const uint8_t > & data,
uint8_t prefix_bits ) -> Result<uint64_t>
private

Definition at line 540 of file hpack.cpp.

543 {
544 if (data.empty())
545 {
546 return error_info(100, "Insufficient data for integer", "hpack");
547 }
548
549 uint8_t prefix_mask = (1 << prefix_bits) - 1;
550 uint64_t value = data[0] & prefix_mask;
551 data = data.subspan(1);
552
553 if (value < prefix_mask)
554 {
555 return value;
556 }
557
558 // Multi-byte integer
559 uint64_t m = 0;
560 do
561 {
562 if (data.empty())
563 {
564 return error_info(101, "Incomplete integer encoding", "hpack");
565 }
566
567 uint8_t byte = data[0];
568 data = data.subspan(1);
569
570 const uint64_t payload = byte & 0x7F;
571 if (m >= 64 || payload > ((std::numeric_limits<uint64_t>::max() - value) >> m))
572 {
573 return error_info(102, "Integer overflow", "hpack");
574 }
575 value += payload << m;
576
577 if ((byte & 0x80) == 0)
578 {
579 break;
580 }
581 m += 7;
582 } while (true);
583
584 return value;
585 }
simple_error error_info

References kcenon::network::protocols::http2::data.

◆ decode_string()

auto kcenon::network::protocols::http2::hpack_decoder::decode_string ( std::span< const uint8_t > & data) -> Result<std::string>
private

Definition at line 587 of file hpack.cpp.

589 {
590 if (data.empty())
591 {
592 return error_info(103, "Insufficient data for string", "hpack");
593 }
594
595 bool huffman = (data[0] & 0x80) != 0;
596
597 auto length_result = decode_integer(data, 7);
598 if (length_result.is_err())
599 {
600 return length_result.error();
601 }
602
603 size_t length = length_result.value();
604
605 if (data.size() < length)
606 {
607 return error_info(104, "Insufficient data for string value", "hpack");
608 }
609
610 std::string result;
611 if (huffman)
612 {
613 auto decoded = huffman::decode(data.subspan(0, length));
614 if (decoded.is_err())
615 {
616 return decoded.error();
617 }
618 result = std::move(decoded.value());
619 }
620 else
621 {
622 result.assign(data.begin(), data.begin() + length);
623 }
624
625 data = data.subspan(length);
626 return result;
627 }
Huffman coding for HPACK string compression.
auto decode(std::span< const uint8_t > data) -> Result< std::string >
Decode Huffman encoded string.
Definition hpack.cpp:808

References kcenon::network::protocols::http2::data, and kcenon::network::protocols::http2::huffman::decode().

Here is the call graph for this function:

◆ get_indexed_header()

auto kcenon::network::protocols::http2::hpack_decoder::get_indexed_header ( size_t index) const -> Result<http_header>
private

Definition at line 629 of file hpack.cpp.

631 {
632 if (index == 0)
633 {
634 return error_info(105, "Invalid index 0", "hpack");
635 }
636
637 // Check static table
638 if (index <= static_table::size())
639 {
640 auto header = static_table::get(index);
641 if (header.has_value())
642 {
643 return std::move(header.value());
644 }
645 return error_info(106, "Invalid static table index", "hpack");
646 }
647
648 // Check dynamic table
649 size_t dynamic_index = index - static_table::size() - 1;
650 auto header = table_.get(dynamic_index);
651 if (header.has_value())
652 {
653 return std::move(header.value());
654 }
655
656 return error_info(107, "Invalid dynamic table index", "hpack");
657 }
auto get(size_t index) const -> std::optional< http_header >
Get header by dynamic table index.
Definition hpack.cpp:129
static constexpr auto size() -> size_t
Get static table size.
Definition hpack.h:72
static auto get(size_t index) -> std::optional< http_header >
Get static table entry by index.
Definition hpack.cpp:84

References kcenon::network::protocols::http2::static_table::get(), and kcenon::network::protocols::http2::static_table::size().

Here is the call graph for this function:

◆ set_max_table_size()

auto kcenon::network::protocols::http2::hpack_decoder::set_max_table_size ( size_t size) -> void

Set maximum dynamic table size.

Parameters
sizeNew maximum size

Definition at line 530 of file hpack.cpp.

531 {
532 table_.set_max_size(size);
533 }
auto set_max_size(size_t size) -> void
Set maximum table size.
Definition hpack.cpp:155

◆ table_size()

auto kcenon::network::protocols::http2::hpack_decoder::table_size ( ) const -> size_t

Get current dynamic table size.

Returns
Current size in bytes

Definition at line 535 of file hpack.cpp.

536 {
537 return table_.current_size();
538 }
auto current_size() const -> size_t
Get current table size.
Definition hpack.cpp:161

References kcenon::network::protocols::http2::dynamic_table::current_size(), and table_.

Here is the call graph for this function:

Member Data Documentation

◆ table_

dynamic_table kcenon::network::protocols::http2::hpack_decoder::table_
private

Definition at line 242 of file hpack.h.

Referenced by table_size().


The documentation for this class was generated from the following files: