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())
})
})
|