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 402 of file hpack.cpp.

403 : table_(max_table_size)
404 {
405 }

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 407 of file hpack.cpp.

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

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 536 of file hpack.cpp.

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

585 {
586 if (data.empty())
587 {
588 return error_info(103, "Insufficient data for string", "hpack");
589 }
590
591 bool huffman = (data[0] & 0x80) != 0;
592
593 auto length_result = decode_integer(data, 7);
594 if (length_result.is_err())
595 {
596 return length_result.error();
597 }
598
599 size_t length = length_result.value();
600
601 if (data.size() < length)
602 {
603 return error_info(104, "Insufficient data for string value", "hpack");
604 }
605
606 std::string result;
607 if (huffman)
608 {
609 // Huffman decoding not implemented yet - just return raw for now
610 result.assign(data.begin(), data.begin() + length);
611 }
612 else
613 {
614 result.assign(data.begin(), data.begin() + length);
615 }
616
617 data = data.subspan(length);
618 return result;
619 }
Huffman coding for HPACK string compression.

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

◆ get_indexed_header()

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

Definition at line 621 of file hpack.cpp.

623 {
624 if (index == 0)
625 {
626 return error_info(105, "Invalid index 0", "hpack");
627 }
628
629 // Check static table
630 if (index <= static_table::size())
631 {
632 auto header = static_table::get(index);
633 if (header.has_value())
634 {
635 return std::move(header.value());
636 }
637 return error_info(106, "Invalid static table index", "hpack");
638 }
639
640 // Check dynamic table
641 size_t dynamic_index = index - static_table::size() - 1;
642 auto header = table_.get(dynamic_index);
643 if (header.has_value())
644 {
645 return std::move(header.value());
646 }
647
648 return error_info(107, "Invalid dynamic table index", "hpack");
649 }
auto get(size_t index) const -> std::optional< http_header >
Get header by dynamic table index.
Definition hpack.cpp:128
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:83

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 526 of file hpack.cpp.

527 {
528 table_.set_max_size(size);
529 }
auto set_max_size(size_t size) -> void
Set maximum table size.
Definition hpack.cpp:154

◆ 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 531 of file hpack.cpp.

532 {
533 return table_.current_size();
534 }
auto current_size() const -> size_t
Get current table size.
Definition hpack.cpp:160

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: