Skip to content

Commit 92d7f93

Browse files
make it possible to encode multiple header fields
1 parent c53d8d6 commit 92d7f93

File tree

3 files changed

+106
-15
lines changed

3 files changed

+106
-15
lines changed

encoder.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66

77
// An Encoder performs QPACK encoding.
88
type Encoder struct {
9+
wrotePrefix bool
10+
911
w io.Writer
1012
buf []byte
1113
}
@@ -21,15 +23,25 @@ func NewEncoder(w io.Writer) *Encoder {
2123
// if necessary. If produced, it is done before encoding f.
2224
func (e *Encoder) WriteField(f HeaderField) error {
2325
// write the Header Block Prefix
24-
e.buf = appendVarInt(e.buf, 8, 0)
25-
e.buf = appendVarInt(e.buf, 7, 0)
26+
if !e.wrotePrefix {
27+
e.buf = appendVarInt(e.buf, 8, 0)
28+
e.buf = appendVarInt(e.buf, 7, 0)
29+
e.wrotePrefix = true
30+
}
2631

2732
e.writeLiteralFieldWithoutNameReference(f)
2833
e.w.Write(e.buf)
2934
e.buf = e.buf[:0]
3035
return nil
3136
}
3237

38+
// Close declares that the encoding is complete and resets the Encoder
39+
// to be reused again for a new header block.
40+
func (e *Encoder) Close() error {
41+
e.wrotePrefix = false
42+
return nil
43+
}
44+
3345
func (e *Encoder) writeLiteralFieldWithoutNameReference(f HeaderField) {
3446
offset := len(e.buf)
3547
e.buf = appendVarInt(e.buf, 3, uint64(len(f.Name)))

encoder_test.go

Lines changed: 52 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,24 +27,64 @@ var _ = Describe("Encoder", func() {
2727
return
2828
}
2929

30-
It("encodes", func() {
30+
checkHeaderField := func(data []byte, hf HeaderField) []byte {
31+
Expect(data[0] & (0x80 ^ 0x40 ^ 0x20)).To(Equal(uint8(0x20))) // 001xxxxx
32+
Expect(data[0] & 0x8).To(BeZero()) // no Huffman encoding
33+
nameLen, data, err := readVarInt(3, data)
34+
Expect(err).ToNot(HaveOccurred())
35+
Expect(nameLen).To(BeEquivalentTo(len(hf.Name)))
36+
Expect(string(data[:len(hf.Name)])).To(Equal(hf.Name))
37+
valueLen, data, err := readVarInt(7, data[len(hf.Name):])
38+
Expect(err).ToNot(HaveOccurred())
39+
Expect(valueLen).To(BeEquivalentTo(len(hf.Value)))
40+
Expect(string(data[:len(hf.Value)])).To(Equal(hf.Value))
41+
return data[len(hf.Value):]
42+
}
43+
44+
It("encodes a single field", func() {
3145
hf := HeaderField{Name: "foobar", Value: "lorem ipsum"}
3246
Expect(encoder.WriteField(hf)).To(Succeed())
3347

3448
data, requiredInsertCount, deltaBase := readPrefix(output.Bytes())
3549
Expect(requiredInsertCount).To(BeZero())
3650
Expect(deltaBase).To(BeZero())
3751

38-
Expect(data[0] & (0x80 ^ 0x40 ^ 0x20)).To(Equal(uint8(0x20))) // 001xxxxx
39-
Expect(data[0] & 0x8).To(BeZero()) // no Huffman encoding
40-
nameLen, data, err := readVarInt(3, data)
41-
Expect(err).ToNot(HaveOccurred())
42-
Expect(nameLen).To(BeEquivalentTo(6))
43-
Expect(string(data[:6])).To(Equal("foobar"))
44-
valueLen, data, err := readVarInt(7, data[6:])
45-
Expect(err).ToNot(HaveOccurred())
46-
Expect(valueLen).To(BeEquivalentTo(11))
47-
Expect(string(data[:11])).To(Equal("lorem ipsum"))
48-
Expect(data[11:]).To(BeEmpty())
52+
data = checkHeaderField(data, hf)
53+
Expect(data).To(BeEmpty())
54+
})
55+
56+
It("encodes multipe fields", func() {
57+
hf1 := HeaderField{Name: "foobar", Value: "lorem ipsum"}
58+
hf2 := HeaderField{Name: "raboof", Value: "dolor sit amet"}
59+
Expect(encoder.WriteField(hf1)).To(Succeed())
60+
Expect(encoder.WriteField(hf2)).To(Succeed())
61+
62+
data, requiredInsertCount, deltaBase := readPrefix(output.Bytes())
63+
Expect(requiredInsertCount).To(BeZero())
64+
Expect(deltaBase).To(BeZero())
65+
66+
data = checkHeaderField(data, hf1)
67+
data = checkHeaderField(data, hf2)
68+
Expect(data).To(BeEmpty())
69+
})
70+
71+
It("encodes multiple requests", func() {
72+
hf1 := HeaderField{Name: "foobar", Value: "lorem ipsum"}
73+
Expect(encoder.WriteField(hf1)).To(Succeed())
74+
data, requiredInsertCount, deltaBase := readPrefix(output.Bytes())
75+
Expect(requiredInsertCount).To(BeZero())
76+
Expect(deltaBase).To(BeZero())
77+
data = checkHeaderField(data, hf1)
78+
Expect(data).To(BeEmpty())
79+
80+
output.Reset()
81+
Expect(encoder.Close())
82+
hf2 := HeaderField{Name: "raboof", Value: "dolor sit amet"}
83+
Expect(encoder.WriteField(hf2)).To(Succeed())
84+
data, requiredInsertCount, deltaBase = readPrefix(output.Bytes())
85+
Expect(requiredInsertCount).To(BeZero())
86+
Expect(deltaBase).To(BeZero())
87+
data = checkHeaderField(data, hf2)
88+
Expect(data).To(BeEmpty())
4989
})
5090
})

integrationtests/self/integration_test.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,50 @@ var _ = Describe("Self Tests", func() {
2828
})
2929
})
3030

31-
It("encodes and decodes a single header", func() {
31+
It("encodes and decodes a single header field", func() {
3232
hf := qpack.HeaderField{Name: "foo", Value: "bar"}
3333
Expect(encoder.WriteField(hf)).To(Succeed())
3434
_, err := decoder.Write(output.Bytes())
3535
Expect(err).ToNot(HaveOccurred())
3636
Expect(headerFields).To(Equal([]qpack.HeaderField{hf}))
3737
})
38+
39+
It("encodes and decodes multiple header fields", func() {
40+
hfs := []qpack.HeaderField{
41+
{Name: "foo", Value: "bar"},
42+
{Name: "lorem", Value: "ipsum"},
43+
{Name: "name", Value: "value"},
44+
}
45+
for _, hf := range hfs {
46+
Expect(encoder.WriteField(hf)).To(Succeed())
47+
}
48+
_, err := decoder.Write(output.Bytes())
49+
Expect(err).ToNot(HaveOccurred())
50+
Expect(headerFields).To(Equal(hfs))
51+
})
52+
53+
It("encodes and decodes multiple requests", func() {
54+
hfs1 := []qpack.HeaderField{{Name: "foo", Value: "bar"}}
55+
hfs2 := []qpack.HeaderField{
56+
{Name: "lorem", Value: "ipsum"},
57+
{Name: "name", Value: "value"},
58+
}
59+
for _, hf := range hfs1 {
60+
Expect(encoder.WriteField(hf)).To(Succeed())
61+
}
62+
req1 := append([]byte{}, output.Bytes()...)
63+
output.Reset()
64+
for _, hf := range hfs2 {
65+
Expect(encoder.WriteField(hf)).To(Succeed())
66+
}
67+
req2 := append([]byte{}, output.Bytes()...)
68+
69+
_, err := decoder.Write(req1)
70+
Expect(err).ToNot(HaveOccurred())
71+
Expect(headerFields).To(Equal(hfs1))
72+
headerFields = nil
73+
_, err = decoder.Write(req2)
74+
Expect(err).ToNot(HaveOccurred())
75+
Expect(headerFields).To(Equal(hfs2))
76+
})
3877
})

0 commit comments

Comments
 (0)