1
2
3
4
5 package http3
6
7 import (
8 "encoding/binary"
9 "errors"
10 "io"
11 "math"
12
13 "golang.org/x/net/http/httpguts"
14 "golang.org/x/net/http2/hpack"
15 )
16
17
18
19
20
21
22
23
24
25 type tableType byte
26
27 const (
28 dynamicTable = 0x00
29 staticTable = 0xff
30 )
31
32
33
34 func tableTypeForTbit(bit byte) tableType {
35 if bit == 0 {
36 return dynamicTable
37 }
38 return staticTable
39 }
40
41
42
43
44 func (t tableType) tbit(bit byte) byte {
45 return bit & byte(t)
46 }
47
48
49
50
51
52
53
54
55
56 type indexType byte
57
58 const (
59 mayIndex = 0x00
60 neverIndex = 0xff
61 )
62
63
64
65 func indexTypeForNBit(bit byte) indexType {
66 if bit == 0 {
67 return mayIndex
68 }
69 return neverIndex
70 }
71
72
73
74
75 func (t indexType) nbit(bit byte) byte {
76 return bit & byte(t)
77 }
78
79
80
81
82
83
84
85
86
87
88 func appendIndexedFieldLine(b []byte, ttype tableType, index int) []byte {
89 const tbit = 0b_01000000
90 return appendPrefixedInt(b, 0b_1000_0000|ttype.tbit(tbit), 6, int64(index))
91 }
92
93 func (st *stream) decodeIndexedFieldLine(b byte) (itype indexType, name, value string, err error) {
94 index, err := st.readPrefixedIntWithByte(b, 6)
95 if err != nil {
96 return 0, "", "", err
97 }
98 const tbit = 0b_0100_0000
99 if tableTypeForTbit(b&tbit) == staticTable {
100 ent, err := staticTableEntry(index)
101 if err != nil {
102 return 0, "", "", err
103 }
104 return mayIndex, ent.name, ent.value, nil
105 } else {
106 return 0, "", "", errors.New("dynamic table is not supported yet")
107 }
108 }
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 func appendLiteralFieldLineWithNameReference(b []byte, ttype tableType, itype indexType, nameIndex int, value string) []byte {
124 const tbit = 0b_0001_0000
125 const nbit = 0b_0010_0000
126 b = appendPrefixedInt(b, 0b_0100_0000|itype.nbit(nbit)|ttype.tbit(tbit), 4, int64(nameIndex))
127 b = appendPrefixedString(b, 0, 7, value)
128 return b
129 }
130
131 func (st *stream) decodeLiteralFieldLineWithNameReference(b byte) (itype indexType, name, value string, err error) {
132 nameIndex, err := st.readPrefixedIntWithByte(b, 4)
133 if err != nil {
134 return 0, "", "", err
135 }
136
137 const tbit = 0b_0001_0000
138 if tableTypeForTbit(b&tbit) == staticTable {
139 ent, err := staticTableEntry(nameIndex)
140 if err != nil {
141 return 0, "", "", err
142 }
143 name = ent.name
144 } else {
145 return 0, "", "", errors.New("dynamic table is not supported yet")
146 }
147
148 _, value, err = st.readPrefixedString(7)
149 if err != nil {
150 return 0, "", "", err
151 }
152
153 const nbit = 0b_0010_0000
154 itype = indexTypeForNBit(b & nbit)
155
156 return itype, name, value, nil
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 func appendLiteralFieldLineWithLiteralName(b []byte, itype indexType, name, value string) []byte {
175 const nbit = 0b_0001_0000
176 b = appendPrefixedString(b, 0b_0010_0000|itype.nbit(nbit), 3, name)
177 b = appendPrefixedString(b, 0, 7, value)
178 return b
179 }
180
181 func (st *stream) decodeLiteralFieldLineWithLiteralName(b byte) (itype indexType, name, value string, err error) {
182 name, err = st.readPrefixedStringWithByte(b, 3)
183 if err != nil {
184 return 0, "", "", err
185 }
186 _, value, err = st.readPrefixedString(7)
187 if err != nil {
188 return 0, "", "", err
189 }
190 const nbit = 0b_0001_0000
191 itype = indexTypeForNBit(b & nbit)
192 return itype, name, value, nil
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219 func (st *stream) readPrefixedInt(prefixLen uint8) (firstByte byte, v int64, err error) {
220 firstByte, err = st.ReadByte()
221 if err != nil {
222 return 0, 0, errQPACKDecompressionFailed
223 }
224 v, err = st.readPrefixedIntWithByte(firstByte, prefixLen)
225 return firstByte, v, err
226 }
227
228
229
230 func (st *stream) readPrefixedIntWithByte(firstByte byte, prefixLen uint8) (int64, error) {
231 prefixMask := (byte(1) << prefixLen) - 1
232 if v := firstByte & prefixMask; v != prefixMask {
233 return int64(v), nil
234 }
235 v, err := binary.ReadUvarint(st)
236 if err != nil {
237 return 0, errQPACKDecompressionFailed
238 }
239 if v > math.MaxInt64-uint64(prefixMask) {
240 return 0, errQPACKDecompressionFailed
241 }
242 return int64(v + uint64(prefixMask)), nil
243 }
244
245
246
247
248
249 func appendPrefixedInt(b []byte, firstByte byte, prefixLen uint8, i int64) []byte {
250 u := uint64(i)
251 prefixMask := (uint64(1) << prefixLen) - 1
252 if u < prefixMask {
253 return append(b, firstByte|byte(u))
254 }
255 b = append(b, firstByte|byte(prefixMask))
256 u -= prefixMask
257 return binary.AppendUvarint(b, u)
258 }
259
260
261
262
263
264
265
266
267
268
269
270 func (st *stream) readPrefixedString(prefixLen uint8) (firstByte byte, s string, err error) {
271 firstByte, err = st.ReadByte()
272 if err != nil {
273 return 0, "", errQPACKDecompressionFailed
274 }
275 s, err = st.readPrefixedStringWithByte(firstByte, prefixLen)
276 return firstByte, s, err
277 }
278
279
280
281 func (st *stream) readPrefixedStringWithByte(firstByte byte, prefixLen uint8) (s string, err error) {
282 size, err := st.readPrefixedIntWithByte(firstByte, prefixLen)
283 if err != nil {
284 return "", errQPACKDecompressionFailed
285 }
286 if st.lim >= 0 && size > st.lim {
287 return "", errQPACKDecompressionFailed
288 }
289
290 hbit := byte(1) << prefixLen
291 isHuffman := firstByte&hbit != 0
292
293
294 data := make([]byte, size)
295 if _, err := io.ReadFull(st, data); err != nil {
296 return "", errQPACKDecompressionFailed
297 }
298 if isHuffman {
299
300
301
302 s, err := hpack.HuffmanDecodeToString(data)
303 if err != nil {
304 return "", errQPACKDecompressionFailed
305 }
306 return s, nil
307 }
308 return string(data), nil
309 }
310
311
312
313
314
315
316
317 func appendPrefixedString(b []byte, firstByte byte, prefixLen uint8, s string) []byte {
318 huffmanLen := hpack.HuffmanEncodeLength(s)
319 if huffmanLen < uint64(len(s)) {
320 hbit := byte(1) << prefixLen
321 b = appendPrefixedInt(b, firstByte|hbit, prefixLen, int64(huffmanLen))
322 b = hpack.AppendHuffmanString(b, s)
323 } else {
324 b = appendPrefixedInt(b, firstByte, prefixLen, int64(len(s)))
325 b = append(b, s...)
326 }
327 return b
328 }
329
330
331
332
333
334
335
336
337
338 func validWireHeaderFieldName(v string) bool {
339 if len(v) == 0 {
340 return false
341 }
342 for _, r := range v {
343 if !httpguts.IsTokenRune(r) {
344 return false
345 }
346 if 'A' <= r && r <= 'Z' {
347 return false
348 }
349 }
350 return true
351 }
352
View as plain text