浏览代码

http2/hpack: track the beginning of a header block

dynamic table size updates must occur at the beginning of the first
header block. The original fix, golang/go#25023, guaranteed it was at
the beginning of the very first block. The Close method implicitly
marked the end of the current header. We now document the Close behavior
and can track when we are at the beginning of the first block.

Updates golang/go#29187

Change-Id: I83ec39546527cb17d7de8a88ec417a46443d2baa
Reviewed-on: https://go-review.googlesource.com/c/153978
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Michael Fraenkel 7 年之前
父节点
当前提交
891ebc4b82
共有 2 个文件被更改,包括 20 次插入4 次删除
  1. 9 1
      http2/hpack/hpack.go
  2. 11 3
      http2/hpack/hpack_test.go

+ 9 - 1
http2/hpack/hpack.go

@@ -92,6 +92,8 @@ type Decoder struct {
 	// saveBuf is previous data passed to Write which we weren't able
 	// to fully parse before. Unlike buf, we own this data.
 	saveBuf bytes.Buffer
+
+	firstField bool // processing the first field of the header block
 }
 
 // NewDecoder returns a new decoder with the provided maximum dynamic
@@ -101,6 +103,7 @@ func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decod
 	d := &Decoder{
 		emit:        emitFunc,
 		emitEnabled: true,
+		firstField:  true,
 	}
 	d.dynTab.table.init()
 	d.dynTab.allowedMaxSize = maxDynamicTableSize
@@ -226,11 +229,15 @@ func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
 	return hf, 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 (d *Decoder) Close() error {
 	if d.saveBuf.Len() > 0 {
 		d.saveBuf.Reset()
 		return DecodingError{errors.New("truncated headers")}
 	}
+	d.firstField = true
 	return nil
 }
 
@@ -266,6 +273,7 @@ func (d *Decoder) Write(p []byte) (n int, err error) {
 			d.saveBuf.Write(d.buf)
 			return len(p), nil
 		}
+		d.firstField = false
 		if err != nil {
 			break
 		}
@@ -391,7 +399,7 @@ func (d *Decoder) callEmit(hf HeaderField) 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 {
+	if !d.firstField && d.dynTab.size > 0 {
 		return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
 	}
 

+ 11 - 3
http2/hpack/hpack_test.go

@@ -748,14 +748,22 @@ func TestDynamicSizeUpdate(t *testing.T) {
 	enc.SetMaxDynamicTableSize(255)
 	enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
 
-	d := NewDecoder(4096, nil)
-	_, err := d.DecodeFull(buf.Bytes())
+	d := NewDecoder(4096, func(_ HeaderField) {})
+	_, err := d.Write(buf.Bytes())
+	if err != nil {
+		t.Fatalf("unexpected error: got = %v", err)
+	}
+
+	d.Close()
+
+	// Start a new header
+	_, err = d.Write(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())
+	_, err = d.Write(buf.Bytes())
 	if err == nil {
 		t.Fatalf("dynamic table size update not at the beginning of a header block")
 	}