Commit 891ebc4b authored by Michael Fraenkel's avatar Michael Fraenkel Committed by Brad Fitzpatrick

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/153978Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 61058699
...@@ -92,6 +92,8 @@ type Decoder struct { ...@@ -92,6 +92,8 @@ type Decoder struct {
// saveBuf is previous data passed to Write which we weren't able // saveBuf is previous data passed to Write which we weren't able
// to fully parse before. Unlike buf, we own this data. // to fully parse before. Unlike buf, we own this data.
saveBuf bytes.Buffer saveBuf bytes.Buffer
firstField bool // processing the first field of the header block
} }
// NewDecoder returns a new decoder with the provided maximum dynamic // NewDecoder returns a new decoder with the provided maximum dynamic
...@@ -101,6 +103,7 @@ func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decod ...@@ -101,6 +103,7 @@ func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decod
d := &Decoder{ d := &Decoder{
emit: emitFunc, emit: emitFunc,
emitEnabled: true, emitEnabled: true,
firstField: true,
} }
d.dynTab.table.init() d.dynTab.table.init()
d.dynTab.allowedMaxSize = maxDynamicTableSize d.dynTab.allowedMaxSize = maxDynamicTableSize
...@@ -226,11 +229,15 @@ func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) { ...@@ -226,11 +229,15 @@ func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
return hf, nil 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 { func (d *Decoder) Close() error {
if d.saveBuf.Len() > 0 { if d.saveBuf.Len() > 0 {
d.saveBuf.Reset() d.saveBuf.Reset()
return DecodingError{errors.New("truncated headers")} return DecodingError{errors.New("truncated headers")}
} }
d.firstField = true
return nil return nil
} }
...@@ -266,6 +273,7 @@ func (d *Decoder) Write(p []byte) (n int, err error) { ...@@ -266,6 +273,7 @@ func (d *Decoder) Write(p []byte) (n int, err error) {
d.saveBuf.Write(d.buf) d.saveBuf.Write(d.buf)
return len(p), nil return len(p), nil
} }
d.firstField = false
if err != nil { if err != nil {
break break
} }
...@@ -391,7 +399,7 @@ func (d *Decoder) callEmit(hf HeaderField) error { ...@@ -391,7 +399,7 @@ func (d *Decoder) callEmit(hf HeaderField) error {
func (d *Decoder) parseDynamicTableSizeUpdate() error { func (d *Decoder) parseDynamicTableSizeUpdate() error {
// RFC 7541, sec 4.2: This dynamic table size update MUST occur at the // 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. // 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")} return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
} }
......
...@@ -748,14 +748,22 @@ func TestDynamicSizeUpdate(t *testing.T) { ...@@ -748,14 +748,22 @@ func TestDynamicSizeUpdate(t *testing.T) {
enc.SetMaxDynamicTableSize(255) enc.SetMaxDynamicTableSize(255)
enc.WriteField(HeaderField{Name: "foo", Value: "bar"}) enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
d := NewDecoder(4096, nil) d := NewDecoder(4096, func(_ HeaderField) {})
_, err := d.DecodeFull(buf.Bytes()) _, 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 { if err != nil {
t.Fatalf("unexpected error: got = %v", err) t.Fatalf("unexpected error: got = %v", err)
} }
// must fail since the dynamic table update must be at the beginning // 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 { if err == nil {
t.Fatalf("dynamic table size update not at the beginning of a header block") t.Fatalf("dynamic table size update not at the beginning of a header block")
} }
......
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