Skip to content

Commit 3200fb9

Browse files
rework Decoder API to decode header fields one by one (#67)
1 parent c3abb96 commit 3200fb9

File tree

7 files changed

+200
-316
lines changed

7 files changed

+200
-316
lines changed

decoder.go

Lines changed: 86 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
package qpack
22

33
import (
4-
"bytes"
54
"errors"
65
"fmt"
7-
"sync"
6+
"io"
87

98
"golang.org/x/net/http2/hpack"
109
)
1110

12-
// A decodingError is something the spec defines as a decoding error.
11+
// A decodingError represents a QPACK decoding error as defined by the specification
1312
type decodingError struct {
1413
err error
1514
}
@@ -18,8 +17,8 @@ func (de decodingError) Error() string {
1817
return fmt.Sprintf("decoding error: %v", de.err)
1918
}
2019

21-
// An invalidIndexError is returned when an encoder references a table
22-
// entry before the static table or after the end of the dynamic table.
20+
// An invalidIndexError is returned when decoding encounters an invalid index
21+
// (e.g., an index that is out of bounds for the static table).
2322
type invalidIndexError int
2423

2524
func (e invalidIndexError) Error() string {
@@ -28,221 +27,140 @@ func (e invalidIndexError) Error() string {
2827

2928
var errNoDynamicTable = decodingError{errors.New("no dynamic table")}
3029

31-
// errNeedMore is an internal sentinel error value that means the
32-
// buffer is truncated and we need to read more data before we can
33-
// continue parsing.
34-
var errNeedMore = errors.New("need more data")
35-
36-
// A Decoder is the decoding context for incremental processing of
37-
// header blocks.
38-
type Decoder struct {
39-
mutex sync.Mutex
40-
41-
emitFunc func(f HeaderField)
42-
43-
readRequiredInsertCount bool
44-
readDeltaBase bool
45-
46-
// buf is the unparsed buffer. It's only written to
47-
// saveBuf if it was truncated in the middle of a header
48-
// block. Because it's usually not owned, we can only
49-
// process it under Write.
50-
buf []byte // not owned; only valid during Write
51-
52-
// saveBuf is previous data passed to Write which we weren't able
53-
// to fully parse before. Unlike buf, we own this data.
54-
saveBuf bytes.Buffer
55-
}
56-
57-
// NewDecoder returns a new decoder
58-
// The emitFunc will be called for each valid field parsed,
59-
// in the same goroutine as calls to Write, before Write returns.
60-
func NewDecoder(emitFunc func(f HeaderField)) *Decoder {
61-
return &Decoder{emitFunc: emitFunc}
62-
}
63-
64-
func (d *Decoder) Write(p []byte) (int, error) {
65-
if len(p) == 0 {
66-
return 0, nil
67-
}
68-
69-
d.mutex.Lock()
70-
n, err := d.writeLocked(p)
71-
d.mutex.Unlock()
72-
return n, err
30+
// A Decoder decodes QPACK header blocks.
31+
// A Decoder can be reused to decode multiple header blocks on different streams
32+
// on the same connection (e.g., headers then trailers).
33+
// This will be useful when dynamic table support is added.
34+
type Decoder struct{}
35+
36+
// DecodeFunc is a function that decodes the next header field from a header block.
37+
// It should be called repeatedly until it returns io.EOF.
38+
// It returns io.EOF when all header fields have been decoded.
39+
// Any error other than io.EOF indicates a decoding error.
40+
type DecodeFunc func() (HeaderField, error)
41+
42+
// NewDecoder returns a new Decoder.
43+
func NewDecoder() *Decoder {
44+
return &Decoder{}
7345
}
7446

75-
func (d *Decoder) writeLocked(p []byte) (int, error) {
76-
// Only copy the data if we have to. Optimistically assume
77-
// that p will contain a complete header block.
78-
if d.saveBuf.Len() == 0 {
79-
d.buf = p
80-
} else {
81-
d.saveBuf.Write(p)
82-
d.buf = d.saveBuf.Bytes()
83-
d.saveBuf.Reset()
84-
}
85-
86-
if err := d.decode(); err != nil {
87-
if err != errNeedMore {
88-
return 0, err
47+
// Decode returns a function that decodes header fields from the given header block.
48+
// It does not copy the slice; the caller must ensure it remains valid during decoding.
49+
func (d *Decoder) Decode(p []byte) DecodeFunc {
50+
var readRequiredInsertCount bool
51+
var readDeltaBase bool
52+
53+
return func() (HeaderField, error) {
54+
if !readRequiredInsertCount {
55+
requiredInsertCount, rest, err := readVarInt(8, p)
56+
if err != nil {
57+
return HeaderField{}, err
58+
}
59+
p = rest
60+
readRequiredInsertCount = true
61+
if requiredInsertCount != 0 {
62+
return HeaderField{}, decodingError{errors.New("expected Required Insert Count to be zero")}
63+
}
8964
}
90-
// TODO: limit the size of the buffer
91-
d.saveBuf.Write(d.buf)
92-
}
93-
return len(p), nil
94-
}
95-
96-
// DecodeFull decodes an entire block.
97-
func (d *Decoder) DecodeFull(p []byte) ([]HeaderField, error) {
98-
if len(p) == 0 {
99-
return []HeaderField{}, nil
100-
}
10165

102-
d.mutex.Lock()
103-
defer d.mutex.Unlock()
104-
105-
saveFunc := d.emitFunc
106-
defer func() { d.emitFunc = saveFunc }()
107-
108-
var hf []HeaderField
109-
d.emitFunc = func(f HeaderField) { hf = append(hf, f) }
110-
if _, err := d.writeLocked(p); err != nil {
111-
return nil, err
112-
}
113-
if err := d.Close(); err != nil {
114-
return nil, err
115-
}
116-
return hf, nil
117-
}
118-
119-
// Close declares that the decoding is complete and resets the Decoder
120-
// to be reused again for a new header block. If there is any remaining
121-
// data in the decoder's buffer, Close returns an error.
122-
func (d *Decoder) Close() error {
123-
if d.saveBuf.Len() > 0 {
124-
d.saveBuf.Reset()
125-
return decodingError{errors.New("truncated headers")}
126-
}
127-
d.readRequiredInsertCount = false
128-
d.readDeltaBase = false
129-
return nil
130-
}
131-
132-
func (d *Decoder) decode() error {
133-
if !d.readRequiredInsertCount {
134-
requiredInsertCount, rest, err := readVarInt(8, d.buf)
135-
if err != nil {
136-
return err
137-
}
138-
d.readRequiredInsertCount = true
139-
if requiredInsertCount != 0 {
140-
return decodingError{errors.New("expected Required Insert Count to be zero")}
141-
}
142-
d.buf = rest
143-
}
144-
if !d.readDeltaBase {
145-
base, rest, err := readVarInt(7, d.buf)
146-
if err != nil {
147-
return err
66+
if !readDeltaBase {
67+
base, rest, err := readVarInt(7, p)
68+
if err != nil {
69+
return HeaderField{}, err
70+
}
71+
p = rest
72+
readDeltaBase = true
73+
if base != 0 {
74+
return HeaderField{}, decodingError{errors.New("expected Base to be zero")}
75+
}
14876
}
149-
d.readDeltaBase = true
150-
if base != 0 {
151-
return decodingError{errors.New("expected Base to be zero")}
77+
78+
if len(p) == 0 {
79+
return HeaderField{}, io.EOF
15280
}
153-
d.buf = rest
154-
}
155-
if len(d.buf) == 0 {
156-
return errNeedMore
157-
}
15881

159-
for len(d.buf) > 0 {
160-
b := d.buf[0]
82+
b := p[0]
83+
var hf HeaderField
84+
var rest []byte
16185
var err error
16286
switch {
163-
case b&0x80 > 0: // 1xxxxxxx
164-
err = d.parseIndexedHeaderField()
165-
case b&0xc0 == 0x40: // 01xxxxxx
166-
err = d.parseLiteralHeaderField()
167-
case b&0xe0 == 0x20: // 001xxxxx
168-
err = d.parseLiteralHeaderFieldWithoutNameReference()
87+
case (b & 0x80) > 0: // 1xxxxxxx
88+
hf, rest, err = d.parseIndexedHeaderField(p)
89+
case (b & 0xc0) == 0x40: // 01xxxxxx
90+
hf, rest, err = d.parseLiteralHeaderField(p)
91+
case (b & 0xe0) == 0x20: // 001xxxxx
92+
hf, rest, err = d.parseLiteralHeaderFieldWithoutNameReference(p)
16993
default:
17094
err = fmt.Errorf("unexpected type byte: %#x", b)
17195
}
96+
p = rest
17297
if err != nil {
173-
return err
98+
return HeaderField{}, err
17499
}
100+
return hf, nil
175101
}
176-
return nil
177102
}
178103

179-
func (d *Decoder) parseIndexedHeaderField() error {
180-
buf := d.buf
104+
func (d *Decoder) parseIndexedHeaderField(buf []byte) (_ HeaderField, rest []byte, _ error) {
181105
if buf[0]&0x40 == 0 {
182-
return errNoDynamicTable
106+
return HeaderField{}, buf, errNoDynamicTable
183107
}
184-
index, buf, err := readVarInt(6, buf)
108+
index, rest, err := readVarInt(6, buf)
185109
if err != nil {
186-
return err
110+
return HeaderField{}, buf, err
187111
}
188112
hf, ok := d.at(index)
189113
if !ok {
190-
return decodingError{invalidIndexError(index)}
114+
return HeaderField{}, buf, decodingError{invalidIndexError(index)}
191115
}
192-
d.emitFunc(hf)
193-
d.buf = buf
194-
return nil
116+
return hf, rest, nil
195117
}
196118

197-
func (d *Decoder) parseLiteralHeaderField() error {
198-
buf := d.buf
119+
func (d *Decoder) parseLiteralHeaderField(buf []byte) (_ HeaderField, rest []byte, _ error) {
199120
if buf[0]&0x10 == 0 {
200-
return errNoDynamicTable
121+
return HeaderField{}, buf, errNoDynamicTable
201122
}
202123
// We don't need to check the value of the N-bit here.
203124
// It's only relevant when re-encoding header fields,
204125
// and determines whether the header field can be added to the dynamic table.
205126
// Since we don't support the dynamic table, we can ignore it.
206-
index, buf, err := readVarInt(4, buf)
127+
index, rest, err := readVarInt(4, buf)
207128
if err != nil {
208-
return err
129+
return HeaderField{}, buf, err
209130
}
210131
hf, ok := d.at(index)
211132
if !ok {
212-
return decodingError{invalidIndexError(index)}
133+
return HeaderField{}, buf, decodingError{invalidIndexError(index)}
213134
}
135+
buf = rest
214136
if len(buf) == 0 {
215-
return errNeedMore
137+
return HeaderField{}, buf, decodingError{errors.New("truncated literal header field")}
216138
}
217139
usesHuffman := buf[0]&0x80 > 0
218-
val, buf, err := d.readString(buf, 7, usesHuffman)
140+
val, rest, err := d.readString(rest, 7, usesHuffman)
219141
if err != nil {
220-
return err
142+
return HeaderField{}, rest, err
221143
}
222144
hf.Value = val
223-
d.emitFunc(hf)
224-
d.buf = buf
225-
return nil
145+
return hf, rest, nil
226146
}
227147

228-
func (d *Decoder) parseLiteralHeaderFieldWithoutNameReference() error {
229-
buf := d.buf
148+
func (d *Decoder) parseLiteralHeaderFieldWithoutNameReference(buf []byte) (_ HeaderField, rest []byte, _ error) {
230149
usesHuffmanForName := buf[0]&0x8 > 0
231-
name, buf, err := d.readString(buf, 3, usesHuffmanForName)
150+
name, rest, err := d.readString(buf, 3, usesHuffmanForName)
232151
if err != nil {
233-
return err
152+
return HeaderField{}, rest, err
234153
}
154+
buf = rest
235155
if len(buf) == 0 {
236-
return errNeedMore
156+
return HeaderField{}, rest, decodingError{errors.New("truncated literal header field without name reference")}
237157
}
238158
usesHuffmanForVal := buf[0]&0x80 > 0
239-
val, buf, err := d.readString(buf, 7, usesHuffmanForVal)
159+
val, rest, err := d.readString(buf, 7, usesHuffmanForVal)
240160
if err != nil {
241-
return err
161+
return HeaderField{}, rest, err
242162
}
243-
d.emitFunc(HeaderField{Name: name, Value: val})
244-
d.buf = buf
245-
return nil
163+
return HeaderField{Name: name, Value: val}, rest, nil
246164
}
247165

248166
func (d *Decoder) readString(buf []byte, n uint8, usesHuffman bool) (string, []byte, error) {
@@ -251,11 +169,10 @@ func (d *Decoder) readString(buf []byte, n uint8, usesHuffman bool) (string, []b
251169
return "", nil, err
252170
}
253171
if uint64(len(buf)) < l {
254-
return "", nil, errNeedMore
172+
return "", nil, decodingError{errors.New("truncated string")}
255173
}
256174
var val string
257175
if usesHuffman {
258-
var err error
259176
val, err = hpack.HuffmanDecodeToString(buf[:l])
260177
if err != nil {
261178
return "", nil, err

0 commit comments

Comments
 (0)