alpacki is an HPACK (RFC 7541) implementation for Gleam. It handles header compression for HTTP/2 connections.
gleam add alpacki@2Each side of an HTTP/2 connection maintains its own dynamic table. Headers are encoded into compact header block fragments for transmission, and decoded back on the receiving side.
Encoding from a list of headers:
let table = alpacki.new_dynamic(4096)
let headers = [
alpacki.HeaderField(":method", "GET", alpacki.WithIndexing),
alpacki.HeaderField(":path", "/", alpacki.WithIndexing),
alpacki.HeaderField(":scheme", "https", alpacki.WithIndexing),
]
let #(data, table) =
alpacki.encode_header_block(headers, table, huffman: True)Decoding headers from raw bits:
let table = alpacki.new_dynamic(4096)
let assert Ok(#(headers, table)) = alpacki.decode_header_block(data, table)The Indexing type on each HeaderField controls the wire representation:
WithIndexing adds the entry to the dynamic table for future reference,
WithoutIndexing sends it without storing, and NeverIndexed signals that
the value is sensitive and must never be compressed by intermediaries.
When the remote peer sends a SETTINGS frame that changes
SETTINGS_HEADER_TABLE_SIZE, call resize_dynamic on the encoder's
table. The next encode_header_block call will automatically prepend the
required size update instructions before the header fields.
// Remote peer reduced the table size to 2048 bytes.
let encoder_table = alpacki.resize_dynamic(encoder_table, 2048)
// The next encoded block will start with a size update instruction.
let #(data, encoder_table) =
alpacki.encode_header_block(headers, encoder_table, huffman: True)On the decoder side, expect_table_size_update can optionally be used to enforce the peer sends the size update, decode_header_block processes any size update instructions at the start of a block automatically.
Beyond the high-level API, alpacki exposes the individual HPACK primitives.
If you are building on primitives instead of encode_header_block /
decode_header_block, you are responsible for emitting dynamic table size
updates yourself with encode_table_size_update when the maximum table size
changes.
Integer:
let encoded = alpacki.encode_integer(120, prefix: 5)
let assert Ok(#(120, <<>>)) = alpacki.decode_integer(encoded, prefix: 5)String Literal:
let encoded = alpacki.encode_string_literal(<<"Wibble":utf8>>, huffman: False)
let assert Ok(#(decoded, <<>>)) = alpacki.decode_string_literal(encoded)Huffman:
let encoded = alpacki.encode_huffman(<<"www.example.com":utf8>>)
let assert Ok(decoded) = alpacki.decode_huffman(encoded)Further documentation can be found at https://hexdocs.pm/alpacki.
