mirror of
https://github.com/golang/go
synced 2024-10-14 11:53:56 +00:00
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: Andrew Bonventre <andybons@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
3acd2576ab
commit
a2ef8b9c6c
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 init() {
|
||||
func getRootHuffmanNode() *node {
|
||||
buildRootOnce.Do(buildRootHuffmanNode)
|
||||
return lazyRootHuffmanNode
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
122
src/vendor/golang_org/x/net/http2/hpack/tables.go
vendored
122
src/vendor/golang_org/x/net/http2/hpack/tables.go
vendored
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue