Commit a2ef8b9c authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

vendor: update golang.org/x/net/http2/hpack

Updates bundled golang.org/x/net/http2/hpack to x/net git rev 22bb95c5e for:

   http2/hpack: lazily build huffman table on first use
   https://golang.org/cl/127275

   http2/hpack: reduce memory for huffman decoding table
   https://golang.org/cl/127235

   http2/hpack: dynamic table updates must occur first
   https://golang.org/cl/111681

And a typo & gofmt CL.

Updates #25023

Change-Id: I7027fdb4982305aa671d811fe87f61e5df0f8e0e
Reviewed-on: https://go-review.googlesource.com/127355
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: default avatarAndrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 3acd2576
...@@ -206,7 +206,7 @@ func appendVarInt(dst []byte, n byte, i uint64) []byte { ...@@ -206,7 +206,7 @@ func appendVarInt(dst []byte, n byte, i uint64) []byte {
} }
// appendHpackString appends s, as encoded in "String Literal" // appendHpackString appends s, as encoded in "String Literal"
// representation, to dst and returns the the extended buffer. // representation, to dst and returns the extended buffer.
// //
// s will be encoded in Huffman codes only when it produces strictly // s will be encoded in Huffman codes only when it produces strictly
// shorter byte string. // shorter byte string.
......
...@@ -389,6 +389,12 @@ func (d *Decoder) callEmit(hf HeaderField) error { ...@@ -389,6 +389,12 @@ func (d *Decoder) callEmit(hf HeaderField) error {
// (same invariants and behavior as parseHeaderFieldRepr) // (same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseDynamicTableSizeUpdate() error { func (d *Decoder) parseDynamicTableSizeUpdate() 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 d.dynTab.size > 0 {
return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
}
buf := d.buf buf := d.buf
size, buf, err := readVarInt(5, buf) size, buf, err := readVarInt(5, buf)
if err != nil { if err != nil {
......
...@@ -462,6 +462,27 @@ func TestHuffmanDecode(t *testing.T) { ...@@ -462,6 +462,27 @@ func TestHuffmanDecode(t *testing.T) {
} }
} }
func BenchmarkHuffmanDecode(b *testing.B) {
b.StopTimer()
enc, err := hex.DecodeString(strings.Replace("94e7 821d d7f2 e6c7 b335 dfdf cd5b 3960 d5af 2708 7f36 72c1 ab27 0fb5 291f 9587 3160 65c0 03ed 4ee5 b106 3d50 07",
" ", "", -1))
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
b.StartTimer()
var buf bytes.Buffer
for i := 0; i < b.N; i++ {
buf.Reset()
if _, err := HuffmanDecode(&buf, enc); err != nil {
b.Fatalf("decode error: %v", err)
}
if string(buf.Bytes()) != "foo=ASDJKHQKBZXOQWEOPIUAXQWEOIU; max-age=3600; version=1" {
b.Fatalf("bogus output %q", buf.Bytes())
}
}
}
func TestAppendHuffmanString(t *testing.T) { func TestAppendHuffmanString(t *testing.T) {
tests := []struct { tests := []struct {
in, want string in, want string
...@@ -720,3 +741,22 @@ func TestSaveBufLimit(t *testing.T) { ...@@ -720,3 +741,22 @@ func TestSaveBufLimit(t *testing.T) {
t.Fatalf("Write error = %v; want ErrStringLength", err) t.Fatalf("Write error = %v; want ErrStringLength", err)
} }
} }
func TestDynamicSizeUpdate(t *testing.T) {
var buf bytes.Buffer
enc := NewEncoder(&buf)
enc.SetMaxDynamicTableSize(255)
enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
d := NewDecoder(4096, nil)
_, err := d.DecodeFull(buf.Bytes())
if err != nil {
t.Fatalf("unexpected error: got = %v", err)
}
// must fail since the dynamic table update must be at the beginning
_, err = d.DecodeFull(buf.Bytes())
if err == nil {
t.Fatalf("dynamic table size update not at the beginning of a header block")
}
}
...@@ -47,6 +47,7 @@ var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data") ...@@ -47,6 +47,7 @@ var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
// If maxLen is greater than 0, attempts to write more to buf than // If maxLen is greater than 0, attempts to write more to buf than
// maxLen bytes will return ErrStringLength. // maxLen bytes will return ErrStringLength.
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error { func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
rootHuffmanNode := getRootHuffmanNode()
n := rootHuffmanNode n := rootHuffmanNode
// cur is the bit buffer that has not been fed into n. // cur is the bit buffer that has not been fed into n.
// cbits is the number of low order bits in cur that are valid. // cbits is the number of low order bits in cur that are valid.
...@@ -106,7 +107,7 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error { ...@@ -106,7 +107,7 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
type node struct { type node struct {
// children is non-nil for internal nodes // children is non-nil for internal nodes
children []*node children *[256]*node
// The following are only valid if children is nil: // The following are only valid if children is nil:
codeLen uint8 // number of bits that led to the output of sym codeLen uint8 // number of bits that led to the output of sym
...@@ -114,22 +115,31 @@ type node struct { ...@@ -114,22 +115,31 @@ type node struct {
} }
func newInternalNode() *node { func newInternalNode() *node {
return &node{children: make([]*node, 256)} return &node{children: new([256]*node)}
} }
var rootHuffmanNode = newInternalNode() var (
buildRootOnce sync.Once
lazyRootHuffmanNode *node
)
func getRootHuffmanNode() *node {
buildRootOnce.Do(buildRootHuffmanNode)
return lazyRootHuffmanNode
}
func init() { func buildRootHuffmanNode() {
if len(huffmanCodes) != 256 { if len(huffmanCodes) != 256 {
panic("unexpected size") panic("unexpected size")
} }
lazyRootHuffmanNode = newInternalNode()
for i, code := range huffmanCodes { for i, code := range huffmanCodes {
addDecoderNode(byte(i), code, huffmanCodeLen[i]) addDecoderNode(byte(i), code, huffmanCodeLen[i])
} }
} }
func addDecoderNode(sym byte, code uint32, codeLen uint8) { func addDecoderNode(sym byte, code uint32, codeLen uint8) {
cur := rootHuffmanNode cur := lazyRootHuffmanNode
for codeLen > 8 { for codeLen > 8 {
codeLen -= 8 codeLen -= 8
i := uint8(code >> codeLen) i := uint8(code >> codeLen)
......
...@@ -128,67 +128,67 @@ func (t *headerFieldTable) idToIndex(id uint64) uint64 { ...@@ -128,67 +128,67 @@ func (t *headerFieldTable) idToIndex(id uint64) uint64 {
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
var staticTable = newStaticTable() var staticTable = newStaticTable()
var staticTableEntries = [...]HeaderField{ var staticTableEntries = [...]HeaderField{
HeaderField{Name: ":authority"}, {Name: ":authority"},
HeaderField{Name: ":method", Value: "GET"}, {Name: ":method", Value: "GET"},
HeaderField{Name: ":method", Value: "POST"}, {Name: ":method", Value: "POST"},
HeaderField{Name: ":path", Value: "/"}, {Name: ":path", Value: "/"},
HeaderField{Name: ":path", Value: "/index.html"}, {Name: ":path", Value: "/index.html"},
HeaderField{Name: ":scheme", Value: "http"}, {Name: ":scheme", Value: "http"},
HeaderField{Name: ":scheme", Value: "https"}, {Name: ":scheme", Value: "https"},
HeaderField{Name: ":status", Value: "200"}, {Name: ":status", Value: "200"},
HeaderField{Name: ":status", Value: "204"}, {Name: ":status", Value: "204"},
HeaderField{Name: ":status", Value: "206"}, {Name: ":status", Value: "206"},
HeaderField{Name: ":status", Value: "304"}, {Name: ":status", Value: "304"},
HeaderField{Name: ":status", Value: "400"}, {Name: ":status", Value: "400"},
HeaderField{Name: ":status", Value: "404"}, {Name: ":status", Value: "404"},
HeaderField{Name: ":status", Value: "500"}, {Name: ":status", Value: "500"},
HeaderField{Name: "accept-charset"}, {Name: "accept-charset"},
HeaderField{Name: "accept-encoding", Value: "gzip, deflate"}, {Name: "accept-encoding", Value: "gzip, deflate"},
HeaderField{Name: "accept-language"}, {Name: "accept-language"},
HeaderField{Name: "accept-ranges"}, {Name: "accept-ranges"},
HeaderField{Name: "accept"}, {Name: "accept"},
HeaderField{Name: "access-control-allow-origin"}, {Name: "access-control-allow-origin"},
HeaderField{Name: "age"}, {Name: "age"},
HeaderField{Name: "allow"}, {Name: "allow"},
HeaderField{Name: "authorization"}, {Name: "authorization"},
HeaderField{Name: "cache-control"}, {Name: "cache-control"},
HeaderField{Name: "content-disposition"}, {Name: "content-disposition"},
HeaderField{Name: "content-encoding"}, {Name: "content-encoding"},
HeaderField{Name: "content-language"}, {Name: "content-language"},
HeaderField{Name: "content-length"}, {Name: "content-length"},
HeaderField{Name: "content-location"}, {Name: "content-location"},
HeaderField{Name: "content-range"}, {Name: "content-range"},
HeaderField{Name: "content-type"}, {Name: "content-type"},
HeaderField{Name: "cookie"}, {Name: "cookie"},
HeaderField{Name: "date"}, {Name: "date"},
HeaderField{Name: "etag"}, {Name: "etag"},
HeaderField{Name: "expect"}, {Name: "expect"},
HeaderField{Name: "expires"}, {Name: "expires"},
HeaderField{Name: "from"}, {Name: "from"},
HeaderField{Name: "host"}, {Name: "host"},
HeaderField{Name: "if-match"}, {Name: "if-match"},
HeaderField{Name: "if-modified-since"}, {Name: "if-modified-since"},
HeaderField{Name: "if-none-match"}, {Name: "if-none-match"},
HeaderField{Name: "if-range"}, {Name: "if-range"},
HeaderField{Name: "if-unmodified-since"}, {Name: "if-unmodified-since"},
HeaderField{Name: "last-modified"}, {Name: "last-modified"},
HeaderField{Name: "link"}, {Name: "link"},
HeaderField{Name: "location"}, {Name: "location"},
HeaderField{Name: "max-forwards"}, {Name: "max-forwards"},
HeaderField{Name: "proxy-authenticate"}, {Name: "proxy-authenticate"},
HeaderField{Name: "proxy-authorization"}, {Name: "proxy-authorization"},
HeaderField{Name: "range"}, {Name: "range"},
HeaderField{Name: "referer"}, {Name: "referer"},
HeaderField{Name: "refresh"}, {Name: "refresh"},
HeaderField{Name: "retry-after"}, {Name: "retry-after"},
HeaderField{Name: "server"}, {Name: "server"},
HeaderField{Name: "set-cookie"}, {Name: "set-cookie"},
HeaderField{Name: "strict-transport-security"}, {Name: "strict-transport-security"},
HeaderField{Name: "transfer-encoding"}, {Name: "transfer-encoding"},
HeaderField{Name: "user-agent"}, {Name: "user-agent"},
HeaderField{Name: "vary"}, {Name: "vary"},
HeaderField{Name: "via"}, {Name: "via"},
HeaderField{Name: "www-authenticate"}, {Name: "www-authenticate"},
} }
func newStaticTable() *headerFieldTable { func newStaticTable() *headerFieldTable {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment