or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

bpf.mdcontext-ctxhttp.mdcontext.mddict.mddns-dnsmessage.mdhtml-atom.mdhtml-charset.mdhtml.mdhttp-httpguts.mdhttp-httpproxy.mdhttp2-h2c.mdhttp2-hpack.mdhttp2.mdicmp.mdidna.mdindex.mdipv4.mdipv6.mdnettest.mdnetutil.mdproxy.mdpublicsuffix.mdquic-qlog.mdquic.mdtrace.mdwebdav.mdwebsocket.mdxsrftoken.md
tile.json

http2-hpack.mddocs/

HPACK Header Compression

Package hpack implements HPACK, a compression format for efficiently representing HTTP header fields in the context of HTTP/2.

See http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-09

Import

import "golang.org/x/net/http2/hpack"

Variables

// ErrInvalidHuffman is returned for errors found decoding Huffman-encoded strings
var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")

// ErrStringLength is returned when the max string length would be violated
var ErrStringLength = errors.New("hpack: string too long")

Types

// HeaderField is a name-value pair
type HeaderField struct {
    Name      string
    Value     string
    Sensitive bool // Should never be indexed
}

func (hf HeaderField) IsPseudo() bool
func (hf HeaderField) Size() uint32
func (hf HeaderField) String() string

HeaderField Methods

  • IsPseudo: Reports whether the header field is an http2 pseudo header (starts with colon)
  • Size: Returns the size of an entry per RFC 7541 section 4.1
  • String: Returns string representation

Decoder

// Decoder is the decoding context for incremental processing of header blocks
type Decoder struct {
    // Has unexported fields
}

func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder

func (d *Decoder) Close() error
func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error)
func (d *Decoder) EmitEnabled() bool
func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32)
func (d *Decoder) SetEmitEnabled(v bool)
func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField))
func (d *Decoder) SetMaxDynamicTableSize(v uint32)
func (d *Decoder) SetMaxStringLength(n int)
func (d *Decoder) Write(p []byte) (n int, err error)

Decoder Methods

  • NewDecoder: Returns a new decoder with maximum dynamic table size and emit function
  • Close: Declares decoding is complete and resets the decoder
  • DecodeFull: Decodes an entire block
  • EmitEnabled: Reports whether emit function calls are enabled
  • SetAllowedMaxDynamicTableSize: Sets upper bound for maximum size
  • SetEmitEnabled: Controls whether emit function should be called
  • SetEmitFunc: Changes callback used when new header fields are decoded
  • SetMaxDynamicTableSize: Sets maximum dynamic table size
  • SetMaxStringLength: Sets maximum size of HeaderField name or value string (0 means unlimited)
  • Write: Writes compressed header data

Encoder

// Encoder performs HPACK encoding
type Encoder struct {
    // Has unexported fields
}

func NewEncoder(w io.Writer) *Encoder

func (e *Encoder) MaxDynamicTableSize() uint32
func (e *Encoder) SetMaxDynamicTableSize(v uint32)
func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32)
func (e *Encoder) WriteField(f HeaderField) error

Encoder Methods

  • NewEncoder: Returns a new Encoder which writes to w
  • MaxDynamicTableSize: Returns current dynamic header table size
  • SetMaxDynamicTableSize: Changes dynamic header table size
  • SetMaxDynamicTableSizeLimit: Changes maximum value for SetMaxDynamicTableSize (default: 4096)
  • WriteField: Encodes header field (may also produce "Header Table Size Update")

Error Types

// DecodingError is a decoding error as defined by the spec
type DecodingError struct {
    Err error
}

func (de DecodingError) Error() string

// InvalidIndexError is returned when encoder references invalid table entry
type InvalidIndexError int

func (e InvalidIndexError) Error() string

Huffman Coding Functions

// AppendHuffmanString appends s, as encoded in Huffman codes, to dst
func AppendHuffmanString(dst []byte, s string) []byte

// HuffmanDecode decodes the string in v and writes to w
func HuffmanDecode(w io.Writer, v []byte) (int, error)

// HuffmanDecodeToString decodes the string in v
func HuffmanDecodeToString(v []byte) (string, error)

// HuffmanEncodeLength returns bytes required to encode s in Huffman codes
func HuffmanEncodeLength(s string) uint64

Usage Examples

Encoding Headers

import (
    "bytes"
    "golang.org/x/net/http2/hpack"
)

func encodeHeaders() ([]byte, error) {
    var buf bytes.Buffer
    encoder := hpack.NewEncoder(&buf)

    // Encode header fields
    headers := []hpack.HeaderField{
        {Name: ":method", Value: "GET"},
        {Name: ":scheme", Value: "https"},
        {Name: ":path", Value: "/index.html"},
        {Name: ":authority", Value: "example.com"},
        {Name: "user-agent", Value: "MyClient/1.0"},
    }

    for _, hf := range headers {
        if err := encoder.WriteField(hf); err != nil {
            return nil, err
        }
    }

    return buf.Bytes(), nil
}

Decoding Headers

func decodeHeaders(encoded []byte) ([]hpack.HeaderField, error) {
    var headers []hpack.HeaderField

    decoder := hpack.NewDecoder(4096, func(f hpack.HeaderField) {
        headers = append(headers, f)
    })

    _, err := decoder.Write(encoded)
    if err != nil {
        return nil, err
    }

    if err := decoder.Close(); err != nil {
        return nil, err
    }

    return headers, nil
}

Using DecodeFull

func decodeHeaderBlock(encoded []byte) ([]hpack.HeaderField, error) {
    decoder := hpack.NewDecoder(4096, nil)
    return decoder.DecodeFull(encoded)
}

Sensitive Headers

func encodeSensitiveHeader() error {
    var buf bytes.Buffer
    encoder := hpack.NewEncoder(&buf)

    // Mark authorization header as sensitive (never indexed)
    authHeader := hpack.HeaderField{
        Name:      "authorization",
        Value:     "Bearer token123",
        Sensitive: true,
    }

    return encoder.WriteField(authHeader)
}

Dynamic Table Size Management

func configureEncoder() *hpack.Encoder {
    var buf bytes.Buffer
    encoder := hpack.NewEncoder(&buf)

    // Set maximum dynamic table size limit
    encoder.SetMaxDynamicTableSizeLimit(8192)

    // Set actual dynamic table size
    encoder.SetMaxDynamicTableSize(4096)

    return encoder
}

func configureDecoder() *hpack.Decoder {
    decoder := hpack.NewDecoder(4096, func(f hpack.HeaderField) {
        fmt.Printf("%s: %s\n", f.Name, f.Value)
    })

    // Set allowed maximum
    decoder.SetAllowedMaxDynamicTableSize(8192)

    // Set actual maximum
    decoder.SetMaxDynamicTableSize(4096)

    return decoder
}

String Length Limits

func decodeWithLimit(encoded []byte) error {
    decoder := hpack.NewDecoder(4096, func(f hpack.HeaderField) {
        // Process field
    })

    // Limit header field name/value to 16KB
    decoder.SetMaxStringLength(16 * 1024)

    _, err := decoder.Write(encoded)
    return err
}

Huffman Encoding

func huffmanEncode(s string) []byte {
    // Calculate required length
    length := hpack.HuffmanEncodeLength(s)
    fmt.Printf("Original: %d bytes, Encoded: %d bytes\n", len(s), length)

    // Encode string
    encoded := hpack.AppendHuffmanString(nil, s)
    return encoded
}

func huffmanDecode(encoded []byte) (string, error) {
    return hpack.HuffmanDecodeToString(encoded)
}

Controlling Emission

func limitedDecode(encoded []byte, maxSize int) ([]hpack.HeaderField, error) {
    var headers []hpack.HeaderField
    var totalSize int

    decoder := hpack.NewDecoder(4096, func(f hpack.HeaderField) {
        totalSize += int(f.Size())
        if totalSize <= maxSize {
            headers = append(headers, f)
        }
    })

    // Process headers
    _, err := decoder.Write(encoded[:len(encoded)/2])
    if err != nil {
        return nil, err
    }

    // Disable emission if limit exceeded
    if totalSize > maxSize {
        decoder.SetEmitEnabled(false)
    }

    // Continue processing
    _, err = decoder.Write(encoded[len(encoded)/2:])
    if err != nil {
        return nil, err
    }

    return headers, decoder.Close()
}