Skip to content

Commit f8170ed

Browse files
Merge pull request #5 from marten-seemann/decode-full
implement DecodeFull for the decoder
2 parents 416d651 + 680a677 commit f8170ed

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

decoder.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"errors"
66
"fmt"
7+
"sync"
78

89
"golang.org/x/net/http2/hpack"
910
)
@@ -35,6 +36,8 @@ var errNeedMore = errors.New("need more data")
3536
// A Decoder is the decoding context for incremental processing of
3637
// header blocks.
3738
type Decoder struct {
39+
mutex sync.Mutex
40+
3841
emitFunc func(f HeaderField)
3942

4043
readRequiredInsertCount bool
@@ -63,6 +66,13 @@ func (d *Decoder) Write(p []byte) (int, error) {
6366
return 0, nil
6467
}
6568

69+
d.mutex.Lock()
70+
n, err := d.writeLocked(p)
71+
d.mutex.Unlock()
72+
return n, err
73+
}
74+
75+
func (d *Decoder) writeLocked(p []byte) (int, error) {
6676
// Only copy the data if we have to. Optimistically assume
6777
// that p will contain a complete header block.
6878
if d.saveBuf.Len() == 0 {
@@ -83,6 +93,29 @@ func (d *Decoder) Write(p []byte) (int, error) {
8393
return len(p), nil
8494
}
8595

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+
}
101+
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+
86119
// Close declares that the decoding is complete and resets the Decoder
87120
// to be reused again for a new header block. If there is any remaining
88121
// data in the decoder's buffer, Close returns an error.

decoder_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package qpack
22

33
import (
4+
"bytes"
5+
46
. "github.com/onsi/ginkgo"
57
. "github.com/onsi/gomega"
68
"golang.org/x/net/http2/hpack"
@@ -175,4 +177,50 @@ var _ = Describe("Decoder", func() {
175177
doPartialWrites(data)
176178
})
177179
})
180+
181+
Context("using DecodeFull", func() {
182+
It("decodes nothing", func() {
183+
data, err := NewDecoder(nil).DecodeFull([]byte{})
184+
Expect(err).ToNot(HaveOccurred())
185+
Expect(data).To(BeEmpty())
186+
})
187+
188+
It("decodes multiple entries", func() {
189+
buf := &bytes.Buffer{}
190+
enc := NewEncoder(buf)
191+
Expect(enc.WriteField(HeaderField{Name: "foo", Value: "bar"})).To(Succeed())
192+
Expect(enc.WriteField(HeaderField{Name: "lorem", Value: "ipsum"})).To(Succeed())
193+
data, err := NewDecoder(nil).DecodeFull(buf.Bytes())
194+
Expect(err).ToNot(HaveOccurred())
195+
Expect(data).To(Equal([]HeaderField{
196+
{Name: "foo", Value: "bar"},
197+
{Name: "lorem", Value: "ipsum"},
198+
}))
199+
})
200+
201+
It("returns an error if the data is incomplete", func() {
202+
buf := &bytes.Buffer{}
203+
enc := NewEncoder(buf)
204+
Expect(enc.WriteField(HeaderField{Name: "foo", Value: "bar"})).To(Succeed())
205+
_, err := NewDecoder(nil).DecodeFull(buf.Bytes()[:buf.Len()-2])
206+
Expect(err).To(MatchError("decoding error: truncated headers"))
207+
})
208+
209+
It("restores the emitFunc afterwards", func() {
210+
var emitFuncCalled bool
211+
emitFunc := func(HeaderField) {
212+
emitFuncCalled = true
213+
}
214+
decoder := NewDecoder(emitFunc)
215+
buf := &bytes.Buffer{}
216+
enc := NewEncoder(buf)
217+
Expect(enc.WriteField(HeaderField{Name: "foo", Value: "bar"})).To(Succeed())
218+
_, err := decoder.DecodeFull(buf.Bytes())
219+
Expect(err).ToNot(HaveOccurred())
220+
Expect(emitFuncCalled).To(BeFalse())
221+
_, err = decoder.Write(buf.Bytes())
222+
Expect(err).ToNot(HaveOccurred())
223+
Expect(emitFuncCalled).To(BeTrue())
224+
})
225+
})
178226
})

0 commit comments

Comments
 (0)