Skip to content

Commit 5652e3a

Browse files
Merge pull request #1 from marten-seemann/no-name-reference
implement parsing of literal header fields without name reference
2 parents 7eff25a + a311ee6 commit 5652e3a

File tree

4 files changed

+66
-19
lines changed

4 files changed

+66
-19
lines changed

decoder.go

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,12 @@ func (d *Decoder) decode() error {
7373
b := d.buf[0]
7474
var err error
7575
switch {
76-
case b&0x80 > 0:
76+
case b&0x80 > 0: // 1xxxxxxx
7777
err = d.parseIndexedHeaderField()
78-
case b&0xc0 == 0x40:
78+
case b&0xc0 == 0x40: // 01xxxxxx
7979
err = d.parseLiteralHeaderField()
80+
case b&0xe0 == 0x20: // 001xxxxx
81+
err = d.parseLiteralHeaderFieldWithoutNameReference()
8082
default:
8183
err = fmt.Errorf("unexpected type byte: %#x", d.buf[0])
8284
}
@@ -105,8 +107,7 @@ func (d *Decoder) parseIndexedHeaderField() error {
105107
}
106108

107109
func (d *Decoder) parseLiteralHeaderField() error {
108-
b := d.buf
109-
if b[0]&0x20 > 0 || b[0]&0x10 == 0 {
110+
if d.buf[0]&0x20 > 0 || d.buf[0]&0x10 == 0 {
110111
return errNoDynamicTable
111112
}
112113
index, rest, err := readVarInt(4, d.buf)
@@ -124,23 +125,56 @@ func (d *Decoder) parseLiteralHeaderField() error {
124125
return err
125126
}
126127
d.buf = rest
128+
val, err := d.parseString(l, usesHuffman)
129+
if err != nil {
130+
return err
131+
}
132+
hf.Value = val
133+
d.emitFunc(hf)
134+
return nil
135+
}
136+
137+
func (d *Decoder) parseLiteralHeaderFieldWithoutNameReference() error {
138+
usesHuffmanForName := d.buf[0]&0x8 > 0
139+
nameLen, rest, err := readVarInt(3, d.buf)
140+
if err != nil {
141+
return err
142+
}
143+
d.buf = rest
144+
name, err := d.parseString(nameLen, usesHuffmanForName)
145+
if err != nil {
146+
return err
147+
}
148+
usesHuffmanForVal := d.buf[0]&0x80 > 0
149+
valLen, rest, err := readVarInt(7, d.buf)
150+
if err != nil {
151+
return err
152+
}
153+
d.buf = rest
154+
val, err := d.parseString(valLen, usesHuffmanForVal)
155+
if err != nil {
156+
return err
157+
}
158+
d.emitFunc(HeaderField{Name: name, Value: val})
159+
return nil
160+
}
161+
162+
func (d *Decoder) parseString(l uint64, usesHuffman bool) (string, error) {
127163
if uint64(len(d.buf)) < l {
128-
return errors.New("too little data")
164+
return "", errors.New("too little data")
129165
}
130166
var val string
131167
if usesHuffman {
132168
var err error
133169
val, err = hpack.HuffmanDecodeToString(d.buf[:l])
134170
if err != nil {
135-
return err
171+
return "", err
136172
}
137173
} else {
138174
val = string(d.buf[:l])
139175
}
140176
d.buf = d.buf[l:]
141-
hf.Value = val
142-
d.emitFunc(hf)
143-
return nil
177+
return val, nil
144178
}
145179

146180
func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {

decoder_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,20 @@ var _ = Describe("Decoder", func() {
9797
Expect(err).To(MatchError(errNoDynamicTable))
9898
})
9999

100+
It("parses a literal header field without name reference", func() {
101+
data := appendVarInt(nil, 3, 3)
102+
data[0] ^= 0x20
103+
data = append(data, []byte("foo")...)
104+
data2 := appendVarInt(nil, 7, 3)
105+
data2 = append(data2, []byte("bar")...)
106+
data = append(data, data2...)
107+
_, err := decoder.Write(insertPrefix(data))
108+
Expect(err).ToNot(HaveOccurred())
109+
Expect(headerFields).To(HaveLen(1))
110+
Expect(headerFields[0].Name).To(Equal("foo"))
111+
Expect(headerFields[0].Value).To(Equal("bar"))
112+
})
113+
100114
It("rejects unknown type bytes", func() {
101115
_, err := decoder.Write(insertPrefix([]byte{0x10}))
102116
Expect(err).To(MatchError("unexpected type byte: 0x10"))

integrationtests/integrationtests_suite_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,10 @@ var qifs map[string]qif
3131
func readQIFs() {
3232
qifDir := currentDir() + "/qifs/qifs"
3333
Expect(qifDir).To(BeADirectory())
34-
var processedFirst bool
3534
filepath.Walk(qifDir, func(path string, info os.FileInfo, err error) error {
36-
if processedFirst {
37-
return nil
38-
}
3935
if info.IsDir() {
4036
return nil
4137
}
42-
processedFirst = true
4338
_, filename := filepath.Split(path)
4439
ext := filepath.Ext(filename)
4540
name := filename[:len(filename)-len(ext)]

integrationtests/interop_test.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,27 +62,31 @@ var _ = Describe("Interop", func() {
6262
filenames := findFiles()
6363
for i := range filenames {
6464
path := filenames[i]
65-
_, filename := filepath.Split(path)
65+
fpath, filename := filepath.Split(path)
66+
prettyPath := path[len(filepath.Dir(filepath.Dir(filepath.Dir(fpath))))+1:]
6667

67-
It(fmt.Sprintf("using %s", filename), func() {
68+
It(fmt.Sprintf("using %s", prettyPath), func() {
6869
qif, ok := qifs[strings.Split(filename, ".")[0]]
69-
if !ok {
70-
Skip("Skipping. No QIF file.")
71-
}
70+
Expect(ok).To(BeTrue())
7271

7372
file, err := os.Open(path)
7473
var headers []qpack.HeaderField
7574
decoder := qpack.NewDecoder(func(hf qpack.HeaderField) {
7675
headers = append(headers, hf)
7776
})
77+
var numRequests, numHeaderFields int
78+
Expect(qif.requests).ToNot(BeEmpty())
7879
for _, req := range qif.requests {
7980
Expect(err).ToNot(HaveOccurred())
8081
_, data := parseInput(file)
8182
_, err = decoder.Write(data)
8283
Expect(err).ToNot(HaveOccurred())
8384
Expect(headers).To(Equal(req.headers))
85+
numRequests++
86+
numHeaderFields += len(headers)
8487
headers = nil
8588
}
89+
fmt.Fprintf(GinkgoWriter, "Decoded %d requests containing %d header fields.\n", len(qif.requests), numHeaderFields)
8690
})
8791
}
8892
})

0 commit comments

Comments
 (0)