Sign in

    moonbitstack/moonhttp/hpack does not have a README file

    Refused

    pub(all) suberror Refused {
    Malformed(String)
    Index(got~ : Int)
    Exceeded(limit~ : Int, got~ : Int)
    } derive(Eq,
    Debug
    )

    Why a header block was refused (RFC 7541 §6).

    Malformed and Index are connection errors in HTTP/2 (RFC 9113 §4.3): the two ends' dynamic tables have gone out of step and nothing after this point can be read. Exceeded is not. The block was decoded to its end, so the table is in step, and only this one field section is refused for being larger than the caller allows.
    impl Show for Refused

    Refused::equal

    fn Refused::equal(Refused, Refused) -> Bool

    Refused::not_equal

    fn Refused::not_equal(x : Refused, y : Refused) -> Bool

    Refused::output

    fn Refused::output(self : Refused, logger : &Logger) -> Unit

    Refused::to_repr

    Refused::to_string

    fn Refused::to_string(self : Refused) -> String

    Decoder

    pub(all) struct Decoder {
    table : Table
    limit : Int
    }

    A stateful HPACK decoder: it owns a dynamic table that persists across the header blocks of a connection. limit is the peer-agreed hard cap (SETTINGS_HEADER_TABLE_SIZE) a size update may not exceed.

    Decoder::decode

    fn Decoder::decode(self : Decoder, block : BytesView, limit? : Int) -> Array[
    Header
    ] raise Refused

    Decode one complete header block into its header list (RFC 7541 §6), mutating the dynamic table for incrementally indexed fields and size updates.

    limit bounds the list by RFC 7541 §4.1 size, each field's octets plus 32, which is what SETTINGS_MAX_HEADER_LIST_SIZE counts. Past it the block is still decoded to its end, so the dynamic table stays in step with the encoder, but no more fields are kept, and then Exceeded is raised. A block of a few octets that names large table entries over and over would otherwise decode to as much memory as the peer liked.

    Decoder::new

    fn Decoder::new(limit? : Int) -> Decoder

    A new decoder whose dynamic table is bounded by limit octets (also the hard cap enforced on dynamic table size updates).

    Encoder

    pub(all) struct Encoder {
    table : Table
    huffman : Bool
    }

    A stateful HPACK encoder: it owns a dynamic table mirroring the decoder's, and prefers indexed representations. huffman selects Huffman string literals when they are shorter.

    Encoder::encode

    Encode a header list into a header block (RFC 7541 §6), using indexed fields where possible and literal-with-incremental-indexing otherwise (mutating the dynamic table to mirror what the peer decoder will build). The output decodes back to the same header list via Decoder.

    Encoder::new

    fn Encoder::new(limit? : Int, huffman? : Bool) -> Encoder

    A new encoder bounded by limit octets; huffman (default true) enables the shorter-of-two string-literal heuristic.

    Table

    pub(all) struct Table {
    entries : Array[(Bytes, Bytes)]
    size : Int
    limit : Int
    }

    The HPACK dynamic table: a FIFO of recently seen (name, value) entries, newest first (entries[0]), bounded by limit octets where each entry costs name.len + value.len + 32 (RFC 7541 §4.1). Adding evicts the oldest entries until the newcomer fits; an entry larger than limit empties the table and is not stored (§4.4).

    Table::add

    fn Table::add(self : Table, name : Bytes, value : Bytes) -> Unit

    Insert (name, value) at the front, evicting oldest entries to make room. If the entry alone exceeds limit the table ends up empty (RFC 7541 §4.4).

    Table::count

    fn Table::count(self : Table) -> Int

    The number of entries currently in the dynamic table.

    Table::get

    fn Table::get(self : Table, index : Int) ->
    Header
    ?

    The field an HPACK index names, across the static and dynamic tables together (RFC 7541 §2.3.3): one through sixty-one are the static table, and everything above is this table, newest first. None when the index names nothing.

    Table::limit

    fn Table::limit(self : Table) -> Int

    The ceiling this table evicts to keep under, in octets.

    Table::new

    fn Table::new(limit? : Int) -> Table

    A new empty dynamic table bounded by limit octets (default 4096, the HTTP/2 initial SETTINGS_HEADER_TABLE_SIZE).

    Table::resize

    fn Table::resize(self : Table, limit : Int) -> Unit

    Resize the table (a dynamic table size update, RFC 7541 §4.2), evicting to fit.

    Table::size

    fn Table::size(self : Table) -> Int

    The current total size of the dynamic table in octets (§4.1 accounting).

    entry

    Look up an HPACK static-table entry by its 1-based RFC index (1..=61), returning (name, value) or None when the index is out of range.

    limit

    let limit : Int

    How many octets a dynamic table holds by default.

    Four kibibytes is the value HTTP/2 gives SETTINGS_HEADER_TABLE_SIZE before either end has said otherwise (RFC 9113 §6.5.2), so it is what both tables start at.

    read_literal

    fn read_literal(data : BytesView, offset : Int) -> (Bytes, Int) raise Refused

    Decode an HPACK string literal from data at offset, returning (octets,bytes_consumed). The length is read as a 7-bit-prefix integer (the H bit is masked off); this is the inverse of string for H = 0. Huffman decoding is not applied here, so ask @prefix.flagged first if the literal may be coded.

    read_string

    fn read_string(data : BytesView, offset : Int) -> (Bytes, Int) raise Refused

    Read an HPACK string literal at offset, resolving Huffman coding when the H bit is set, returning (octets, bytes_consumed). Unlike read_literal, this applies Huffman decoding. Raises on bad Huffman.

    size_update

    fn size_update(limit : Int) -> Bytes

    Encode a dynamic table size update (RFC 7541 §6.3): 001 prefix with the new maximum size as a 5-bit-prefix integer.

    static_table

    The static table as (name, value) octet pairs, in RFC index order (index 1 at position 0). Derived once from static_table.

    string

    fn string(octets : BytesView, huffman? : Bool) -> Bytes

    A string literal (RFC 7541 §5.2): the length as a seven-bit-prefix integer, then the octets, with the H bit saying whether they are Huffman-coded.

    huffman takes the shorter of the two forms, which is what an encoder does; false writes the octets as they are, which is what a test with a published block needs.

    A tie goes to the coded form, which is what RFC 7541's own examples do: it costs nothing and leaves less of the value legible to anything reading the connection.

    Source Files