blob: ed39007d13e98045ffe2e0d4767f8664090c8920 [file] [log] [blame]
Willy Tarreau679790b2017-05-30 19:09:44 +02001/*
2 * HPACK decompressor (RFC7541)
3 *
4 * Copyright (C) 2014-2017 Willy Tarreau <willy@haproxy.org>
5 * Copyright (C) 2017 HAProxy Technologies
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
Willy Tarreaua1bd1fa2019-03-29 17:26:33 +010028#include <inttypes.h>
Willy Tarreau679790b2017-05-30 19:09:44 +020029#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32
Willy Tarreaub2551052020-06-09 09:07:15 +020033#include <import/ist.h>
34#include <haproxy/chunk.h>
Willy Tarreau18a194c2023-01-20 00:02:37 +010035#include <haproxy/global.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020036#include <haproxy/h2.h>
Willy Tarreaube327fa2020-06-03 09:09:57 +020037#include <haproxy/hpack-dec.h>
38#include <haproxy/hpack-huff.h>
39#include <haproxy/hpack-tbl.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020040#include <haproxy/tools.h>
Willy Tarreau679790b2017-05-30 19:09:44 +020041
Willy Tarreau679790b2017-05-30 19:09:44 +020042
43#if defined(DEBUG_HPACK)
44#define hpack_debug_printf printf
Willy Tarreauc775f832017-12-30 13:17:37 +010045#define hpack_debug_hexdump debug_hexdump
Willy Tarreau679790b2017-05-30 19:09:44 +020046#else
47#define hpack_debug_printf(...) do { } while (0)
Willy Tarreauc775f832017-12-30 13:17:37 +010048#define hpack_debug_hexdump(...) do { } while (0)
Willy Tarreau679790b2017-05-30 19:09:44 +020049#endif
50
51/* reads a varint from <raw>'s lowest <b> bits and <len> bytes max (raw included).
52 * returns the 32-bit value on success after updating raw_in and len_in. Forces
53 * len_in to (uint32_t)-1 on truncated input.
54 */
55static uint32_t get_var_int(const uint8_t **raw_in, uint32_t *len_in, int b)
56{
57 uint32_t ret = 0;
58 int len = *len_in;
59 const uint8_t *raw = *raw_in;
60 uint8_t shift = 0;
61
62 len--;
63 ret = *(raw++) & ((1 << b) - 1);
64 if (ret != (uint32_t)((1 << b) - 1))
65 goto end;
66
Willy Tarreau077d3662020-02-05 15:28:55 +010067 while (len && (*raw & 128)) {
Willy Tarreau679790b2017-05-30 19:09:44 +020068 ret += ((uint32_t)(*raw++) & 127) << shift;
69 shift += 7;
70 len--;
71 }
72
73 /* last 7 bits */
74 if (!len)
75 goto too_short;
76 len--;
77 ret += ((uint32_t)(*raw++) & 127) << shift;
78
79 end:
80 *raw_in = raw;
81 *len_in = len;
82 return ret;
83
84 too_short:
85 *len_in = (uint32_t)-1;
86 return 0;
87}
88
Willy Tarreau59a10fb2017-11-21 20:03:02 +010089/* returns the pseudo-header <idx> corresponds to among the following values :
90 * - 0 = unknown, the header's string needs to be used instead
91 * - 1 = ":authority"
92 * - 2 = ":method"
93 * - 3 = ":path"
94 * - 4 = ":scheme"
95 * - 5 = ":status"
Willy Tarreau679790b2017-05-30 19:09:44 +020096 */
97static inline int hpack_idx_to_phdr(uint32_t idx)
98{
99 if (idx > 14)
100 return 0;
101
102 idx >>= 1;
103 idx <<= 2;
104 return (0x55554321U >> idx) & 0xF;
105}
106
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100107/* If <idx> designates a static header, returns <in>. Otherwise allocates some
108 * room from chunk <store> to duplicate <in> into it and returns the string
109 * allocated there. In case of allocation failure, returns a string whose
110 * pointer is NULL.
Willy Tarreau679790b2017-05-30 19:09:44 +0200111 */
Willy Tarreau7f2a44d2018-09-17 14:07:33 +0200112static inline struct ist hpack_alloc_string(struct buffer *store, uint32_t idx,
Willy Tarreau83061a82018-07-13 11:56:34 +0200113 struct ist in)
Willy Tarreau679790b2017-05-30 19:09:44 +0200114{
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100115 struct ist out;
Willy Tarreau679790b2017-05-30 19:09:44 +0200116
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100117 if (idx < HPACK_SHT_SIZE)
118 return in;
Willy Tarreau679790b2017-05-30 19:09:44 +0200119
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100120 out.len = in.len;
121 out.ptr = chunk_newstr(store);
Tim Duesterhus7b5777d2021-03-02 18:57:28 +0100122 if (unlikely(!isttest(out)))
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100123 return out;
Willy Tarreau679790b2017-05-30 19:09:44 +0200124
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200125 if (unlikely(store->data + out.len > store->size)) {
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100126 out.ptr = NULL;
127 return out;
Willy Tarreau679790b2017-05-30 19:09:44 +0200128 }
129
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200130 store->data += out.len;
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100131 memcpy(out.ptr, in.ptr, out.len);
132 return out;
Willy Tarreau679790b2017-05-30 19:09:44 +0200133}
134
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100135/* decode an HPACK frame starting at <raw> for <len> bytes, using the dynamic
136 * headers table <dht>, produces the output into list <list> of <list_size>
137 * entries max, and uses pre-allocated buffer <tmp> for temporary storage (some
138 * list elements will point to it). Some <list> name entries may be made of a
139 * NULL pointer and a len, in which case they will designate a pseudo header
140 * index according to the values returned by hpack_idx_to_phdr() above. The
141 * number of <list> entries used is returned on success, or <0 on failure, with
142 * the opposite one of the HPACK_ERR_* codes. A last element is always zeroed
143 * and is not counted in the number of returned entries. This way the caller
144 * can use list[].n.len == 0 as a marker for the end of list.
Willy Tarreau679790b2017-05-30 19:09:44 +0200145 */
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100146int hpack_decode_frame(struct hpack_dht *dht, const uint8_t *raw, uint32_t len,
Willy Tarreau83061a82018-07-13 11:56:34 +0200147 struct http_hdr *list, int list_size,
148 struct buffer *tmp)
Willy Tarreau679790b2017-05-30 19:09:44 +0200149{
150 uint32_t idx;
151 uint32_t nlen;
152 uint32_t vlen;
153 uint8_t huff;
Willy Tarreau679790b2017-05-30 19:09:44 +0200154 struct ist name;
155 struct ist value;
Willy Tarreau679790b2017-05-30 19:09:44 +0200156 int must_index;
157 int ret;
Willy Tarreau679790b2017-05-30 19:09:44 +0200158
Willy Tarreauc775f832017-12-30 13:17:37 +0100159 hpack_debug_hexdump(stderr, "[HPACK-DEC] ", (const char *)raw, 0, len);
160
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100161 chunk_reset(tmp);
162 ret = 0;
Willy Tarreau679790b2017-05-30 19:09:44 +0200163 while (len) {
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100164 int __maybe_unused code = *raw; /* first byte, only for debugging */
Willy Tarreau679790b2017-05-30 19:09:44 +0200165
166 must_index = 0;
167 if (*raw >= 0x80) {
168 /* indexed header field */
169 if (*raw == 0x80) {
170 hpack_debug_printf("unhandled code 0x%02x (raw=%p, len=%d)\n", *raw, raw, len);
171 ret = -HPACK_ERR_UNKNOWN_OPCODE;
172 goto leave;
173 }
174
175 hpack_debug_printf("%02x: p14: indexed header field : ", code);
176
177 idx = get_var_int(&raw, &len, 7);
178 if (len == (uint32_t)-1) { // truncated
Willy Tarreauc775f832017-12-30 13:17:37 +0100179 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau679790b2017-05-30 19:09:44 +0200180 ret = -HPACK_ERR_TRUNCATED;
181 goto leave;
182 }
183
Willy Tarreauc775f832017-12-30 13:17:37 +0100184 hpack_debug_printf(" idx=%u ", idx);
185
Willy Tarreaud85ba4e2017-12-03 12:12:17 +0100186 if (!hpack_valid_idx(dht, idx)) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100187 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreaud85ba4e2017-12-03 12:12:17 +0100188 ret = -HPACK_ERR_TOO_LARGE;
189 goto leave;
190 }
191
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100192 value = hpack_alloc_string(tmp, idx, hpack_idx_to_value(dht, idx));
Tim Duesterhused526372020-03-05 17:56:33 +0100193 if (!isttest(value)) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100194 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100195 ret = -HPACK_ERR_TOO_LARGE;
196 goto leave;
197 }
Willy Tarreau679790b2017-05-30 19:09:44 +0200198
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100199 /* here we don't index so we can always keep the pseudo header number */
200 name = ist2(NULL, hpack_idx_to_phdr(idx));
Willy Tarreau679790b2017-05-30 19:09:44 +0200201
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100202 if (!name.len) {
203 name = hpack_alloc_string(tmp, idx, hpack_idx_to_name(dht, idx));
Tim Duesterhused526372020-03-05 17:56:33 +0100204 if (!isttest(name)) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100205 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100206 ret = -HPACK_ERR_TOO_LARGE;
207 goto leave;
208 }
209 }
210 /* <name> and <value> are now set and point to stable values */
Willy Tarreau679790b2017-05-30 19:09:44 +0200211 }
212 else if (*raw >= 0x20 && *raw <= 0x3f) {
213 /* max dyn table size change */
Willy Tarreauc775f832017-12-30 13:17:37 +0100214 hpack_debug_printf("%02x: p18: dynamic table size update : ", code);
215
Willy Tarreauc611e662017-12-03 18:09:21 +0100216 if (ret) {
217 /* 7541#4.2.1 : DHT size update must only be at the beginning */
Willy Tarreauc775f832017-12-30 13:17:37 +0100218 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreauc611e662017-12-03 18:09:21 +0100219 ret = -HPACK_ERR_TOO_LARGE;
220 goto leave;
221 }
222
Willy Tarreau679790b2017-05-30 19:09:44 +0200223 idx = get_var_int(&raw, &len, 5);
224 if (len == (uint32_t)-1) { // truncated
Willy Tarreauc775f832017-12-30 13:17:37 +0100225 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau679790b2017-05-30 19:09:44 +0200226 ret = -HPACK_ERR_TRUNCATED;
227 goto leave;
228 }
Willy Tarreauc775f832017-12-30 13:17:37 +0100229 hpack_debug_printf(" new len=%u\n", idx);
Willy Tarreau1e7d4442019-01-24 10:47:10 +0100230
231 if (idx > dht->size) {
232 hpack_debug_printf("##ERR@%d##\n", __LINE__);
233 ret = -HPACK_ERR_INVALID_ARGUMENT;
234 goto leave;
235 }
Willy Tarreau679790b2017-05-30 19:09:44 +0200236 continue;
237 }
238 else if (!(*raw & (*raw - 0x10))) {
239 /* 0x00, 0x10, and 0x40 (0x20 and 0x80 were already handled above) */
240
241 /* literal header field without/never/with incremental indexing -- literal name */
242 if (*raw == 0x00)
243 hpack_debug_printf("%02x: p17: literal without indexing : ", code);
244 else if (*raw == 0x10)
245 hpack_debug_printf("%02x: p18: literal never indexed : ", code);
246 else if (*raw == 0x40)
247 hpack_debug_printf("%02x: p16: literal with indexing : ", code);
248
249 if (*raw == 0x40)
250 must_index = 1;
251
252 raw++; len--;
253
254 /* retrieve name */
255 if (!len) { // truncated
Willy Tarreauc775f832017-12-30 13:17:37 +0100256 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau679790b2017-05-30 19:09:44 +0200257 ret = -HPACK_ERR_TRUNCATED;
258 goto leave;
259 }
260
261 huff = *raw & 0x80;
262 nlen = get_var_int(&raw, &len, 7);
263 if (len == (uint32_t)-1 || len < nlen) { // truncated
Willy Tarreauc775f832017-12-30 13:17:37 +0100264 hpack_debug_printf("##ERR@%d## (truncated): nlen=%d len=%d\n",
265 __LINE__, (int)nlen, (int)len);
Willy Tarreau679790b2017-05-30 19:09:44 +0200266 ret = -HPACK_ERR_TRUNCATED;
267 goto leave;
268 }
269
270 name = ist2(raw, nlen);
271
272 raw += nlen;
273 len -= nlen;
Willy Tarreau679790b2017-05-30 19:09:44 +0200274
275 if (huff) {
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100276 char *ntrash = chunk_newstr(tmp);
277 if (!ntrash) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100278 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100279 ret = -HPACK_ERR_TOO_LARGE;
280 goto leave;
281 }
282
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200283 nlen = huff_dec((const uint8_t *)name.ptr, name.len, ntrash,
284 tmp->size - tmp->data);
Willy Tarreau679790b2017-05-30 19:09:44 +0200285 if (nlen == (uint32_t)-1) {
286 hpack_debug_printf("2: can't decode huffman.\n");
287 ret = -HPACK_ERR_HUFFMAN;
288 goto leave;
289 }
Willy Tarreauc775f832017-12-30 13:17:37 +0100290 hpack_debug_printf(" [name huff %d->%d] ", (int)name.len, (int)nlen);
291
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200292 tmp->data += nlen; // make room for the value
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100293 name = ist2(ntrash, nlen);
Willy Tarreau679790b2017-05-30 19:09:44 +0200294 }
295
296 /* retrieve value */
297 if (!len) { // truncated
Willy Tarreauc775f832017-12-30 13:17:37 +0100298 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau679790b2017-05-30 19:09:44 +0200299 ret = -HPACK_ERR_TRUNCATED;
300 goto leave;
301 }
302
303 huff = *raw & 0x80;
304 vlen = get_var_int(&raw, &len, 7);
305 if (len == (uint32_t)-1 || len < vlen) { // truncated
Willy Tarreauc775f832017-12-30 13:17:37 +0100306 hpack_debug_printf("##ERR@%d## : vlen=%d len=%d\n",
307 __LINE__, (int)vlen, (int)len);
Willy Tarreau679790b2017-05-30 19:09:44 +0200308 ret = -HPACK_ERR_TRUNCATED;
309 goto leave;
310 }
311
312 value = ist2(raw, vlen);
313 raw += vlen;
314 len -= vlen;
315
316 if (huff) {
317 char *vtrash = chunk_newstr(tmp);
318 if (!vtrash) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100319 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100320 ret = -HPACK_ERR_TOO_LARGE;
Willy Tarreau679790b2017-05-30 19:09:44 +0200321 goto leave;
322 }
323
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200324 vlen = huff_dec((const uint8_t *)value.ptr, value.len, vtrash,
325 tmp->size - tmp->data);
Willy Tarreau679790b2017-05-30 19:09:44 +0200326 if (vlen == (uint32_t)-1) {
327 hpack_debug_printf("3: can't decode huffman.\n");
328 ret = -HPACK_ERR_HUFFMAN;
329 goto leave;
330 }
Willy Tarreauc775f832017-12-30 13:17:37 +0100331 hpack_debug_printf(" [value huff %d->%d] ", (int)value.len, (int)vlen);
332
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200333 tmp->data += vlen; // make room for the value
Willy Tarreau679790b2017-05-30 19:09:44 +0200334 value = ist2(vtrash, vlen);
335 }
336
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100337 /* <name> and <value> are correctly filled here */
Willy Tarreau679790b2017-05-30 19:09:44 +0200338 }
339 else {
340 /* 0x01..0x0f : literal header field without indexing -- indexed name */
341 /* 0x11..0x1f : literal header field never indexed -- indexed name */
342 /* 0x41..0x7f : literal header field with incremental indexing -- indexed name */
343
344 if (*raw <= 0x0f)
345 hpack_debug_printf("%02x: p16: literal without indexing -- indexed name : ", code);
346 else if (*raw >= 0x41)
347 hpack_debug_printf("%02x: p15: literal with indexing -- indexed name : ", code);
348 else
349 hpack_debug_printf("%02x: p16: literal never indexed -- indexed name : ", code);
350
351 /* retrieve name index */
352 if (*raw >= 0x41) {
353 must_index = 1;
354 idx = get_var_int(&raw, &len, 6);
355 }
356 else
357 idx = get_var_int(&raw, &len, 4);
358
Willy Tarreauc775f832017-12-30 13:17:37 +0100359 hpack_debug_printf(" idx=%u ", idx);
360
Willy Tarreau679790b2017-05-30 19:09:44 +0200361 if (len == (uint32_t)-1 || !len) { // truncated
Willy Tarreauc775f832017-12-30 13:17:37 +0100362 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau679790b2017-05-30 19:09:44 +0200363 ret = -HPACK_ERR_TRUNCATED;
364 goto leave;
365 }
366
Willy Tarreaud85ba4e2017-12-03 12:12:17 +0100367 if (!hpack_valid_idx(dht, idx)) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100368 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreaud85ba4e2017-12-03 12:12:17 +0100369 ret = -HPACK_ERR_TOO_LARGE;
370 goto leave;
371 }
372
Willy Tarreau679790b2017-05-30 19:09:44 +0200373 /* retrieve value */
374 huff = *raw & 0x80;
375 vlen = get_var_int(&raw, &len, 7);
376 if (len == (uint32_t)-1 || len < vlen) { // truncated
Willy Tarreauc775f832017-12-30 13:17:37 +0100377 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau679790b2017-05-30 19:09:44 +0200378 ret = -HPACK_ERR_TRUNCATED;
379 goto leave;
380 }
381
382 value = ist2(raw, vlen);
383 raw += vlen;
384 len -= vlen;
385
386 if (huff) {
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100387 char *vtrash = chunk_newstr(tmp);
388 if (!vtrash) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100389 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100390 ret = -HPACK_ERR_TOO_LARGE;
391 goto leave;
392 }
393
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200394 vlen = huff_dec((const uint8_t *)value.ptr, value.len, vtrash,
395 tmp->size - tmp->data);
Willy Tarreau679790b2017-05-30 19:09:44 +0200396 if (vlen == (uint32_t)-1) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100397 hpack_debug_printf("##ERR@%d## can't decode huffman : ilen=%d osize=%d\n",
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200398 __LINE__, (int)value.len,
399 (int)(tmp->size - tmp->data));
Willy Tarreauc775f832017-12-30 13:17:37 +0100400 hpack_debug_hexdump(stderr, "[HUFFMAN] ", value.ptr, 0, value.len);
Willy Tarreau679790b2017-05-30 19:09:44 +0200401 ret = -HPACK_ERR_HUFFMAN;
402 goto leave;
403 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200404 tmp->data += vlen; // make room for the value
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100405 value = ist2(vtrash, vlen);
Willy Tarreau679790b2017-05-30 19:09:44 +0200406 }
407
Tim Duesterhus241e29e2020-03-05 17:56:30 +0100408 name = IST_NULL;
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100409 if (!must_index)
410 name.len = hpack_idx_to_phdr(idx);
Willy Tarreau679790b2017-05-30 19:09:44 +0200411
Willy Tarreaubb39b492017-12-30 16:56:28 +0100412 if (!name.len) {
413 name = hpack_alloc_string(tmp, idx, hpack_idx_to_name(dht, idx));
Tim Duesterhused526372020-03-05 17:56:33 +0100414 if (!isttest(name)) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100415 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreaubb39b492017-12-30 16:56:28 +0100416 ret = -HPACK_ERR_TOO_LARGE;
417 goto leave;
418 }
419 }
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100420 /* <name> and <value> are correctly filled here */
Willy Tarreau679790b2017-05-30 19:09:44 +0200421 }
Willy Tarreau679790b2017-05-30 19:09:44 +0200422
Willy Tarreau486cd732023-02-09 21:36:54 +0100423 /* We must not accept empty header names (forbidden by the spec and used
424 * as a list termination).
425 */
426 if (!name.len) {
427 hpack_debug_printf("##ERR@%d##\n", __LINE__);
428 ret = -HPACK_ERR_INVALID_ARGUMENT;
429 goto leave;
430 }
431
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100432 /* here's what we have here :
433 * - name.len > 0
434 * - value is filled with either const data or data allocated from tmp
435 * - name.ptr == NULL && !must_index : known pseudo-header #name.len
436 * - name.ptr != NULL || must_index : general header, unknown pseudo-header or index needed
437 */
438 if (ret >= list_size) {
Willy Tarreauc775f832017-12-30 13:17:37 +0100439 hpack_debug_printf("##ERR@%d##\n", __LINE__);
Willy Tarreau679790b2017-05-30 19:09:44 +0200440 ret = -HPACK_ERR_TOO_LARGE;
441 goto leave;
442 }
443
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100444 list[ret].n = name;
445 list[ret].v = value;
446 ret++;
Willy Tarreau679790b2017-05-30 19:09:44 +0200447
448 if (must_index && hpack_dht_insert(dht, name, value) < 0) {
449 hpack_debug_printf("failed to find some room in the dynamic table\n");
450 ret = -HPACK_ERR_DHT_INSERT_FAIL;
451 goto leave;
452 }
453
Willy Tarreau679790b2017-05-30 19:09:44 +0200454 hpack_debug_printf("\e[1;34m%s\e[0m: ",
Tim Duesterhused526372020-03-05 17:56:33 +0100455 isttest(name) ? istpad(trash.area, name).ptr : h2_phdr_to_str(name.len));
Willy Tarreau679790b2017-05-30 19:09:44 +0200456
Willy Tarreauc775f832017-12-30 13:17:37 +0100457 hpack_debug_printf("\e[1;35m%s\e[0m [mustidx=%d, used=%d] [n=(%p,%d) v=(%p,%d)]\n",
Willy Tarreau843b7cb2018-07-13 10:54:26 +0200458 istpad(trash.area, value).ptr, must_index,
459 dht->used,
Willy Tarreauc775f832017-12-30 13:17:37 +0100460 name.ptr, (int)name.len, value.ptr, (int)value.len);
Willy Tarreau679790b2017-05-30 19:09:44 +0200461 }
462
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100463 if (ret >= list_size) {
Willy Tarreau679790b2017-05-30 19:09:44 +0200464 ret = -HPACK_ERR_TOO_LARGE;
465 goto leave;
466 }
467
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100468 /* put an end marker */
Tim Duesterhus241e29e2020-03-05 17:56:30 +0100469 list[ret].n = list[ret].v = IST_NULL;
Willy Tarreau59a10fb2017-11-21 20:03:02 +0100470 ret++;
Willy Tarreau679790b2017-05-30 19:09:44 +0200471
Willy Tarreau679790b2017-05-30 19:09:44 +0200472 leave:
Willy Tarreauc775f832017-12-30 13:17:37 +0100473 hpack_debug_printf("-- done: ret=%d list_size=%d --\n", (int)ret, (int)list_size);
Willy Tarreau679790b2017-05-30 19:09:44 +0200474 return ret;
475}