// Copyright 2014 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// 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
package hpackimport ()// A DecodingError is something the spec defines as a decoding error.typeDecodingErrorstruct {Errerror}func ( DecodingError) () string {returnfmt.Sprintf("decoding error: %v", .Err)}// An InvalidIndexError is returned when an encoder references a table// entry before the static table or after the end of the dynamic table.typeInvalidIndexErrorintfunc ( InvalidIndexError) () string {returnfmt.Sprintf("invalid indexed representation index %d", int())}// A HeaderField is a name-value pair. Both the name and value are// treated as opaque sequences of octets.typeHeaderFieldstruct {Name, Valuestring// Sensitive means that this header field should never be // indexed.Sensitivebool}// IsPseudo 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 ( HeaderField) () bool {returnlen(.Name) != 0 && .Name[0] == ':'}func ( HeaderField) () string {varstringif .Sensitive { = " (sensitive)" }returnfmt.Sprintf("header field %q = %q%s", .Name, .Value, )}// Size returns the size of an entry per RFC 7541 section 4.1.func ( HeaderField) () uint32 {// https://httpwg.org/specs/rfc7541.html#rfc.section.4.1 // "The size of the dynamic table is the sum of the size of // its entries. The size of an entry is the sum of its name's // length in octets (as defined in Section 5.2), its value's // length in octets (see Section 5.2), plus 32. The size of // an entry is calculated using the length of the name and // value without any Huffman encoding applied."// This can overflow if somebody makes a large HeaderField // Name and/or Value by hand, but we don't care, because that // won't happen on the wire because the encoding doesn't allow // it.returnuint32(len(.Name) + len(.Value) + 32)}// A Decoder is the decoding context for incremental processing of// header blocks.typeDecoderstruct {dynTabdynamicTableemitfunc(f HeaderField)emitEnabledbool// whether calls to emit are enabledmaxStrLenint// 0 means unlimited// buf is the unparsed buffer. It's only written to // saveBuf if it was truncated in the middle of a header // block. Because it's usually not owned, we can only // process it under Write.buf []byte// not owned; only valid during Write// saveBuf is previous data passed to Write which we weren't able // to fully parse before. Unlike buf, we own this data.saveBufbytes.BufferfirstFieldbool// processing the first field of the header block}// 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 ( uint32, func( HeaderField)) *Decoder { := &Decoder{emit: ,emitEnabled: true,firstField: true, } .dynTab.table.init() .dynTab.allowedMaxSize = .dynTab.setMaxSize()return}// ErrStringLength is returned by Decoder.Write when the max string length// (as configured by Decoder.SetMaxStringLength) would be violated.varErrStringLength = errors.New("hpack: string too long")// 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 ( *Decoder) ( int) { .maxStrLen = }// SetEmitFunc changes the callback used when new header fields// are decoded.// It must be non-nil. It does not affect EmitEnabled.func ( *Decoder) ( func( HeaderField)) { .emit = }// 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 ( *Decoder) ( bool) { .emitEnabled = }// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder// are currently enabled. The default is true.func ( *Decoder) () bool { return .emitEnabled }// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their// underlying buffers for garbage reasons.func ( *Decoder) ( uint32) { .dynTab.setMaxSize()}// SetAllowedMaxDynamicTableSize sets the upper bound that the encoded// stream (via dynamic table size updates) may set the maximum size// to.func ( *Decoder) ( uint32) { .dynTab.allowedMaxSize = }typedynamicTablestruct {// https://httpwg.org/specs/rfc7541.html#rfc.section.2.3.2tableheaderFieldTablesizeuint32// in bytesmaxSizeuint32// current maxSizeallowedMaxSizeuint32// maxSize may go up to this, inclusive}func ( *dynamicTable) ( uint32) { .maxSize = .evict()}func ( *dynamicTable) ( HeaderField) { .table.addEntry() .size += .Size() .evict()}// If we're too big, evict old stuff.func ( *dynamicTable) () {varintfor .size > .maxSize && < .table.len() { .size -= .table.ents[].Size() ++ } .table.evictOldest()}func ( *Decoder) () int {// This should never overflow. RFC 7540 Section 6.5.2 limits the size of // the dynamic table to 2^32 bytes, where each entry will occupy more than // one byte. Further, the staticTable has a fixed, small length.return .dynTab.table.len() + staticTable.len()}func ( *Decoder) ( uint64) ( HeaderField, bool) {// See Section 2.3.3.if == 0 {return }if <= uint64(staticTable.len()) {returnstaticTable.ents[-1], true }if > uint64(.maxTableIndex()) {return }// In the dynamic table, newer entries have lower indices. // However, dt.ents[0] is the oldest entry. Hence, dt.ents is // the reversed dynamic table. := .dynTab.tablereturn .ents[.len()-(int()-staticTable.len())], true}// DecodeFull decodes an entire block.//// TODO: remove this method and make it incremental later? This is// easier for debugging now.func ( *Decoder) ( []byte) ([]HeaderField, error) {var []HeaderField := .emitdeferfunc() { .emit = }() .emit = func( HeaderField) { = append(, ) }if , := .Write(); != nil {returnnil, }if := .Close(); != nil {returnnil, }return , nil}// Close 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 ( *Decoder) () error {if .saveBuf.Len() > 0 { .saveBuf.Reset()returnDecodingError{errors.New("truncated headers")} } .firstField = truereturnnil}func ( *Decoder) ( []byte) ( int, error) {iflen() == 0 {// Prevent state machine CPU attacks (making us redo // work up to the point of finding out we don't have // enough data)return }// Only copy the data if we have to. Optimistically assume // that p will contain a complete header block.if .saveBuf.Len() == 0 { .buf = } else { .saveBuf.Write() .buf = .saveBuf.Bytes() .saveBuf.Reset() }forlen(.buf) > 0 { = .parseHeaderFieldRepr()if == errNeedMore {// Extra paranoia, making sure saveBuf won't // get too large. All the varint and string // reading code earlier should already catch // overlong things and return ErrStringLength, // but keep this as a last resort.const = 8// conservativeif .maxStrLen != 0 && int64(len(.buf)) > 2*(int64(.maxStrLen)+) {return0, ErrStringLength } .saveBuf.Write(.buf)returnlen(), nil } .firstField = falseif != nil {break } }returnlen(), }// errNeedMore is an internal sentinel error value that means the// buffer is truncated and we need to read more data before we can// continue parsing.varerrNeedMore = errors.New("need more data")typeindexTypeintconst (indexedTrueindexType = iotaindexedFalseindexedNever)func ( indexType) () bool { return == indexedTrue }func ( indexType) () bool { return == indexedNever }// returns 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) > 0func ( *Decoder) () error { := .buf[0]switch {case &128 != 0:// Indexed representation. // High bit set? // https://httpwg.org/specs/rfc7541.html#rfc.section.6.1return .parseFieldIndexed()case &192 == 64:// 6.2.1 Literal Header Field with Incremental Indexing // 0b10xxxxxx: top two bits are 10 // https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.1return .parseFieldLiteral(6, indexedTrue)case &240 == 0:// 6.2.2 Literal Header Field without Indexing // 0b0000xxxx: top four bits are 0000 // https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.2return .parseFieldLiteral(4, indexedFalse)case &240 == 16:// 6.2.3 Literal Header Field never Indexed // 0b0001xxxx: top four bits are 0001 // https://httpwg.org/specs/rfc7541.html#rfc.section.6.2.3return .parseFieldLiteral(4, indexedNever)case &224 == 32:// 6.3 Dynamic Table Size Update // Top three bits are '001'. // https://httpwg.org/specs/rfc7541.html#rfc.section.6.3return .parseDynamicTableSizeUpdate() }returnDecodingError{errors.New("invalid encoding")}}// (same invariants and behavior as parseHeaderFieldRepr)func ( *Decoder) () error { := .buf , , := readVarInt(7, )if != nil {return } , := .at()if ! {returnDecodingError{InvalidIndexError()} } .buf = return .callEmit(HeaderField{Name: .Name, Value: .Value})}// (same invariants and behavior as parseHeaderFieldRepr)func ( *Decoder) ( uint8, indexType) error { := .buf , , := readVarInt(, )if != nil {return }varHeaderField := .emitEnabled || .indexed()varundecodedStringif > 0 { , := .at()if ! {returnDecodingError{InvalidIndexError()} } .Name = .Name } else { , , = .readString()if != nil {return } } , , := .readString()if != nil {return }if {if <= 0 { .Name, = .decodeString()if != nil {return } } .Value, = .decodeString()if != nil {return } } .buf = if .indexed() { .dynTab.add() } .Sensitive = .sensitive()return .callEmit()}func ( *Decoder) ( HeaderField) error {if .maxStrLen != 0 {iflen(.Name) > .maxStrLen || len(.Value) > .maxStrLen {returnErrStringLength } }if .emitEnabled { .emit() }returnnil}// (same invariants and behavior as parseHeaderFieldRepr)func ( *Decoder) () error {// RFC 7541, sec 4.2: This dynamic table size update MUST occur at the // beginning of the first header block following the change to the dynamic table size.if !.firstField && .dynTab.size > 0 {returnDecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")} } := .buf , , := readVarInt(5, )if != nil {return }if > uint64(.dynTab.allowedMaxSize) {returnDecodingError{errors.New("dynamic table size update too large")} } .dynTab.setMaxSize(uint32()) .buf = returnnil}varerrVarintOverflow = DecodingError{errors.New("varint integer overflow")}// 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 ( byte, []byte) ( uint64, []byte, error) {if < 1 || > 8 {panic("bad n") }iflen() == 0 {return0, , errNeedMore } = uint64([0])if < 8 { &= (1 << uint64()) - 1 }if < (1<<uint64())-1 {return , [1:], nil } := = [1:]varuint64forlen() > 0 { := [0] = [1:] += uint64(&127) << if &128 == 0 {return , , nil } += 7if >= 63 { // TODO: proper overflow check. making this up.return0, , errVarintOverflow } }return0, , errNeedMore}// readString 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 ( *Decoder) ( []byte) ( undecodedString, []byte, error) {iflen() == 0 {return , , errNeedMore } := [0]&128 != 0 , , := readVarInt(7, )if != nil {return , , }if .maxStrLen != 0 && > uint64(.maxStrLen) {// Returning an error here means Huffman decoding errors // for non-indexed strings past the maximum string length // are ignored, but the server is returning an error anyway // and because the string is not indexed the error will not // affect the decoding state.return , nil, ErrStringLength }ifuint64(len()) < {return , , errNeedMore } .isHuff = .b = [:]return , [:], nil}typeundecodedStringstruct {isHuffboolb []byte}func ( *Decoder) ( undecodedString) (string, error) {if !.isHuff {returnstring(.b), nil } := bufPool.Get().(*bytes.Buffer) .Reset() // don't trust othersvarstring := huffmanDecode(, .maxStrLen, .b)if == nil { = .String() } .Reset() // be nice to GCbufPool.Put()return , }
The pages are generated with Goldsv0.6.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.