class HPack::Decoder

Overview

To decode headers, use a HPack::Decoder instance. By default, a decoder is created with a 4k (4096 bytes) table size. That table size can be changed in the constructor.

# To create a default Decoder:
decoder = HPack::Decoder.new

# To create a decoder with a larger table size:
decoder = HPack::Decoder.new(8192)

# To create a decoder that refuses to materialize any single literal
# larger than 64 KiB:
decoder = HPack::Decoder.new(max_decoded_string_size: 64 * 1024)

# To decode headers:
headers = decoder.decode(bytes)

# To decode headers into an existing `HTTP::Headers` instance:
headers = decoder.decode(bytes, HTTP::Headers.new)

# To decode with a decompressed field-section budget:
result = decoder.decode_each(bytes, max_field_section_size: 64 * 1024) do |field|
  # Validate or retain this ordered field.
end
result.limit_exceeded # => false

Defined in:

decoder.cr

Constructors

Instance Method Summary

Constructor Detail

def self.new(max_table_size = 4096, max_decoded_string_size : Int | Nil = nil) #

[View source]

Instance Method Detail

def decode(bytes, headers = HTTP::Headers.new) #

Decodes bytes and adds each field to headers.

Output is unlimited; use #decode_each with max_field_section_size to bound the decompressed size of untrusted field blocks.


[View source]
def decode_each(bytes, max_field_section_size : Int | Nil = nil, & : DecodedHeader -> ) : DecodeResult #

Decodes bytes, yielding one DecodedHeader per field in wire order.

Yielded names and values are ordinary immutable strings and remain valid after the callback; no header collection is retained internally.

max_field_section_size bounds the decompressed output using the HTTP/2 field-section size rule (name.bytesize + value.bytesize + 32 per field). A total exactly equal to the limit is accepted. The field that crosses the limit is not yielded and neither is any later field, but the rest of the block is still parsed and dynamic-table insertions and size updates are still applied, so the compression context stays synchronized with the peer. nil means unlimited.

If the callback raises, the first exception is saved, no later field is yielded, and the remainder of the block is still decoded. A malformed remainder raises Error and a resource cap raises ResourceLimitError; otherwise the saved callback exception is re-raised after the block has been fully decompressed, leaving the decoder reusable.

Returns a DecodeResult carrying the final decoded size and whether the limit was crossed. Callers should not publish the field section to application code until limit_exceeded is known.

result = decoder.decode_each(
  encoded,
  max_field_section_size: 64 * 1024,
) do |field|
  # Validate or retain this ordered field.
end

[View source]
def decode_with_metadata(bytes, headers = HTTP::Headers.new) #

Decodes headers and retains their ordered indexing representations.

The returned headers value is the same value returned by #decode. fields retains one entry per decoded field, including Indexing::NEVER markers that intermediaries need when forwarding fields.


[View source]
def indexed(index) #

[View source]
def integer(n) #

[View source]
def literal_indexed #

[View source]
def literal_never_indexed #

[View source]
def literal_with_incremental_indexing #

[View source]
def literal_without_indexing #

[View source]
def max_decoded_string_size : Int32 | Nil #

The hard cap applied to every decoded literal name and value, or nil when literals are unbounded.


[View source]
def max_table_size : Int32 #

[View source]
def max_table_size=(size : Int) #

Changes the protocol limit for dynamic-table size updates.

Reducing this limit below the peer's current table capacity requires a conforming update at the beginning of the next decoded field block. The table itself is resized only when that instruction is received.


[View source]
def string #

[View source]
def table : DynamicTable #

[View source]