HPACK
HPACK is the HTTP 2 header compression scheme. This is a specialized algorithm and does not allow for arbitrary compression schemes.
HPACK is implemented in the module HTTP2.HPack.
Header compression and decompression is implemented by compressing or decompressing data as it is first inserted to or read from an IO stream. As the specification is rigid and does not allow for any sort of custom data or metadata, the implementation is not particularly flexible.
API
HTTP2.HPack — ModuleHTTP2.HPack.AbstractDecoder — TypeAbstractDecoderAbstract type for all HPACK decoding data structures.
HTTP2.HPack.AbstractEncoder — TypeAbstractEncoderAbstract type for all HPACK encoding data structures.
HTTP2.HPack.BitWindow — TypeBitWindowData structure representing a range of bits in a single byte. The left boundary β.j₁ gives the first bit (according to 1-based indexing) and the right boundary w.j₂ gives the last. For example, the least significant 4 bits of the byte 0xff can be represented with BitWindow(0xff, 4, 8).
Relevant Methods
UInt8(β::BitWindow): Convert the bit window to aUInt8, that is, it removes bits outside of the specified range and moves them to the least significant end of the byte.pushbits(o::UInt, β::BitWindow): Append the bits of the bit window to the integero, moving exiting bits to more significant digits.
HTTP2.HPack.BytesWindow — TypeBytesWindowData structure representing a range of bits in an array of bytes. The left boundary w.j₁ gives the first bit (according to 1-based indexing) and the right boundary w.j₂ gives the last. For example, the entirety of the 1-byte array v = [0xff] can be described with BytesWindow(v, 1, 8).
This struct is used for decoding HPACK Huffman code.
Relevant Methods
UInt(w::BytesWindow): Converts the entire window into a singleUIntobject. The length of the window must not exceed8sizeof(UInt)or bits will be lost.extend(w::BytesWindow): Create a newBytesWindowwith the latter index incremented by1.
HTTP2.HPack.DecodeTable — TypeDecodeTableData structure containing an HPACK decoding table. This includes the entries from the static table in the specification as well as dynamic entries added when writing
DecodeTable is thread safe, retrieving and setting entries are atomic operations.
Constructors
DecodeTable(;max_size=typemax(Int32))Arguments
max_size: The maximum table size according to the definition given in the specification.
Indexing
Header fields are retrieved using their index in the table, for example
dt = DecodeTable()
dt[1] # returns ":authority"=>""HTTP2.HPack.Decoder — TypeDecoderData structure for reading compressed HPACK headers.
Constructors
Decoder(;max_table_size=typemax(Int32))Arguments
max_table_size: The maximum dynamic table size according to the definition given in the specification.
Relevant Methods
read(io, d, n): Read at mostnbytes from the streamiousing the decoderd.
WARNING: the byte limit n is not a "hard" limit in that it is not checked on every byte read. Instead, it merely guarantees that no new header fields will be read past the nth byte.
HTTP2.HPack.EncodeTable — TypeEncodeTableData structure containing an HPACK encoding table. This includes the entries from the static table in the specification as well as dynamic entries added when writing.
EncodeTable is thread safe, retrieving and setting entries are atomic operations.
Constructors
EncodeTable(;max_size=typemax(Int32))Arguments
max_size: The maximum table size according to the definition given in the specification.
Indexing
EncodeTable objects can be indexed with either a header key or a header field. The table index is returned. For example:
et = EncodeTable()
et[":method"=>"POST"] # returns 3
et[":method"] # returns 2, the index of the first table entry with the `":method"` key.
get(et, "bogus", missing) # can use get for returning defaults as with dictsHTTP2.HPack.Encoder — TypeEncoder{ℰ<:StringEncoder}Data structure for writing compressed HPACK headers.
Constructors
Encoder(; never_index=Set{String}(), max_table_size=typemax(Int32))Arguments
never_index: A set of header keys as strings which should never be indexed in the table in memory.max_table_size: The maximum dynamic table size. The size definition is somewhat bizarre, see here for how it is defined.
Relevant Methods
write(io, e, kv): Writes the header field or fieldskvto the streamiousing encodere.
HTTP2.HPack.HuffmanDecoder — TypeHuffmanDecoder()Data structure for decoding HPACK Huffman encoded strings. By default, this uses the static Huffman code given in the HPACK specification.
HuffmanDecoder()[l, c] gets the value of code word c of length l.
Strings can be read with readstring(io, HuffmanDecoder()).
HTTP2.HPack.HuffmanEncoder — TypeHuffmanEncoder()Encodes strings according to a static Huffman code. By default, this uses the Huffman code found in the HPACK specification.
HTTP2.HPack.IdentityStringDecoder — TypeIdentityStringDecoder()Singleton data structure used for trivially decoding strings in HPACK headers. This is simply used for moving bytes to Julia String objects, no decompression nor any other type of transformation is applied.
HTTP2.HPack.IdentityStringEncoder — TypeIdentityStringEncoder()Singleton data structure used for trivially encoding strings in HPACK headers. Strings encoded with this encoder appear exactly as they do in memory and do not undergo any compression or any other type of transformation.
HTTP2.HPack.StringDecoder — TypeStringDecoderAbstract type for decoding strings in HPAK.
HTTP2.HPack.StringEncoder — TypeStringEncoderAbstract type for encoding strings in HPACK.
HTTP2.HPack.Transcoder — TypeTranscoder{ℰ<:StringEncoder}Data structure for reading and writing of HPACK headers. This is a simple convenience wrapper around HPack.Encoder and HPack.Decoder.
Base.write — Methodwrite(io::IO, h::HuffmanEncoder, s)Write the string s to io using the Huffman encoding of h. This is for encoding strings in HPACK headers, and can be used directly, that is, it writes the encoding length integer first, with the leading bit set to 1 (this signals to HPACK implementations that the string is Huffman encoded).
HTTP2.HPack.decode — Methoddecode(d::Union{Decoder,Transcoder}, data::AbstractVector{UInt8})Decode HPACK data from an array of bytes.
HTTP2.HPack.encode — Methodencode(e::Union{Encoder,Transcoder}, ϕ; literal_write=literal)Encode header fields ϕ (either a Pair{String,String} or iterator thereof) using method literal_write for writing literals returning a Vector{UInt8} of HPACK encoded data.
HTTP2.HPack.entry! — Methodentry!(et::EncodeTable, kv::AbstractHeaderField)Insert the header field kv into the table. As per the specification, it is always added as the first entry of the dynamic table, evicting the last entries as needed to satisfy the maximum size constraint.
HTTP2.HPack.entrysize — Methodentrysize(kv::HeaderField)The "size" of a header entry according to the HPACK specification. This is defined as the sum of the size of the strings plus, for some reason, 32, don't ask me why.
HTTP2.HPack.evict! — Functionevict!(et::EncodeTable, n=1)Evict n entries from the HPACK encoding table et.
HTTP2.HPack.huffmanlookuptree — Methodhuffmanlookuptree(v, ℓ)Given huffman code v and word length ℓ, generate a nested dictionary allowing for efficient lookups of huffman words.
For the outer dict, the keys are the word lengths and the values are the inner dicts. The inner dicts have the words as keys with indices as values.
This is used to generate HPack.HUFFMAN_LOOKUP_TREE and under normal circumstances is never called at run time.
HTTP2.HPack.index — MethodindexDecompress a header field by referring to an indexed table entry.
HTTP2.HPack.literal — MethodliteralDecompress a literal header field, possibly by referring to the key as an indexed table entry, but with the value given literally. Results in adding the header field as an entry to the dynamic table.
HTTP2.HPack.literalneverindex — MethodliteralneverindexDecompress a literal header field, possibly by referring to the key as an indexed table entry, but forbidding the value from ever being stored in the dynamic table.
HTTP2.HPack.literalnoindex — MethodliteralnoindexDecompress a literal header field, possibly by referring to the key as an indexed table entry, but without creating any new table entries.
HTTP2.HPack.read_integer — Methodread_integer(io, b, p)Read an integer from the stream. The first byte b must be provided, along with the prefix length p.
Returns integer, number of bytes read.
HTTP2.HPack.readentry — Methodreadentry(io, d::Decoder)Read a single entry from the stream returning the entry and the number of bytes read.
HTTP2.HPack.readnextword — Methodreadnextword(v::AbstractVector{UInt8}, j::Int, d::HuffmanDecoder)Attempt to read the next word starting at bit j in a Huffman code given in v. Returns a tuple of a found code word and the next bit which has not yet been read. If no valid code word can be found starting at j the first return value is nothing.
HTTP2.HPack.setmaxsize! — Methodsetmaxsize!(t, s::Integer)Set the maximum size of the table t, evicting entries as necessary.
HTTP2.HPack.shouldneverindex — Methodshouldneverindex(e::Encoder, kv::AbstractHeaderField)Returns true iff the encoder e specifies that the header field should never be indexed.
HTTP2.HPack.tablesize — Methodtablesize(et::EncodeTable)
tablesize(dt::DecodeTable)Computes the "table size" as defined in the HPACK specification. This is computed by summing entrysize for all entries. This counts only the size of the dynamic table, not the static table.
HTTP2.HPack.tablesize — Methodtablesize(ed)Gives the current dynamic table size of the HPACK encoder or decoder ed. The definition of the size is somewhat bizarre, see here for the exact definition.
HTTP2.HPack.write_huffman_integer — Methodwrite_huffman_integer(io, b, p, n, ℓ)Write the Huffman code word n of length ℓ bits to io starting with a p bit prefix on the byte b (that is, p bits are available to be written on b).
Note that this requires p > 1, otherwise you will get a bogus answer. No check for this is performed.
HTTP2.HPack.write_huffman_string — Methodwrite_huffman_string(io, h, v)Write the string v to io using the Huffman encoder h. This does NOT include the encoding length integer.
If the final byte contains unused bits, these are filled with 1s. While the HPACK header does not explicitly indicate this is required, there is no Huffman word for 7 1s and it can be seen in examples. Alignment of the end of the code to the final byte is required by the specification.
HTTP2.HPack.write_integer — Methodwrite_integerWrite integer n to the stream with initial byte b and prefix length p.