]> Cypherpunks repositories - gostls13.git/commitdiff
vendor: update golang.org/x/net/http2/hpack
authorBrad Fitzpatrick <bradfitz@golang.org>
Wed, 1 Aug 2018 19:48:58 +0000 (19:48 +0000)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 1 Aug 2018 20:05:31 +0000 (20:05 +0000)
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: Andrew Bonventre <andybons@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/vendor/golang_org/x/net/http2/hpack/encode.go
src/vendor/golang_org/x/net/http2/hpack/hpack.go
src/vendor/golang_org/x/net/http2/hpack/hpack_test.go
src/vendor/golang_org/x/net/http2/hpack/huffman.go
src/vendor/golang_org/x/net/http2/hpack/tables.go

index 54726c2a3c521e6a636cdde32b96e1dbda76b9ca..1565cf2702d27ac4e614d3747c92ef8f267457ad 100644 (file)
@@ -206,7 +206,7 @@ func appendVarInt(dst []byte, n byte, i uint64) []byte {
 }
 
 // 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
 // shorter byte string.
index 176644acdaceca5cc935e263598ee4155623a312..166788ceec5e84f0c1dd5245f9bb042e40d88dad 100644 (file)
@@ -389,6 +389,12 @@ func (d *Decoder) callEmit(hf HeaderField) error {
 
 // (same invariants and behavior as parseHeaderFieldRepr)
 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
        size, buf, err := readVarInt(5, buf)
        if err != nil {
index bc7f4767822e7ad404b9d080ae82ce1325fd3fba..3f2227442a985319e1f7eeceb9ba4fe7687da148 100644 (file)
@@ -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) {
        tests := []struct {
                in, want string
@@ -720,3 +741,22 @@ func TestSaveBufLimit(t *testing.T) {
                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")
+       }
+}
index 8850e3946770ea09203ddb3ea15d4c818e5eeea0..b412a96c5043b1b96e217fa534cd82daa052f549 100644 (file)
@@ -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
 // maxLen bytes will return ErrStringLength.
 func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
+       rootHuffmanNode := getRootHuffmanNode()
        n := rootHuffmanNode
        // 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.
@@ -106,7 +107,7 @@ func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
 
 type node struct {
        // children is non-nil for internal nodes
-       children []*node
+       children *[256]*node
 
        // The following are only valid if children is nil:
        codeLen uint8 // number of bits that led to the output of sym
@@ -114,22 +115,31 @@ type node struct {
 }
 
 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 {
                panic("unexpected size")
        }
+       lazyRootHuffmanNode = newInternalNode()
        for i, code := range huffmanCodes {
                addDecoderNode(byte(i), code, huffmanCodeLen[i])
        }
 }
 
 func addDecoderNode(sym byte, code uint32, codeLen uint8) {
-       cur := rootHuffmanNode
+       cur := lazyRootHuffmanNode
        for codeLen > 8 {
                codeLen -= 8
                i := uint8(code >> codeLen)
index 8bd975d388d6f64c808373ab1aea4ea91acf1ad9..a66cfbea69d91145413a42c4772fb332360b1be6 100644 (file)
@@ -128,67 +128,67 @@ func (t *headerFieldTable) idToIndex(id uint64) uint64 {
 // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
 var staticTable = newStaticTable()
 var staticTableEntries = [...]HeaderField{
-       HeaderField{Name: ":authority"},
-       HeaderField{Name: ":method", Value: "GET"},
-       HeaderField{Name: ":method", Value: "POST"},
-       HeaderField{Name: ":path", Value: "/"},
-       HeaderField{Name: ":path", Value: "/index.html"},
-       HeaderField{Name: ":scheme", Value: "http"},
-       HeaderField{Name: ":scheme", Value: "https"},
-       HeaderField{Name: ":status", Value: "200"},
-       HeaderField{Name: ":status", Value: "204"},
-       HeaderField{Name: ":status", Value: "206"},
-       HeaderField{Name: ":status", Value: "304"},
-       HeaderField{Name: ":status", Value: "400"},
-       HeaderField{Name: ":status", Value: "404"},
-       HeaderField{Name: ":status", Value: "500"},
-       HeaderField{Name: "accept-charset"},
-       HeaderField{Name: "accept-encoding", Value: "gzip, deflate"},
-       HeaderField{Name: "accept-language"},
-       HeaderField{Name: "accept-ranges"},
-       HeaderField{Name: "accept"},
-       HeaderField{Name: "access-control-allow-origin"},
-       HeaderField{Name: "age"},
-       HeaderField{Name: "allow"},
-       HeaderField{Name: "authorization"},
-       HeaderField{Name: "cache-control"},
-       HeaderField{Name: "content-disposition"},
-       HeaderField{Name: "content-encoding"},
-       HeaderField{Name: "content-language"},
-       HeaderField{Name: "content-length"},
-       HeaderField{Name: "content-location"},
-       HeaderField{Name: "content-range"},
-       HeaderField{Name: "content-type"},
-       HeaderField{Name: "cookie"},
-       HeaderField{Name: "date"},
-       HeaderField{Name: "etag"},
-       HeaderField{Name: "expect"},
-       HeaderField{Name: "expires"},
-       HeaderField{Name: "from"},
-       HeaderField{Name: "host"},
-       HeaderField{Name: "if-match"},
-       HeaderField{Name: "if-modified-since"},
-       HeaderField{Name: "if-none-match"},
-       HeaderField{Name: "if-range"},
-       HeaderField{Name: "if-unmodified-since"},
-       HeaderField{Name: "last-modified"},
-       HeaderField{Name: "link"},
-       HeaderField{Name: "location"},
-       HeaderField{Name: "max-forwards"},
-       HeaderField{Name: "proxy-authenticate"},
-       HeaderField{Name: "proxy-authorization"},
-       HeaderField{Name: "range"},
-       HeaderField{Name: "referer"},
-       HeaderField{Name: "refresh"},
-       HeaderField{Name: "retry-after"},
-       HeaderField{Name: "server"},
-       HeaderField{Name: "set-cookie"},
-       HeaderField{Name: "strict-transport-security"},
-       HeaderField{Name: "transfer-encoding"},
-       HeaderField{Name: "user-agent"},
-       HeaderField{Name: "vary"},
-       HeaderField{Name: "via"},
-       HeaderField{Name: "www-authenticate"},
+       {Name: ":authority"},
+       {Name: ":method", Value: "GET"},
+       {Name: ":method", Value: "POST"},
+       {Name: ":path", Value: "/"},
+       {Name: ":path", Value: "/index.html"},
+       {Name: ":scheme", Value: "http"},
+       {Name: ":scheme", Value: "https"},
+       {Name: ":status", Value: "200"},
+       {Name: ":status", Value: "204"},
+       {Name: ":status", Value: "206"},
+       {Name: ":status", Value: "304"},
+       {Name: ":status", Value: "400"},
+       {Name: ":status", Value: "404"},
+       {Name: ":status", Value: "500"},
+       {Name: "accept-charset"},
+       {Name: "accept-encoding", Value: "gzip, deflate"},
+       {Name: "accept-language"},
+       {Name: "accept-ranges"},
+       {Name: "accept"},
+       {Name: "access-control-allow-origin"},
+       {Name: "age"},
+       {Name: "allow"},
+       {Name: "authorization"},
+       {Name: "cache-control"},
+       {Name: "content-disposition"},
+       {Name: "content-encoding"},
+       {Name: "content-language"},
+       {Name: "content-length"},
+       {Name: "content-location"},
+       {Name: "content-range"},
+       {Name: "content-type"},
+       {Name: "cookie"},
+       {Name: "date"},
+       {Name: "etag"},
+       {Name: "expect"},
+       {Name: "expires"},
+       {Name: "from"},
+       {Name: "host"},
+       {Name: "if-match"},
+       {Name: "if-modified-since"},
+       {Name: "if-none-match"},
+       {Name: "if-range"},
+       {Name: "if-unmodified-since"},
+       {Name: "last-modified"},
+       {Name: "link"},
+       {Name: "location"},
+       {Name: "max-forwards"},
+       {Name: "proxy-authenticate"},
+       {Name: "proxy-authorization"},
+       {Name: "range"},
+       {Name: "referer"},
+       {Name: "refresh"},
+       {Name: "retry-after"},
+       {Name: "server"},
+       {Name: "set-cookie"},
+       {Name: "strict-transport-security"},
+       {Name: "transfer-encoding"},
+       {Name: "user-agent"},
+       {Name: "vary"},
+       {Name: "via"},
+       {Name: "www-authenticate"},
 }
 
 func newStaticTable() *headerFieldTable {