alpacki
Types
Errors that can occur when decoding a header block or its components.
pub type DecodeError {
Incomplete
IntegerOverflow
InvalidEncoding
InvalidTableIndex
InvalidHeaderName
InvalidHeaderValue
InvalidHuffmanEncoding
}
Constructors
-
IncompleteThe input ended before a complete value could be decoded.
-
IntegerOverflowAn encoded integer exceeded the maximum supported value.
-
InvalidEncodingThe data contained an unrecognizable bit pattern.
-
InvalidTableIndexA header field referenced a table index that does not exist.
-
InvalidHeaderNameA literal header name contained bytes outside the allowed range.
-
InvalidHeaderValueA header value contained bytes that are not valid UTF-8.
-
InvalidHuffmanEncodingHuffman-encoded data was malformed or had invalid padding.
Dynamic table for HPACK compression. Stores recently used header fields with indices starting at 62. The encoder and decoder each maintain their own table.
pub opaque type DynamicTable
A header field as it flows through the encoder and decoder. When encoding,
the indexing mode controls the wire representation. When decoding, it
preserves the representation chosen by the sender.
pub type HeaderField {
HeaderField(name: String, value: String, indexing: Indexing)
}
Constructors
-
HeaderField(name: String, value: String, indexing: Indexing)
Indexing mode for a header field, controlling how the encoder represents it on the wire and how the decoder preserves the original signal.
See: RFC 7541 Section 6.2
pub type Indexing {
WithIndexing
WithoutIndexing
NeverIndexed
}
Constructors
-
WithIndexingLiteral with incremental indexing (Section 6.2.1). Store in the dynamic table for future reference.
-
WithoutIndexingLiteral without indexing (Section 6.2.2). Do not store. Useful for header fields that change every request.
-
NeverIndexedLiteral never indexed (Section 6.2.3). Do not store, and signal to intermediaries that this value is sensitive and must never be compressed.
Result of searching a table for a header field. The index refers to the combined address space: 1–61 for static entries, 62 and above for dynamic entries.
pub type TableMatch {
FullMatch(index: Int)
NameMatch(index: Int)
NoMatch
}
Constructors
-
FullMatch(index: Int)Both name and value matched an entry at the given index.
-
NameMatch(index: Int)Only the name matched; the value at this index differs.
-
NoMatchNeither name nor value matched any entry.
Values
pub fn add_dynamic(
table: DynamicTable,
name: String,
value: String,
) -> DynamicTable
Adds an entry to the dynamic table at index 62. Evicts oldest entries if the new entry would exceed maximum size. Clears the table without adding if the entry alone exceeds maximum size.
See: RFC 7541 Section 4.4
pub fn clear_dynamic(table: DynamicTable) -> DynamicTable
Removes all entries from the dynamic table while preserving the maximum size setting.
pub fn decode_header_block(
data: BitArray,
dynamic_table: DynamicTable,
) -> Result(#(List(HeaderField), DynamicTable), DecodeError)
Decodes a complete header block fragment into a list of header fields, updating the dynamic table as specified by the encoded instructions.
Any dynamic table size update instructions at the start of the block are processed automatically before header fields are decoded.
See: RFC 7541 Section 6
A header block is a sequence of header field representations, each identified by its first-byte bit pattern:
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 1 | Index (7+) | 6.1 Indexed
+---+---------------------------+
| 0 | 1 | Index (6+) | 6.2.1 With Indexing
+---+---+-----------------------+
| 0 | 0 | 0 | 0 | Index (4+) | 6.2.2 Without Indexing
+---+---+---+---+---------------+
| 0 | 0 | 0 | 1 | Index (4+) | 6.2.3 Never Indexed
+---+---+---+---+---------------+
| 0 | 0 | 1 | Max size (5+) | 6.3 Size Update
+---+---+---+-------------------+
Indexed representations reference an existing table entry. Literal
representations carry the value on the wire, optionally referencing a
table entry for the name. The decoder preserves each header field’s
indexing mode in the returned HeaderField.
pub fn decode_huffman(
data: BitArray,
) -> Result(BitArray, DecodeError)
Decodes Huffman-coded data. Accepts Huffman-encoded bits and returns the decoded byte sequence. The input must be padded to an octet boundary with the most significant bits of the EOS symbol.
See: RFC 7541 Appendix B
pub fn decode_integer(
data: BitArray,
prefix prefix: Int,
) -> Result(#(Int, BitArray), DecodeError)
Decodes an integer used to represent name indices, string lengths, or integer values. Accepts a BitArray starting at the byte containing the prefix and the number of prefix bits. Returns the decoded integer with the remaining BitArray, or a decode error.
The prefix size must be between 1 and 8 bits. Other values cause a panic.
See: RFC 7541 Section 5.1
An integer is represented in two parts: a prefix that fills the current octet and an optional list of octets that are used if the integer value does not fit within the prefix.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| ? | ? | ? | Value | N = 5, value < 2^N-1
+---+---+---+-------------------+
If the value is too large for the N-bit prefix, all prefix bits are set to 1 and the remainder is encoded using continuation bytes in base-128.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| ? | ? | ? | 1 1 1 1 1 | N = 5, prefix exhausted
+---+---+---+-------------------+
| 1 | Value-(2^N-1) LSB |
+---+---------------------------+
...
+---+---------------------------+
| 0 | Value-(2^N-1) MSB |
+---+---------------------------+
pub fn decode_string_literal(
data: BitArray,
) -> Result(#(BitArray, BitArray), DecodeError)
Decodes a string literal representation used for header field names and values. Returns the decoded octets and the remaining BitArray, or a decode error.
See: RFC 7541 Section 5.2
A string literal is an opaque sequence of octets, encoded either directly or using Huffman coding. The representation starts with a one-bit flag (H) indicating Huffman encoding, followed by the string length as a 7-bit prefixed integer, then the encoded data.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| H | String Length (7+) |
+---+---------------------------+
| String Data (Length octets) |
+-------------------------------+
pub fn dynamic_length(table: DynamicTable) -> Int
Returns the number of entries in the dynamic table. (RFC 7541 Section 2.3.2)
pub fn dynamic_max_size(table: DynamicTable) -> Int
Returns the maximum size of the dynamic table in bytes. (RFC 7541 Section 4.2)
pub fn dynamic_size(table: DynamicTable) -> Int
Returns the current size of the dynamic table in bytes, calculated as the sum of each entry’s name length, value length, and 32-byte overhead. (RFC 7541 Section 4.1)
pub fn encode_header_block(
headers: List(HeaderField),
dynamic_table: DynamicTable,
huffman huffman: Bool,
) -> #(bytes_tree.BytesTree, DynamicTable)
Encodes a list of header fields into a header block fragment, updating the
dynamic table as entries are added. Returns the encoded block as a
BytesTree and the updated dynamic table. When huffman is True, all
name and value strings use Huffman coding.
If resize_dynamic was called since the last encoding, the required
dynamic table size update instructions are prepended automatically.
See: RFC 7541 Section 6
The encoder looks up each header field in the static and dynamic tables and selects the most compact representation. A full match always uses the indexed representation regardless of the indexing mode, as the entry is already visible to the decoder as referencing it leaks no new information.
When only the name matches or nothing matches, the indexing mode selects
the literal representation: WithIndexing uses incremental indexing and
adds the entry to the dynamic table, WithoutIndexing sends the value
without storing it, and NeverIndexed signals that intermediaries must
never compress this value.
pub fn encode_huffman(data: BitArray) -> BitArray
Encodes data using Huffman coding. Accepts raw bytes and returns Huffman-encoded bits padded to an octet boundary with the most significant bits of the EOS symbol.
See: RFC 7541 Appendix B
pub fn encode_integer(
integer: Int,
prefix prefix: Int,
) -> BitArray
Encodes an integer used to represent name indices, string lengths, or integer values. Accepts an integer and the number of prefix bits (N). Returns the encoded BitArray.
The prefix size must be between 1 and 8 bits. Other values cause a panic.
See: RFC 7541 Section 5.1
An integer is represented in two parts: a prefix that fills the current octet and an optional list of octets that are used if the integer value does not fit within the prefix.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| ? | ? | ? | Value | N = 5, value < 2^N-1
+---+---+---+-------------------+
If the value is too large for the N-bit prefix, all prefix bits are set to 1 and the remainder is encoded using continuation bytes in base-128.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| ? | ? | ? | 1 1 1 1 1 | N = 5, prefix exhausted
+---+---+---+-------------------+
| 1 | Value-(2^N-1) LSB |
+---+---------------------------+
...
+---+---------------------------+
| 0 | Value-(2^N-1) MSB |
+---+---------------------------+
pub fn encode_string_literal(
data: BitArray,
huffman huffman: Bool,
) -> BitArray
Encodes a string literal representation for header field names and values. Accepts the raw octets and a flag indicating whether to use Huffman coding. Returns the encoded BitArray.
See: RFC 7541 Section 5.2
A string literal is an opaque sequence of octets, encoded either directly or using Huffman coding. The representation starts with a one-bit flag (H) indicating Huffman encoding, followed by the string length as a 7-bit prefixed integer, then the encoded data.
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| H | String Length (7+) |
+---+---------------------------+
| String Data (Length octets) |
+-------------------------------+
pub fn encode_table_size_update(new_size: Int) -> BitArray
Encodes a dynamic table size update instruction, signaling the decoder about a change in the maximum dynamic table size.
See: RFC 7541 Section 6.3
0 1 2 3 4 5 6 7
+---+---+---+---+---+---+---+---+
| 0 | 0 | 1 | Max size (5+) |
+---+---+---+-------------------+
pub fn lookup(
dynamic_table: DynamicTable,
index: Int,
) -> Result(#(String, String), Nil)
Looks up a header field by index across the static and dynamic tables. Indices 1 to 61 address the static table; 62 and above address the dynamic table starting from the most recently added entry. Returns the name-value pair or an error if the index is out of range.
pub fn lookup_dynamic(
table: DynamicTable,
index: Int,
) -> Result(#(String, String), Nil)
Looks up a header field by index in the dynamic table. Indices start at 62 for the most recently added entry. Returns the name-value pair or an error if the index is out of range.
pub fn lookup_static(
index: Int,
) -> Result(#(String, String), Nil)
Looks up a header field by index 1 to 61 in the static table. Returns the name-value pair or an error if the index is out of range.
See: RFC 7541 Appendix A
pub fn match(
dynamic_table: DynamicTable,
name: String,
value: String,
) -> TableMatch
Searches the static and dynamic tables for the best match for a header field. Checks the static table first, then the dynamic table, and returns the most useful match found.
A full match in the static table wins immediately. When the static table has only a name match, the dynamic table is still checked for a full match. A static name match is preferred over a dynamic name match. When the static table has no match, the dynamic table result is returned.
pub fn match_dynamic(
table: DynamicTable,
name: String,
value: String,
) -> TableMatch
Searches the dynamic table for an entry matching the given name and value.
Returns FullMatch with index if both match, NameMatch with index if
only the name matches, or NoMatch.
pub fn match_static(name: String, value: String) -> TableMatch
Searches the static table for an entry matching the given name and value.
Returns FullMatch with index if both match, NameMatch with index if
only the name matches, or NoMatch.
See: RFC 7541 Appendix A
pub fn new_dynamic(max_size: Int) -> DynamicTable
Creates an empty dynamic table with the specified maximum size in bytes.
The protocol determines the initial maximum size; HTTP/2 defaults to
4096 bytes via SETTINGS_HEADER_TABLE_SIZE.
See: RFC 7541 Section 4.2
pub fn resize_dynamic(
table: DynamicTable,
new_max_size: Int,
) -> DynamicTable
Resizes the dynamic table, typically in response to a SETTINGS frame.
Evicts oldest entries if the current size exceeds the new maximum. Records
the pending resize so that encode_header_block automatically emits the
required size update instructions at the start of the next header block.
See: RFC 7541 Section 4.2