Imports #
"fmt"
"io"
"bytes"
"errors"
"fmt"
"bytes"
"errors"
"io"
"sync"
"fmt"
"io"
"bytes"
"errors"
"fmt"
"bytes"
"errors"
"io"
"sync"
ErrInvalidHuffman is returned for errors found decoding Huffman-encoded strings.
var ErrInvalidHuffman = *ast.CallExprErrStringLength is returned by Decoder.Write when the max string length (as configured by Decoder.SetMaxStringLength) would be violated.
var ErrStringLength = *ast.CallExprvar bufPool = sync.Pool{...}var buildRootOnce sync.OnceerrNeedMore is an internal sentinel error value that means the buffer is truncated and we need to read more data before we can continue parsing.
var errNeedMore = *ast.CallExprvar errVarintOverflow = DecodingError{...}var huffmanCodeLen = [256]uint8{...}var huffmanCodes = [256]uint32{...}const indexedFalseconst indexedNeverconst indexedTrue indexType = iotaconst initialHeaderTableSize = 4096var lazyRootHuffmanNode *nodevar staticTable = *ast.UnaryExprconst uint32Max = *ast.UnaryExprAn InvalidIndexError is returned when an encoder references a table entry before the static table or after the end of the dynamic table.
type InvalidIndexError intincomparable is a zero-width, non-comparable type. Adding it to a struct makes that struct also non-comparable, and generally doesn't add any size (as long as it's first).
type incomparable [0]func()type indexType intA Decoder is the decoding context for incremental processing of header blocks.
type Decoder struct {
dynTab dynamicTable
emit func(f HeaderField)
emitEnabled bool
maxStrLen int
buf []byte
saveBuf bytes.Buffer
firstField bool
}A DecodingError is something the spec defines as a decoding error.
type DecodingError struct {
Err error
}type Encoder struct {
dynTab dynamicTable
minSize uint32
maxSizeLimit uint32
tableSizeUpdate bool
w io.Writer
buf []byte
}A HeaderField is a name-value pair. Both the name and value are treated as opaque sequences of octets.
type HeaderField struct {
Name string
Value string
Sensitive bool
}type dynamicTable struct {
table headerFieldTable
size uint32
maxSize uint32
allowedMaxSize uint32
}headerFieldTable implements a list of HeaderFields. This is used to implement the static and dynamic tables.
type headerFieldTable struct {
ents []HeaderField
evictCount uint64
byName map[string]uint64
byNameValue map[pairNameValue]uint64
}type node struct {
_ incomparable
children *[256]*node
codeLen uint8
sym byte
}type pairNameValue struct {
name string
value string
}type undecodedString struct {
isHuff bool
b []byte
}AppendHuffmanString appends s, as encoded in Huffman codes, to dst and returns the extended buffer.
func AppendHuffmanString(dst []byte, s string) []byteClose declares that the decoding is complete and resets the Decoder to be reused again for a new header block. If there is any remaining data in the decoder's buffer, Close returns an error.
func (d *Decoder) Close() errorDecodeFull decodes an entire block. TODO: remove this method and make it incremental later? This is easier for debugging now.
func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error)EmitEnabled reports whether calls to the emitFunc provided to NewDecoder are currently enabled. The default is true.
func (d *Decoder) EmitEnabled() boolfunc (e InvalidIndexError) Error() stringfunc (de DecodingError) Error() stringHuffmanDecode decodes the string in v and writes the expanded result to w, returning the number of bytes written to w and the Write call's return value. At most one Write call is made.
func HuffmanDecode(w io.Writer, v []byte) (int, error)HuffmanDecodeToString decodes the string in v.
func HuffmanDecodeToString(v []byte) (string, error)HuffmanEncodeLength returns the number of bytes required to encode s in Huffman codes. The result is round up to byte boundary.
func HuffmanEncodeLength(s string) uint64IsPseudo reports whether the header field is an http2 pseudo header. That is, it reports whether it starts with a colon. It is not otherwise guaranteed to be a valid pseudo header field, though.
func (hf HeaderField) IsPseudo() boolMaxDynamicTableSize returns the current dynamic header table size.
func (e *Encoder) MaxDynamicTableSize() (v uint32)NewDecoder returns a new decoder with the provided maximum dynamic table size. The emitFunc will be called for each valid field parsed, in the same goroutine as calls to Write, before Write returns.
func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *DecoderNewEncoder returns a new Encoder which performs HPACK encoding. An encoded data is written to w.
func NewEncoder(w io.Writer) *EncoderSetAllowedMaxDynamicTableSize sets the upper bound that the encoded stream (via dynamic table size updates) may set the maximum size to.
func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32)SetEmitEnabled controls whether the emitFunc provided to NewDecoder should be called. The default is true. This facility exists to let servers enforce MAX_HEADER_LIST_SIZE while still decoding and keeping in-sync with decoder state, but without doing unnecessary decompression or generating unnecessary garbage for header fields past the limit.
func (d *Decoder) SetEmitEnabled(v bool)SetEmitFunc changes the callback used when new header fields are decoded. It must be non-nil. It does not affect EmitEnabled.
func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField))SetMaxDynamicTableSize changes the dynamic header table size to v. The actual size is bounded by the value passed to SetMaxDynamicTableSizeLimit.
func (e *Encoder) SetMaxDynamicTableSize(v uint32)func (d *Decoder) SetMaxDynamicTableSize(v uint32)SetMaxDynamicTableSizeLimit changes the maximum value that can be specified in SetMaxDynamicTableSize to v. By default, it is set to 4096, which is the same size of the default dynamic header table size described in HPACK specification. If the current maximum dynamic header table size is strictly greater than v, "Header Table Size Update" will be done in the next WriteField call and the maximum dynamic header table size is truncated to v.
func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32)SetMaxStringLength sets the maximum size of a HeaderField name or value string. If a string exceeds this length (even after any decompression), Write will return ErrStringLength. A value of 0 means unlimited and is the default from NewDecoder.
func (d *Decoder) SetMaxStringLength(n int)Size returns the size of an entry per RFC 7541 section 4.1.
func (hf HeaderField) Size() uint32func (hf HeaderField) String() stringfunc (d *Decoder) Write(p []byte) (n int, err error)WriteField encodes f into a single Write to e's underlying Writer. This function may also produce bytes for "Header Table Size Update" if necessary. If produced, it is done before encoding f.
func (e *Encoder) WriteField(f HeaderField) errorfunc (dt *dynamicTable) add(f HeaderField)addEntry adds a new entry.
func (t *headerFieldTable) addEntry(f HeaderField)appendHpackString appends s, as encoded in "String Literal" representation, to dst and returns the extended buffer. s will be encoded in Huffman codes only when it produces strictly shorter byte string.
func appendHpackString(dst []byte, s string) []byteappendIndexed appends index i, as encoded in "Indexed Header Field" representation, to dst and returns the extended buffer.
func appendIndexed(dst []byte, i uint64) []byteappendIndexedName appends f and index i referring indexed name entry, as encoded in one of "Literal Header field - Indexed Name" representation variants, to dst and returns the extended buffer. If f.Sensitive is true, "Never Indexed" representation is used. If f.Sensitive is false and indexing is true, "Incremental Indexing" representation is used.
func appendIndexedName(dst []byte, f HeaderField, i uint64, indexing bool) []byteappendNewName appends f, as encoded in one of "Literal Header field - New Name" representation variants, to dst and returns the extended buffer. If f.Sensitive is true, "Never Indexed" representation is used. If f.Sensitive is false and indexing is true, "Incremental Indexing" representation is used.
func appendNewName(dst []byte, f HeaderField, indexing bool) []byteappendTableSize appends v, as encoded in "Header Table Size Update" representation, to dst and returns the extended buffer.
func appendTableSize(dst []byte, v uint32) []byteappendVarInt appends i, as encoded in variable integer form using n bit prefix, to dst and returns the extended buffer. See https://httpwg.org/specs/rfc7541.html#integer.representation
func appendVarInt(dst []byte, n byte, i uint64) []bytefunc (d *Decoder) at(i uint64) (hf HeaderField, ok bool)func buildRootHuffmanNode()func (d *Decoder) callEmit(hf HeaderField) errorfunc (d *Decoder) decodeString(u undecodedString) (string, error)encodeTypeByte returns type byte. If sensitive is true, type byte for "Never Indexed" representation is returned. If sensitive is false and indexing is true, type byte for "Incremental Indexing" representation is returned. Otherwise, type byte for "Without Indexing" is returned.
func encodeTypeByte(indexing bool, sensitive bool) byteIf we're too big, evict old stuff.
func (dt *dynamicTable) evict()evictOldest evicts the n oldest entries in the table.
func (t *headerFieldTable) evictOldest(n int)func getRootHuffmanNode() *nodehuffmanDecode decodes v to buf. If maxLen is greater than 0, attempts to write more to buf than maxLen bytes will return ErrStringLength.
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) erroridToIndex converts a unique id to an HPACK index. See Section 2.3.3.
func (t *headerFieldTable) idToIndex(id uint64) uint64func (v indexType) indexed() boolfunc (t *headerFieldTable) init()len reports the number of entries in the table.
func (t *headerFieldTable) len() intfunc (d *Decoder) maxTableIndex() intfunc newInternalNode() *node(same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseDynamicTableSizeUpdate() error(same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseFieldIndexed() error(same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseFieldLiteral(n uint8, it indexType) errorreturns errNeedMore if there isn't enough data available. any other error is fatal. consumes d.buf iff it returns nil. precondition: must be called with len(d.buf) > 0
func (d *Decoder) parseHeaderFieldRepr() errorreadString reads an hpack string from p. It returns a reference to the encoded string data to permit deferring decode costs until after the caller verifies all data is present.
func (d *Decoder) readString(p []byte) (u undecodedString, remain []byte, err error)readVarInt reads an unsigned variable length integer off the beginning of p. n is the parameter as described in https://httpwg.org/specs/rfc7541.html#rfc.section.5.1. n must always be between 1 and 8. The returned remain buffer is either a smaller suffix of p, or err != nil. The error is errNeedMore if p doesn't contain a complete integer.
func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error)search finds f in the table. If there is no match, i is 0. If both name and value match, i is the matched index and nameValueMatch becomes true. If only name matches, i points to that index and nameValueMatch becomes false. The returned index is a 1-based HPACK index. For dynamic tables, HPACK says that index 1 should be the newest entry, but t.ents[0] is the oldest entry, meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic table, the return value i actually refers to the entry t.ents[t.len()-i]. All tables are assumed to be a dynamic tables except for the global staticTable. See Section 2.3.3.
func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool)searchTable searches f in both stable and dynamic header tables. The static header table is searched first. Only when there is no exact match for both name and value, the dynamic header table is then searched. If there is no match, i is 0. If both name and value match, i is the matched index and nameValueMatch becomes true. If only name matches, i points to that index and nameValueMatch becomes false.
func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool)func (v indexType) sensitive() boolfunc (dt *dynamicTable) setMaxSize(v uint32)shouldIndex reports whether f should be indexed.
func (e *Encoder) shouldIndex(f HeaderField) boolGenerated with Arrow