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 "golang.org/x/net/http2/hpack"// 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")// 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// 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)// 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// 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// 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) uint64import (
"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
}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
}func decodeHeaderBlock(encoded []byte) ([]hpack.HeaderField, error) {
decoder := hpack.NewDecoder(4096, nil)
return decoder.DecodeFull(encoded)
}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)
}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
}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
}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)
}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()
}