File: encoder_test.go

package info (click to toggle)
golang-github-marten-seemann-qpack 0.2.1%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 192 kB
  • sloc: sh: 63; makefile: 3
file content (152 lines) | stat: -rw-r--r-- 5,008 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package qpack

import (
	"bytes"

	"golang.org/x/net/http2/hpack"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Encoder", func() {
	var (
		encoder *Encoder
		output  *bytes.Buffer
	)

	BeforeEach(func() {
		output = &bytes.Buffer{}
		encoder = NewEncoder(output)
	})

	readPrefix := func(data []byte) (rest []byte, requiredInsertCount uint64, deltaBase uint64) {
		var err error
		requiredInsertCount, rest, err = readVarInt(8, data)
		Expect(err).ToNot(HaveOccurred())
		deltaBase, rest, err = readVarInt(7, rest)
		Expect(err).ToNot(HaveOccurred())
		return
	}

	checkHeaderField := func(data []byte, hf HeaderField) []byte {
		Expect(data[0] & (0x80 ^ 0x40 ^ 0x20)).To(Equal(uint8(0x20))) // 001xxxxx
		Expect(data[0] & 0x8).ToNot(BeZero())                         // Huffman encoding
		nameLen, data, err := readVarInt(3, data)
		Expect(err).ToNot(HaveOccurred())
		l := hpack.HuffmanEncodeLength(hf.Name)
		Expect(nameLen).To(BeEquivalentTo(l))
		Expect(hpack.HuffmanDecodeToString(data[:l])).To(Equal(hf.Name))
		valueLen, data, err := readVarInt(7, data[l:])
		Expect(err).ToNot(HaveOccurred())
		l = hpack.HuffmanEncodeLength(hf.Value)
		Expect(valueLen).To(BeEquivalentTo(l))
		Expect(hpack.HuffmanDecodeToString(data[:l])).To(Equal(hf.Value))
		return data[l:]
	}

	// Reads one indexed field line representation from data and verifies it matches hf.
	// Returns the leftover bytes from data.
	checkIndexedHeaderField := func(data []byte, hf HeaderField) []byte {
		Expect(data[0] >> 7).To(Equal(uint8(1))) // 1Txxxxxx
		index, data, err := readVarInt(6, data)
		Expect(err).ToNot(HaveOccurred())
		Expect(staticTableEntries[index]).To(Equal(hf))
		return data
	}

	checkHeaderFieldWithNameRef := func(data []byte, hf HeaderField) []byte {
		// read name reference
		Expect(data[0] >> 6).To(Equal(uint8(1))) // 01NTxxxx
		index, data, err := readVarInt(4, data)
		Expect(err).ToNot(HaveOccurred())
		Expect(staticTableEntries[index].Name).To(Equal(hf.Name))
		// read literal value
		valueLen, data, err := readVarInt(7, data)
		Expect(err).ToNot(HaveOccurred())
		l := hpack.HuffmanEncodeLength(hf.Value)
		Expect(valueLen).To(BeEquivalentTo(l))
		Expect(hpack.HuffmanDecodeToString(data[:l])).To(Equal(hf.Value))
		return data[l:]
	}

	It("encodes a single field", func() {
		hf := HeaderField{Name: "foobar", Value: "lorem ipsum"}
		Expect(encoder.WriteField(hf)).To(Succeed())

		data, requiredInsertCount, deltaBase := readPrefix(output.Bytes())
		Expect(requiredInsertCount).To(BeZero())
		Expect(deltaBase).To(BeZero())

		data = checkHeaderField(data, hf)
		Expect(data).To(BeEmpty())
	})

	It("encodes multiple fields", func() {
		hf1 := HeaderField{Name: "foobar", Value: "lorem ipsum"}
		hf2 := HeaderField{Name: "raboof", Value: "dolor sit amet"}
		Expect(encoder.WriteField(hf1)).To(Succeed())
		Expect(encoder.WriteField(hf2)).To(Succeed())

		data, requiredInsertCount, deltaBase := readPrefix(output.Bytes())
		Expect(requiredInsertCount).To(BeZero())
		Expect(deltaBase).To(BeZero())

		data = checkHeaderField(data, hf1)
		data = checkHeaderField(data, hf2)
		Expect(data).To(BeEmpty())
	})

	It("encodes all the fields of the static table", func() {
		for _, hf := range staticTableEntries {
			Expect(encoder.WriteField(hf)).To(Succeed())
		}

		data, requiredInsertCount, deltaBase := readPrefix(output.Bytes())
		Expect(requiredInsertCount).To(BeZero())
		Expect(deltaBase).To(BeZero())

		for _, hf := range staticTableEntries {
			data = checkIndexedHeaderField(data, hf)
		}
		Expect(data).To(BeEmpty())
	})

	It("encodes fields with name reference in the static table", func() {
		hf1 := HeaderField{Name: ":status", Value: "666"}
		hf2 := HeaderField{Name: "server", Value: "lorem ipsum"}
		hf3 := HeaderField{Name: ":method", Value: ""}
		Expect(encoder.WriteField(hf1)).To(Succeed())
		Expect(encoder.WriteField(hf2)).To(Succeed())
		Expect(encoder.WriteField(hf3)).To(Succeed())

		data, requiredInsertCount, deltaBase := readPrefix(output.Bytes())
		Expect(requiredInsertCount).To(BeZero())
		Expect(deltaBase).To(BeZero())

		data = checkHeaderFieldWithNameRef(data, hf1)
		data = checkHeaderFieldWithNameRef(data, hf2)
		data = checkHeaderFieldWithNameRef(data, hf3)
		Expect(data).To(BeEmpty())
	})

	It("encodes multiple requests", func() {
		hf1 := HeaderField{Name: "foobar", Value: "lorem ipsum"}
		Expect(encoder.WriteField(hf1)).To(Succeed())
		data, requiredInsertCount, deltaBase := readPrefix(output.Bytes())
		Expect(requiredInsertCount).To(BeZero())
		Expect(deltaBase).To(BeZero())
		data = checkHeaderField(data, hf1)
		Expect(data).To(BeEmpty())

		output.Reset()
		Expect(encoder.Close())
		hf2 := HeaderField{Name: "raboof", Value: "dolor sit amet"}
		Expect(encoder.WriteField(hf2)).To(Succeed())
		data, requiredInsertCount, deltaBase = readPrefix(output.Bytes())
		Expect(requiredInsertCount).To(BeZero())
		Expect(deltaBase).To(BeZero())
		data = checkHeaderField(data, hf2)
		Expect(data).To(BeEmpty())
	})
})