blob: 0da6cf89a72762891654b10a346a7d57d7da90b7 [file] [log] [blame]
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +01001/*
2 * QPACK decompressor
3 *
Willy Tarreau3dfb7da2022-03-02 22:33:39 +01004 * Copyright 2021 HAProxy Technologies, Frederic Lecaille <flecaille@haproxy.com>
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +01005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation, version 2.1
9 * exclusively.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include <inttypes.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <import/ist.h>
27#include <haproxy/buf.h>
28#include <haproxy/chunk.h>
29#include <haproxy/h3.h>
Amaury Denoyelle26aa3992022-08-16 17:42:47 +020030#include <haproxy/mux_quic.h>
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +010031#include <haproxy/qpack-t.h>
32#include <haproxy/qpack-dec.h>
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +020033#include <haproxy/qpack-tbl.h>
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +010034#include <haproxy/hpack-huff.h>
35#include <haproxy/hpack-tbl.h>
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +020036#include <haproxy/http-hdr.h>
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +010037#include <haproxy/tools.h>
38
Amaury Denoyelled96361b2022-03-25 14:56:51 +010039#if defined(DEBUG_QPACK)
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +010040#define qpack_debug_printf fprintf
41#define qpack_debug_hexdump debug_hexdump
42#else
43#define qpack_debug_printf(...) do { } while (0)
44#define qpack_debug_hexdump(...) do { } while (0)
45#endif
46
47/* Encoded field line bitmask */
48#define QPACK_EFL_BITMASK 0xf0
49#define QPACK_LFL_WPBNM 0x00 // Literal field line with post-base name reference
50#define QPACK_IFL_WPBI 0x10 // Indexed field line with post-based index
51#define QPACK_LFL_WLN_BIT 0x20 // Literal field line with literal name
52#define QPACK_LFL_WNR_BIT 0x40 // Literal field line with name reference
53#define QPACK_IFL_BIT 0x80 // Indexed field line
54
55/* reads a varint from <raw>'s lowest <b> bits and <len> bytes max (raw included).
56 * returns the 64-bit value on success after updating buf and len_in. Forces
57 * len_in to (uint64_t)-1 on truncated input.
58 * Note that this function is similar to the one used for HPACK (except that is supports
59 * up to 62-bits integers).
60 */
61static uint64_t qpack_get_varint(const unsigned char **buf, uint64_t *len_in, int b)
62{
63 uint64_t ret = 0;
64 int len = *len_in;
65 const uint8_t *raw = *buf;
66 uint8_t shift = 0;
67
68 len--;
Frédéric Lécaille68424852022-02-02 14:56:23 +010069 ret = *raw++ & ((1ULL << b) - 1);
70 if (ret != (uint64_t)((1ULL << b) - 1))
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +010071 goto end;
72
73 while (len && (*raw & 128)) {
74 ret += ((uint64_t)*raw++ & 127) << shift;
75 shift += 7;
76 len--;
77 }
78
79 /* last 7 bits */
80 if (!len)
81 goto too_short;
82
83 len--;
84 ret += ((uint64_t)*raw++ & 127) << shift;
85
86 end:
87 *buf = raw;
88 *len_in = len;
89 return ret;
90
91 too_short:
92 *len_in = (uint64_t)-1;
93 return 0;
94}
95
Amaury Denoyelle5869cb62022-05-31 15:21:27 +020096/* Decode an encoder stream.
97 *
98 * Returns 0 on success else non-zero.
99 */
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200100int qpack_decode_enc(struct buffer *buf, int fin, void *ctx)
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100101{
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200102 struct qcs *qcs = ctx;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100103 size_t len;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100104 unsigned char inst;
105
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200106 /* RFC 9204 4.2. Encoder and Decoder Streams
107 *
108 * The sender MUST NOT close either of these streams, and the receiver
109 * MUST NOT request that the sender close either of these streams.
110 * Closure of either unidirectional stream type MUST be treated as a
111 * connection error of type H3_CLOSED_CRITICAL_STREAM.
112 */
113 if (fin) {
114 qcc_emit_cc_app(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
115 return -1;
116 }
117
Amaury Denoyelle53eef462022-06-14 16:34:32 +0200118 len = b_data(buf);
119 qpack_debug_hexdump(stderr, "[QPACK-DEC-ENC] ", b_head(buf), 0, len);
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100120
121 if (!len) {
122 qpack_debug_printf(stderr, "[QPACK-DEC-ENC] empty stream\n");
123 return 0;
124 }
125
Amaury Denoyelle53eef462022-06-14 16:34:32 +0200126 inst = (unsigned char)*b_head(buf) & QPACK_ENC_INST_BITMASK;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100127 if (inst == QPACK_ENC_INST_DUP) {
128 /* Duplicate */
129 }
130 else if (inst & QPACK_ENC_INST_IWNR_BIT) {
131 /* Insert With Name Reference */
132 }
133 else if (inst & QPACK_ENC_INST_IWLN_BIT) {
134 /* Insert with literal name */
135 }
136 else if (inst & QPACK_ENC_INST_SDTC_BIT) {
137 /* Set dynamic table capacity */
138 }
139
Amaury Denoyelle5869cb62022-05-31 15:21:27 +0200140 return 0;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100141}
142
Amaury Denoyelle5869cb62022-05-31 15:21:27 +0200143/* Decode an decoder stream.
144 *
145 * Returns 0 on success else non-zero.
146 */
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200147int qpack_decode_dec(struct buffer *buf, int fin, void *ctx)
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100148{
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200149 struct qcs *qcs = ctx;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100150 size_t len;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100151 unsigned char inst;
152
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200153 /* RFC 9204 4.2. Encoder and Decoder Streams
154 *
155 * The sender MUST NOT close either of these streams, and the receiver
156 * MUST NOT request that the sender close either of these streams.
157 * Closure of either unidirectional stream type MUST be treated as a
158 * connection error of type H3_CLOSED_CRITICAL_STREAM.
159 */
160 if (fin) {
161 qcc_emit_cc_app(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
162 return -1;
163 }
164
Amaury Denoyelle53eef462022-06-14 16:34:32 +0200165 len = b_data(buf);
166 qpack_debug_hexdump(stderr, "[QPACK-DEC-DEC] ", b_head(buf), 0, len);
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100167
168 if (!len) {
169 qpack_debug_printf(stderr, "[QPACK-DEC-DEC] empty stream\n");
170 return 0;
171 }
172
Amaury Denoyelle53eef462022-06-14 16:34:32 +0200173 inst = (unsigned char)*b_head(buf) & QPACK_DEC_INST_BITMASK;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100174 if (inst == QPACK_DEC_INST_ICINC) {
175 /* Insert count increment */
176 }
177 else if (inst & QPACK_DEC_INST_SACK) {
178 /* Section Acknowledgment */
179 }
180 else if (inst & QPACK_DEC_INST_SCCL) {
181 /* Stream cancellation */
182 }
183
Amaury Denoyelle5869cb62022-05-31 15:21:27 +0200184 return 0;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100185}
186
187/* Decode a field section prefix made of <enc_ric> and <db> two varints.
188 * Also set the 'S' sign bit for <db>.
189 * Return a negative error if failed, 0 if not.
190 */
191static int qpack_decode_fs_pfx(uint64_t *enc_ric, uint64_t *db, int *sign_bit,
Frédéric Lécaille628e89c2022-06-24 12:13:53 +0200192 const unsigned char **raw, uint64_t *len)
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100193{
194 *enc_ric = qpack_get_varint(raw, len, 8);
195 if (*len == (uint64_t)-1)
196 return -QPACK_ERR_RIC;
197
198 *sign_bit = **raw & 0x8;
199 *db = qpack_get_varint(raw, len, 7);
200 if (*len == (uint64_t)-1)
201 return -QPACK_ERR_DB;
202
203 return 0;
204}
205
Amaury Denoyellec5d31ed2022-06-14 17:34:53 +0200206/* Decode a field section from the <raw> buffer of <len> bytes. Each parsed
Amaury Denoyelle60ef19f2022-06-14 17:38:36 +0200207 * header is inserted into <list> of <list_size> entries max and uses <tmp> as
208 * a storage for some elements pointing into it. An end marker is inserted at
209 * the end of the list with empty strings as name/value.
Amaury Denoyellec5d31ed2022-06-14 17:34:53 +0200210 *
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200211 * Returns the number of headers inserted into list excluding the end marker.
212 * In case of error, a negative code QPACK_ERR_* is returned.
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100213 */
Frédéric Lécaille628e89c2022-06-24 12:13:53 +0200214int qpack_decode_fs(const unsigned char *raw, uint64_t len, struct buffer *tmp,
Amaury Denoyelle60ef19f2022-06-14 17:38:36 +0200215 struct http_hdr *list, int list_size)
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100216{
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200217 struct ist name, value;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100218 uint64_t enc_ric, db;
219 int s;
220 unsigned int efl_type;
221 int ret;
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200222 int hdr_idx = 0;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100223
224 qpack_debug_hexdump(stderr, "[QPACK-DEC-FS] ", (const char *)raw, 0, len);
225
Amaury Denoyellec5d31ed2022-06-14 17:34:53 +0200226 /* parse field section prefix */
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100227 ret = qpack_decode_fs_pfx(&enc_ric, &db, &s, &raw, &len);
228 if (ret < 0) {
229 qpack_debug_printf(stderr, "##ERR@%d(%d)\n", __LINE__, ret);
230 goto out;
231 }
232
233 chunk_reset(tmp);
234 qpack_debug_printf(stderr, "enc_ric: %llu db: %llu s=%d\n",
235 (unsigned long long)enc_ric, (unsigned long long)db, !!s);
236 /* Decode field lines */
237 while (len) {
Amaury Denoyelle60ef19f2022-06-14 17:38:36 +0200238 if (hdr_idx >= list_size) {
239 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
240 ret = -QPACK_ERR_TOO_LARGE;
241 goto out;
242 }
243
Amaury Denoyellec5d31ed2022-06-14 17:34:53 +0200244 /* parse field line representation */
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100245 efl_type = *raw & QPACK_EFL_BITMASK;
246 qpack_debug_printf(stderr, "efl_type=0x%02x\n", efl_type);
Amaury Denoyellec5d31ed2022-06-14 17:34:53 +0200247
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100248 if (efl_type == QPACK_LFL_WPBNM) {
Amaury Denoyelle28d3c242022-06-14 16:36:15 +0200249 /* Literal field line with post-base name reference
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200250 * TODO adjust this when dynamic table support is implemented.
Amaury Denoyelle28d3c242022-06-14 16:36:15 +0200251 */
252#if 0
Amaury Denoyelle18a10d02022-03-25 15:11:38 +0100253 uint64_t index __maybe_unused, length;
Amaury Denoyelled96361b2022-03-25 14:56:51 +0100254 unsigned int n __maybe_unused, h __maybe_unused;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100255
256 qpack_debug_printf(stderr, "literal field line with post-base name reference:");
257 n = *raw & 0x08;
258 index = qpack_get_varint(&raw, &len, 3);
259 if (len == (uint64_t)-1) {
260 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
261 ret = -QPACK_ERR_TRUNCATED;
262 goto out;
263 }
264
265 qpack_debug_printf(stderr, " n=%d index=%llu", !!n, (unsigned long long)index);
266 h = *raw & 0x80;
267 length = qpack_get_varint(&raw, &len, 7);
268 if (len == (uint64_t)-1) {
269 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
270 ret = -QPACK_ERR_TRUNCATED;
271 goto out;
272 }
273
274 qpack_debug_printf(stderr, " h=%d length=%llu", !!h, (unsigned long long)length);
Frédéric Lécaillee629cfd2021-12-15 14:16:16 +0100275
276 if (len < length) {
277 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
278 ret = -QPACK_ERR_TRUNCATED;
279 goto out;
280 }
281
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100282 raw += length;
283 len -= length;
Amaury Denoyelle28d3c242022-06-14 16:36:15 +0200284#endif
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200285
286 /* RFC9204 2.2.3 Invalid References
287 *
288 * If the decoder encounters a reference in a field line representation
289 * to a dynamic table entry that has already been evicted or that has an
290 * absolute index greater than or equal to the declared Required Insert
291 * Count (Section 4.5.1), it MUST treat this as a connection error of
292 * type QPACK_DECOMPRESSION_FAILED.
293 */
294 return -QPACK_DECOMPRESSION_FAILED;
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200295 }
296 else if (efl_type == QPACK_IFL_WPBI) {
Amaury Denoyelle28d3c242022-06-14 16:36:15 +0200297 /* Indexed field line with post-base index
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200298 * TODO adjust this when dynamic table support is implemented.
Amaury Denoyelle28d3c242022-06-14 16:36:15 +0200299 */
300#if 0
Amaury Denoyelle18a10d02022-03-25 15:11:38 +0100301 uint64_t index __maybe_unused;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100302
303 qpack_debug_printf(stderr, "indexed field line with post-base index:");
304 index = qpack_get_varint(&raw, &len, 4);
305 if (len == (uint64_t)-1) {
306 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
307 ret = -QPACK_ERR_TRUNCATED;
308 goto out;
309 }
310
311 qpack_debug_printf(stderr, " index=%llu", (unsigned long long)index);
Amaury Denoyelle28d3c242022-06-14 16:36:15 +0200312#endif
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200313
314 /* RFC9204 2.2.3 Invalid References
315 *
316 * If the decoder encounters a reference in a field line representation
317 * to a dynamic table entry that has already been evicted or that has an
318 * absolute index greater than or equal to the declared Required Insert
319 * Count (Section 4.5.1), it MUST treat this as a connection error of
320 * type QPACK_DECOMPRESSION_FAILED.
321 */
322 return -QPACK_DECOMPRESSION_FAILED;
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200323 }
324 else if (efl_type & QPACK_IFL_BIT) {
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100325 /* Indexed field line */
326 uint64_t index;
Amaury Denoyelledebaa042022-06-20 15:47:46 +0200327 unsigned int static_tbl;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100328
329 qpack_debug_printf(stderr, "indexed field line:");
Amaury Denoyelledebaa042022-06-20 15:47:46 +0200330 static_tbl = efl_type & 0x40;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100331 index = qpack_get_varint(&raw, &len, 6);
332 if (len == (uint64_t)-1) {
333 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
334 ret = -QPACK_ERR_TRUNCATED;
335 goto out;
336 }
337
Amaury Denoyelledebaa042022-06-20 15:47:46 +0200338 if (static_tbl) {
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200339 name = qpack_sht[index].n;
340 value = qpack_sht[index].v;
341 }
Amaury Denoyelledebaa042022-06-20 15:47:46 +0200342 else {
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200343 /* RFC9204 2.2.3 Invalid References
Amaury Denoyelledebaa042022-06-20 15:47:46 +0200344 *
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200345 * If the decoder encounters a reference in a field line representation
346 * to a dynamic table entry that has already been evicted or that has an
347 * absolute index greater than or equal to the declared Required Insert
348 * Count (Section 4.5.1), it MUST treat this as a connection error of
349 * type QPACK_DECOMPRESSION_FAILED.
350 *
351 * TODO adjust this when dynamic table support is implemented.
Amaury Denoyelledebaa042022-06-20 15:47:46 +0200352 */
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200353 return -QPACK_DECOMPRESSION_FAILED;
Amaury Denoyelledebaa042022-06-20 15:47:46 +0200354 }
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200355
Amaury Denoyelle055de232022-06-30 09:28:50 +0200356 qpack_debug_printf(stderr, " t=%d index=%llu", !!static_tbl, (unsigned long long)index);
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200357 }
358 else if (efl_type & QPACK_LFL_WNR_BIT) {
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100359 /* Literal field line with name reference */
360 uint64_t index, length;
Amaury Denoyelle46e992d2022-06-30 09:31:24 +0200361 unsigned int static_tbl, n __maybe_unused, h;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100362
363 qpack_debug_printf(stderr, "Literal field line with name reference:");
364 n = efl_type & 0x20;
Amaury Denoyelle46e992d2022-06-30 09:31:24 +0200365 static_tbl = efl_type & 0x10;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100366 index = qpack_get_varint(&raw, &len, 4);
367 if (len == (uint64_t)-1) {
368 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
369 ret = -QPACK_ERR_TRUNCATED;
370 goto out;
371 }
372
Amaury Denoyelle46e992d2022-06-30 09:31:24 +0200373 if (static_tbl) {
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200374 name = qpack_sht[index].n;
Amaury Denoyelle46e992d2022-06-30 09:31:24 +0200375 }
376 else {
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200377 /* RFC9204 2.2.3 Invalid References
Amaury Denoyelle46e992d2022-06-30 09:31:24 +0200378 *
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200379 * If the decoder encounters a reference in a field line representation
380 * to a dynamic table entry that has already been evicted or that has an
381 * absolute index greater than or equal to the declared Required Insert
382 * Count (Section 4.5.1), it MUST treat this as a connection error of
383 * type QPACK_DECOMPRESSION_FAILED.
384 *
385 * TODO adjust this when dynamic table support is implemented.
Amaury Denoyelle46e992d2022-06-30 09:31:24 +0200386 */
Amaury Denoyellea7a4c802022-06-30 09:30:23 +0200387 return -QPACK_DECOMPRESSION_FAILED;
Amaury Denoyelle46e992d2022-06-30 09:31:24 +0200388 }
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200389
Amaury Denoyelle46e992d2022-06-30 09:31:24 +0200390 qpack_debug_printf(stderr, " n=%d t=%d index=%llu", !!n, !!static_tbl, (unsigned long long)index);
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100391 h = *raw & 0x80;
392 length = qpack_get_varint(&raw, &len, 7);
393 if (len == (uint64_t)-1) {
394 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
395 ret = -QPACK_ERR_TRUNCATED;
396 goto out;
397 }
398
399 qpack_debug_printf(stderr, " h=%d length=%llu", !!h, (unsigned long long)length);
400 if (h) {
401 char *trash;
402 int nlen;
403
404 trash = chunk_newstr(tmp);
405 if (!trash) {
406 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
407 ret = -QPACK_DECOMPRESSION_FAILED;
408 goto out;
409 }
410 nlen = huff_dec(raw, length, trash, tmp->size - tmp->data);
411 if (nlen == (uint32_t)-1) {
412 qpack_debug_printf(stderr, " can't decode huffman.\n");
413 ret = -QPACK_ERR_HUFFMAN;
414 goto out;
415 }
416
417 qpack_debug_printf(stderr, " [name huff %d->%d '%s']", (int)length, (int)nlen, trash);
Amaury Denoyelle9c8c4fa2021-09-30 17:14:55 +0200418 /* makes an ist from tmp storage */
419 b_add(tmp, nlen);
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200420 value = ist2(trash, nlen);
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100421 }
Amaury Denoyelle7d3aea52021-11-24 16:04:03 +0100422 else {
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200423 value = ist2(raw, length);
Amaury Denoyelle7d3aea52021-11-24 16:04:03 +0100424 }
425
Frédéric Lécaillee629cfd2021-12-15 14:16:16 +0100426 if (len < length) {
427 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
428 ret = -QPACK_ERR_TRUNCATED;
429 goto out;
430 }
431
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100432 raw += length;
433 len -= length;
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200434 }
435 else if (efl_type & QPACK_LFL_WLN_BIT) {
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100436 /* Literal field line with literal name */
Amaury Denoyelle4bcaf692022-06-14 16:34:55 +0200437 unsigned int n __maybe_unused, hname, hvalue;
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100438 uint64_t name_len, value_len;
439
440 qpack_debug_printf(stderr, "Literal field line with literal name:");
441 n = *raw & 0x10;
442 hname = *raw & 0x08;
443 name_len = qpack_get_varint(&raw, &len, 3);
444 if (len == (uint64_t)-1) {
445 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
446 ret = -QPACK_ERR_TRUNCATED;
447 goto out;
448 }
449
Amaury Denoyelleab9cec72022-02-14 14:45:10 +0100450 qpack_debug_printf(stderr, " n=%d hname=%d name_len=%llu", !!n, !!hname, (unsigned long long)name_len);
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100451 /* Name string */
Frédéric Lécaillee629cfd2021-12-15 14:16:16 +0100452
453 if (len < name_len) {
454 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
455 ret = -QPACK_ERR_TRUNCATED;
456 goto out;
457 }
458
Amaury Denoyelle4bcaf692022-06-14 16:34:55 +0200459 if (hname) {
460 char *trash;
461 int nlen;
462
463 trash = chunk_newstr(tmp);
464 if (!trash) {
465 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
466 ret = -QPACK_DECOMPRESSION_FAILED;
467 goto out;
468 }
469 nlen = huff_dec(raw, name_len, trash, tmp->size - tmp->data);
470 if (nlen == (uint32_t)-1) {
471 qpack_debug_printf(stderr, " can't decode huffman.\n");
472 ret = -QPACK_ERR_HUFFMAN;
473 goto out;
474 }
475
476 qpack_debug_printf(stderr, " [name huff %d->%d '%s']", (int)name_len, (int)nlen, trash);
477 /* makes an ist from tmp storage */
478 b_add(tmp, nlen);
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200479 name = ist2(trash, nlen);
Amaury Denoyelle4bcaf692022-06-14 16:34:55 +0200480 }
481 else {
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200482 name = ist2(raw, name_len);
Amaury Denoyelle4bcaf692022-06-14 16:34:55 +0200483 }
484
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100485 raw += name_len;
486 len -= name_len;
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200487
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100488 hvalue = *raw & 0x80;
489 value_len = qpack_get_varint(&raw, &len, 7);
490 if (len == (uint64_t)-1) {
491 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
492 ret = -QPACK_ERR_TRUNCATED;
493 goto out;
494 }
495
496 qpack_debug_printf(stderr, " hvalue=%d value_len=%llu", !!hvalue, (unsigned long long)value_len);
497
Frédéric Lécaillee629cfd2021-12-15 14:16:16 +0100498 if (len < value_len) {
499 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
500 ret = -QPACK_ERR_TRUNCATED;
501 goto out;
502 }
503
Amaury Denoyelle4bcaf692022-06-14 16:34:55 +0200504 if (hvalue) {
505 char *trash;
506 int nlen;
507
508 trash = chunk_newstr(tmp);
509 if (!trash) {
510 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
511 ret = -QPACK_DECOMPRESSION_FAILED;
512 goto out;
513 }
514 nlen = huff_dec(raw, value_len, trash, tmp->size - tmp->data);
515 if (nlen == (uint32_t)-1) {
516 qpack_debug_printf(stderr, " can't decode huffman.\n");
517 ret = -QPACK_ERR_HUFFMAN;
518 goto out;
519 }
520
521 qpack_debug_printf(stderr, " [name huff %d->%d '%s']", (int)value_len, (int)nlen, trash);
522 /* makes an ist from tmp storage */
523 b_add(tmp, nlen);
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200524 value = ist2(trash, nlen);
Amaury Denoyelle4bcaf692022-06-14 16:34:55 +0200525 }
526 else {
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200527 value = ist2(raw, value_len);
Amaury Denoyelle4bcaf692022-06-14 16:34:55 +0200528 }
529
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100530 raw += value_len;
531 len -= value_len;
532 }
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200533
534 list[hdr_idx].n = name;
535 list[hdr_idx].v = value;
536 ++hdr_idx;
537
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100538 qpack_debug_printf(stderr, "\n");
539 }
540
Amaury Denoyelle60ef19f2022-06-14 17:38:36 +0200541 if (hdr_idx >= list_size) {
542 qpack_debug_printf(stderr, "##ERR@%d\n", __LINE__);
543 ret = -QPACK_ERR_TOO_LARGE;
544 goto out;
545 }
546
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200547 /* put an end marker */
548 list[hdr_idx].n = list[hdr_idx].v = IST_NULL;
Amaury Denoyelleb666c6b2022-06-14 17:17:07 +0200549 ret = hdr_idx;
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200550
Frédéric Lécailleb4672fb2021-03-03 16:13:10 +0100551 out:
552 qpack_debug_printf(stderr, "-- done: ret=%d\n", ret);
553 return ret;
554}