Documentation
¶
Overview ¶
Package hpack implements HPACK (RFC 7541), the HTTP/2 header compression format.
Design goals over golang.org/x/net/http2/hpack:
- Zero allocation on hot decode paths (static-table hits, indexed fields)
- Pooled scratch buffers — no per-Write heap pressure
- Sharded sync.Pool for Encoders and Decoders for high-concurrency reuse
- Flat, cache-friendly Huffman decode table (256-entry lookup, no tree walk)
- Unsafe string conversion for decoded literals (avoids copy when safe)
- Strict RFC 7541 conformance with clear error taxonomy
- Hard limits on string length, dynamic table size, and header list size
- Full reset/reuse API so callers never need to allocate a new Decoder
Index ¶
- Variables
- func AppendHuffmanString(dst []byte, s string) []byte
- func HuffmanDecode(dst []byte, v []byte) ([]byte, error)
- func HuffmanDecodeToString(v []byte) (string, error)
- func HuffmanEncodeLength(s string) uint64
- type Decoder
- func (d *Decoder) Close() error
- func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error)
- func (d *Decoder) EmitEnabled() bool
- func (d *Decoder) Reset(maxDynTableSize uint32, emitFunc func(HeaderField))
- func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32)
- func (d *Decoder) SetEmitEnabled(v bool)
- func (d *Decoder) SetEmitFunc(fn func(HeaderField))
- func (d *Decoder) SetMaxDynamicTableSize(v uint32)
- func (d *Decoder) SetMaxHeaderBytes(n uint32)
- func (d *Decoder) SetMaxStringLength(n int)
- func (d *Decoder) Write(p []byte) (n int, err error)
- type DecoderPool
- type DecodingError
- type Encoder
- type HeaderField
- type InvalidIndexError
Constants ¶
This section is empty.
Variables ¶
var ( // ErrStringLength is returned when a header name or value exceeds the // configured maximum string length. ErrStringLength = errors.New("hpack: string too long") // ErrHeaderListSize is returned when the total size of decoded headers // exceeds the configured maximum header list size. ErrHeaderListSize = errors.New("hpack: header list size exceeded") // ErrInvalidHuffman is returned for malformed Huffman-encoded strings. ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data") )
Sentinel errors for common decoding failure modes.
Functions ¶
func AppendHuffmanString ¶
AppendHuffmanString appends s Huffman-encoded to dst.
Codegen notes (Go 1.22 amd64):
`n += uint(huffmanCodeLen[c])` before `x <<= huffmanCodeLen[c] % 64` lets the compiler reuse the already-loaded codeLen byte for both the addition and the shift without an extra register move.
`x <<= huffmanCodeLen[c] % 64` — the `% 64` is a hint that the shift amount is always in [0,63], eliminating the branchless overflow guard (CMPQ/SBBQ/ANDQ sequence) the compiler emits for an unbounded shift.
`n %= 32` instead of `n -= 32` after the flush — same hint: tells the compiler n is in [0,31] for the subsequent `x >> n` shift, removing another guard sequence.
Case 2/3 of the tail flush use uint16 intermediates so the compiler emits ROLW + a single wide store rather than two independent byte stores.
Max Huffman code length is 30 bits (see huffmanCodeLen), so the 64-bit accumulator always has room for at least one more code before a flush.
func HuffmanDecode ¶
HuffmanDecode decodes v into dst, returning the number of bytes written.
func HuffmanDecodeToString ¶
HuffmanDecodeToString decodes v and returns the result as a string.
func HuffmanEncodeLength ¶
HuffmanEncodeLength returns the number of bytes required to Huffman-encode s, rounded up to the next byte boundary.
Types ¶
type Decoder ¶
type Decoder struct {
// contains filtered or unexported fields
}
Decoder is a stateful HPACK decoder. It maintains a dynamic table and emits decoded header fields via the callback passed to NewDecoder or SetEmitFunc.
A Decoder is NOT safe for concurrent use. Use the Pool below for concurrency.
func NewDecoder ¶
func NewDecoder(maxDynTableSize uint32, emitFunc func(HeaderField)) *Decoder
NewDecoder returns a new Decoder with the given maximum dynamic table size. emitFunc is called for each decoded HeaderField in the same goroutine as Write.
func (*Decoder) Close ¶
Close declares the end of a header block. Returns an error if there are unconsumed bytes in the internal buffer (truncated block). After Close, the Decoder is ready to decode the next header block.
func (*Decoder) DecodeFull ¶
func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error)
DecodeFull decodes an entire header block and returns all HeaderFields. It is a convenience wrapper; for streaming use Write+Close.
func (*Decoder) EmitEnabled ¶
EmitEnabled reports the current emit-enabled state.
func (*Decoder) Reset ¶
func (d *Decoder) Reset(maxDynTableSize uint32, emitFunc func(HeaderField))
Reset resets d to its initial state and reconfigures it with a new max dynamic table size and emit function. Allows Decoder reuse without allocation.
func (*Decoder) SetAllowedMaxDynamicTableSize ¶
SetAllowedMaxDynamicTableSize sets the upper bound for dynamic table size updates received from the peer. This should match the value sent in SETTINGS.
func (*Decoder) SetEmitEnabled ¶
SetEmitEnabled controls whether the emit callback is invoked. When disabled, the decoder still processes bytes and updates state but does not invoke the emit callback — useful for enforcing MAX_HEADER_LIST_SIZE while staying in sync.
func (*Decoder) SetEmitFunc ¶
func (d *Decoder) SetEmitFunc(fn func(HeaderField))
SetEmitFunc replaces the emit callback.
func (*Decoder) SetMaxDynamicTableSize ¶
SetMaxDynamicTableSize updates the decoder's current dynamic table size limit.
func (*Decoder) SetMaxHeaderBytes ¶
SetMaxHeaderBytes caps the total size (RFC 7541 §4.1 formula) of headers decoded in a single header block. 0 means unlimited.
func (*Decoder) SetMaxStringLength ¶
SetMaxStringLength caps the length of any single header name or value. A value of 0 means unlimited (the default).
type DecoderPool ¶
type DecoderPool struct {
// contains filtered or unexported fields
}
DecoderPool manages a pool of reusable Decoders for high-concurrency environments.
func NewDecoderPool ¶
func NewDecoderPool(maxDynTable uint32, maxStrLen int, maxHeaderBytes uint32) *DecoderPool
NewDecoderPool returns a DecoderPool configured with the given limits.
func (*DecoderPool) Get ¶
func (p *DecoderPool) Get(emitFunc func(HeaderField)) *Decoder
Get returns a Decoder from the pool, configured with the given emit function.
func (*DecoderPool) Put ¶
func (p *DecoderPool) Put(d *Decoder)
Put returns a Decoder to the pool. The emit function is cleared. Callers must not use d after Put.
func (*DecoderPool) Stats ¶
func (p *DecoderPool) Stats() (acquired, released int64)
Stats returns (acquired, released) counts since pool creation.
type DecodingError ¶
type DecodingError struct{ Err error }
DecodingError is returned for any violation of the HPACK specification (RFC 7541). The embedded Err describes the specific violation.
func (DecodingError) Error ¶
func (e DecodingError) Error() string
func (DecodingError) Unwrap ¶
func (e DecodingError) Unwrap() error
type Encoder ¶
type Encoder struct {
// contains filtered or unexported fields
}
Encoder encodes HeaderFields into HPACK wire format. An Encoder is NOT safe for concurrent use.
func NewEncoder ¶
NewEncoder returns a new Encoder that writes to w.
func (*Encoder) MaxDynamicTableSize ¶
MaxDynamicTableSize returns the encoder's current dynamic table size limit.
func (*Encoder) SetMaxDynamicTableSize ¶
SetMaxDynamicTableSize updates the encoder's dynamic table size, bounded by the value set via SetMaxDynamicTableSizeLimit.
func (*Encoder) SetMaxDynamicTableSizeLimit ¶
SetMaxDynamicTableSizeLimit sets the absolute ceiling for SetMaxDynamicTableSize. If the current dynamic table size exceeds v, a Header Table Size Update will be emitted on the next WriteField call.
func (*Encoder) WriteField ¶
func (e *Encoder) WriteField(f HeaderField) error
WriteField encodes f into a single Write to e's underlying writer. It may also emit a Header Table Size Update if one is pending.
type HeaderField ¶
type HeaderField struct {
Name, Value string
// Sensitive marks headers that must never be indexed (e.g., Authorization).
// Corresponds to RFC 7541 §7.1.3 "Never-Indexed Literal Header Field".
Sensitive bool
}
HeaderField is an HTTP/2 header name–value pair as defined in RFC 7541 §1.3.
func (HeaderField) IsPseudo ¶
func (hf HeaderField) IsPseudo() bool
IsPseudo reports whether the header is an HTTP/2 pseudo-header (starts with ':').
func (HeaderField) Size ¶
func (hf HeaderField) Size() uint32
Size returns the entry size per RFC 7541 §4.1: len(name) + len(value) + 32.
func (HeaderField) String ¶
func (hf HeaderField) String() string
type InvalidIndexError ¶
type InvalidIndexError int
InvalidIndexError is returned when an encoder references a table entry before the static table or after the end of the dynamic table.
func (InvalidIndexError) Error ¶
func (e InvalidIndexError) Error() string