blob: 78d43a71a1f378fc34e435d9570e60989f312219 [file] [log] [blame]
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001/*
2 * HTTP/3 protocol processing
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation, version 2.1
7 * exclusively.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include <haproxy/buf.h>
20#include <haproxy/dynbuf.h>
21#include <haproxy/h3.h>
22#include <haproxy/istbuf.h>
23#include <haproxy/mux_quic.h>
24#include <haproxy/pool.h>
25#include <haproxy/qpack-dec.h>
26#include <haproxy/tools.h>
27#include <haproxy/xprt_quic.h>
28
29#define DEBUG_H3
30
31#if defined(DEBUG_H3)
32#define h3_debug_printf fprintf
33#define h3_debug_hexdump debug_hexdump
34#else
35#define h3_debug_printf(...) do { } while (0)
36#define h3_debug_hexdump(...) do { } while (0)
37#endif
38
39#define H3_CF_SETTINGS_SENT 0x00000001
40
41/* Default settings */
Amaury Denoyelle33949392021-08-24 15:16:58 +020042static uint64_t h3_settings_qpack_max_table_capacity = 0;
43static uint64_t h3_settings_qpack_blocked_streams = 4096;
44static uint64_t h3_settings_max_field_section_size = QUIC_VARINT_8_BYTE_MAX; /* Unlimited */
Frédéric Lécailleccac11f2021-03-03 16:09:02 +010045
46struct h3 {
47 struct qcc *qcc;
48 enum h3_err err;
49 uint32_t flags;
50 /* Locally initiated uni-streams */
51 struct h3_uqs lqpack_enc;
52 struct h3_uqs lqpack_dec;
53 struct h3_uqs lctrl;
54 /* Remotely initiated uni-streams */
55 struct h3_uqs rqpack_enc;
56 struct h3_uqs rqpack_dec;
57 struct h3_uqs rctrl;
58 /* Settings */
59 uint64_t qpack_max_table_capacity;
60 uint64_t qpack_blocked_streams;
61 uint64_t max_field_section_size;
62 struct buffer_wait buf_wait; /* wait list for buffer allocations */
63};
64
65DECLARE_STATIC_POOL(pool_head_h3, "h3", sizeof(struct h3));
66
67/* Simple function to duplicate a buffer */
68static inline struct buffer h3_b_dup(struct buffer *b)
69{
70 return b_make(b->area, b->size, b->head, b->data);
71}
72
73static int qcs_buf_available(void *target)
74{
75 struct h3_uqs *h3_uqs = target;
76 struct qcs *qcs = h3_uqs->qcs;
77
78 if ((qcs->flags & OUQS_SF_TXBUF_MALLOC) && b_alloc(&qcs->tx.buf)) {
79 qcs->flags &= ~OUQS_SF_TXBUF_MALLOC;
80 tasklet_wakeup(h3_uqs->wait_event.tasklet);
81 return 1;
82 }
83
84 return 0;
85}
86
87static struct buffer *h3_uqs_get_buf(struct h3_uqs *h3_uqs)
88{
89 struct buffer *buf = NULL;
90 struct h3 *h3 = h3_uqs->qcs->qcc->ctx;
91
92 if (likely(!LIST_INLIST(&h3->buf_wait.list)) &&
93 unlikely((buf = b_alloc(&h3_uqs->qcs->tx.buf)) == NULL)) {
94 h3->buf_wait.target = h3_uqs;
95 h3->buf_wait.wakeup_cb = qcs_buf_available;
96 LIST_APPEND(&ti->buffer_wq, &h3->buf_wait.list);
97 }
98
99 return buf;
100}
101
102/* Decode a h3 frame header made of two QUIC varints from <b> buffer.
103 * Returns the number of bytes consumed if there was enough data in <b>, 0 if not.
104 * Note that this function update <b> buffer to reflect the number of bytes consumed
105 * to decode the h3 frame header.
106 */
107static inline size_t h3_decode_frm_header(uint64_t *ftype, uint64_t *flen,
108 struct buffer *b)
109{
110 size_t hlen;
111
112 hlen = 0;
113 if (!b_quic_dec_int(ftype, b, &hlen) || !b_quic_dec_int(flen, b, &hlen))
114 return 0;
115
116 return hlen;
117}
118
119/* Decode <qcs> remotely initiated bidi-stream */
120static int h3_decode_qcs(struct qcs *qcs, void *ctx)
121{
122 struct buffer *rxbuf = &qcs->rx.buf;
123 struct h3 *h3 = ctx;
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200124 struct http_hdr list[global.tune.max_http_hdr];
125 int hdr_idx;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100126
127 h3_debug_printf(stderr, "%s: STREAM ID: %llu\n", __func__, qcs->by_id.key);
128 if (!b_data(rxbuf))
129 return 0;
130
131 while (b_data(rxbuf)) {
132 size_t hlen;
133 uint64_t ftype, flen;
134 struct buffer b;
135
136 /* Work on a copy of <rxbuf> */
137 b = h3_b_dup(rxbuf);
138 hlen = h3_decode_frm_header(&ftype, &flen, &b);
139 if (!hlen)
140 break;
141
142 h3_debug_printf(stderr, "%s: ftype: %llu, flen: %llu\n", __func__,
143 (unsigned long long)ftype, (unsigned long long)flen);
144 if (flen > b_data(&b))
145 break;
146
147 b_del(rxbuf, hlen);
148 switch (ftype) {
149 case H3_FT_DATA:
150 break;
151 case H3_FT_HEADERS:
152 {
153 const unsigned char *buf = (const unsigned char *)b_head(rxbuf);
154 size_t len = b_data(rxbuf);
155 struct buffer *tmp = get_trash_chunk();
156
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200157 if (qpack_decode_fs(buf, len, tmp, list) < 0) {
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100158 h3->err = QPACK_DECOMPRESSION_FAILED;
159 return -1;
160 }
161 break;
162 }
163 case H3_FT_PUSH_PROMISE:
164 /* Not supported */
165 break;
166 default:
167 /* Error */
168 h3->err = H3_FRAME_UNEXPECTED;
169 return -1;
170 }
171 b_del(rxbuf, flen);
172 }
173
174 return 1;
175}
176
177/* Parse a SETTINGS frame which must not be truncated with <flen> as length from
178 * <rxbuf> buffer. This function does not update this buffer.
179 * Returns 0 if something wrong happened, 1 if not.
180 */
181static int h3_parse_settings_frm(struct h3 *h3, const struct buffer *rxbuf, size_t flen)
182{
183 uint64_t id, value;
184 const unsigned char *buf, *end;
185
186 buf = (const unsigned char *)b_head(rxbuf);
187 end = buf + flen;
188
189 while (buf <= end) {
190 if (!quic_dec_int(&id, &buf, end) || !quic_dec_int(&value, &buf, end))
191 return 0;
192
193 h3_debug_printf(stderr, "%s id: %llu value: %llu\n",
194 __func__, (unsigned long long)id, (unsigned long long)value);
195 switch (id) {
196 case H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY:
197 h3->qpack_max_table_capacity = value;
198 break;
199 case H3_SETTINGS_MAX_FIELD_SECTION_SIZE:
200 h3->max_field_section_size = value;
201 break;
202 case H3_SETTINGS_QPACK_BLOCKED_STREAMS:
203 h3->qpack_blocked_streams = value;
204 break;
205 case H3_SETTINGS_RESERVED_2 ... H3_SETTINGS_RESERVED_5:
206 h3->err = H3_SETTINGS_ERROR;
207 return 0;
208 default:
209 /* MUST be ignored */
210 break;
211 }
212 }
213
214 return 1;
215}
216
217/* Decode <qcs> remotely initiated uni-stream. We stop parsing a frame as soon as
218 * there is not enough received data.
219 * Returns 0 if something wrong happened, 1 if not.
220 */
221static int h3_control_recv(struct h3_uqs *h3_uqs, void *ctx)
222{
223 struct buffer *rxbuf = &h3_uqs->qcs->rx.buf;
224 struct h3 *h3 = ctx;
225
226 h3_debug_printf(stderr, "%s STREAM ID: %llu\n", __func__, h3_uqs->qcs->by_id.key);
227 if (!b_data(rxbuf))
228 return 1;
229
230 while (b_data(rxbuf)) {
231 size_t hlen;
232 uint64_t ftype, flen;
233 struct buffer b;
234
235 /* Work on a copy of <rxbuf> */
236 b = h3_b_dup(rxbuf);
237 hlen = h3_decode_frm_header(&ftype, &flen, &b);
238 if (!hlen)
239 break;
240
241 h3_debug_printf(stderr, "%s: ftype: %llu, flen: %llu\n", __func__,
242 (unsigned long long)ftype, (unsigned long long)flen);
243 if (flen > b_data(&b))
244 break;
245
246 b_del(rxbuf, hlen);
247 /* From here, a frame must not be truncated */
248 switch (ftype) {
249 case H3_FT_CANCEL_PUSH:
250 break;
251 case H3_FT_SETTINGS:
252 if (!h3_parse_settings_frm(h3, rxbuf, flen))
253 return 0;
254 break;
255 case H3_FT_GOAWAY:
256 break;
257 case H3_FT_MAX_PUSH_ID:
258 break;
259 default:
260 /* Error */
261 h3->err = H3_FRAME_UNEXPECTED;
262 return 0;
263 }
264 b_del(rxbuf, flen);
265 }
266
267 if (b_data(rxbuf))
268 h3->qcc->conn->mux->ruqs_subscribe(h3_uqs->qcs, SUB_RETRY_RECV, &h3->rctrl.wait_event);
269
270 return 1;
271}
272
273int h3_txbuf_cpy(struct h3_uqs *h3_uqs, unsigned char *buf, size_t len)
274{
275 struct buffer *res = &h3_uqs->qcs->tx.buf;
276 struct qcc *qcc = h3_uqs->qcs->qcc;
277 int ret;
278
279 ret = 0;
280 if (!h3_uqs_get_buf(h3_uqs)) {
281 qcc->flags |= OUQS_SF_TXBUF_MALLOC;
282 goto out;
283 }
284
285 ret = b_istput(res, ist2((char *)buf, len));
286 if (unlikely(!ret))
287 qcc->flags |= OUQS_SF_TXBUF_FULL;
288
289 out:
290 return ret;
291}
292
293/* Function used to emit stream data from <h3_uqs> control uni-stream */
294static int h3_control_send(struct h3_uqs *h3_uqs, void *ctx)
295{
296 int ret;
297 struct h3 *h3 = ctx;
298 unsigned char data[(2 + 3) * 2 * QUIC_VARINT_MAX_SIZE]; /* enough for 3 settings */
299 unsigned char *pos, *end;
300
301 ret = 0;
302 pos = data;
303 end = pos + sizeof data;
304 if (!(h3->flags & H3_CF_SETTINGS_SENT)) {
305 struct qcs *qcs = h3_uqs->qcs;
306 struct buffer *txbuf = &qcs->tx.buf;
307 size_t frm_len;
308
309 frm_len = quic_int_getsize(H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY) +
310 quic_int_getsize(h3_settings_qpack_max_table_capacity) +
311 quic_int_getsize(H3_SETTINGS_QPACK_BLOCKED_STREAMS) +
312 quic_int_getsize(h3_settings_qpack_blocked_streams);
313 if (h3_settings_max_field_section_size) {
314 frm_len += quic_int_getsize(H3_SETTINGS_MAX_FIELD_SECTION_SIZE) +
315 quic_int_getsize(h3_settings_max_field_section_size);
316 }
317
318 quic_enc_int(&pos, end, H3_UNI_STRM_TP_CONTROL_STREAM);
319 /* Build a SETTINGS frame */
320 quic_enc_int(&pos, end, H3_FT_SETTINGS);
321 quic_enc_int(&pos, end, frm_len);
322 quic_enc_int(&pos, end, H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY);
323 quic_enc_int(&pos, end, h3_settings_qpack_max_table_capacity);
324 quic_enc_int(&pos, end, H3_SETTINGS_QPACK_BLOCKED_STREAMS);
325 quic_enc_int(&pos, end, h3_settings_qpack_blocked_streams);
326 if (h3_settings_max_field_section_size) {
327 quic_enc_int(&pos, end, H3_SETTINGS_MAX_FIELD_SECTION_SIZE);
328 quic_enc_int(&pos, end, h3_settings_max_field_section_size);
329 }
330 ret = h3_txbuf_cpy(h3_uqs, data, pos - data);
331 if (ret < 0) {
332 qc_error(qcs->qcc, H3_INTERNAL_ERROR);
333 return ret;
334 }
335
336 if (ret > 0) {
337 h3->flags |= H3_CF_SETTINGS_SENT;
338 luqs_snd_buf(h3_uqs->qcs, txbuf, b_data(&qcs->tx.buf), 0);
339 }
340 if (b_data(&qcs->tx.buf))
341 qcs->qcc->conn->mux->luqs_subscribe(qcs, SUB_RETRY_SEND, &h3->lctrl.wait_event);
342 }
343
344 return ret;
345}
346
347/* Finalize the initialization of remotely initiated uni-stream <qcs>.
348 * Return 1 if succeeded, 0 if not. In this latter case, set the ->err h3 error
349 * to inform the QUIC mux layer of the encountered error.
350 */
351static int h3_attach_ruqs(struct qcs *qcs, void *ctx)
352{
353 uint64_t strm_type;
354 struct h3 *h3 = ctx;
355 struct buffer *rxbuf = &qcs->rx.buf;
356
357 /* First octets: the uni-stream type */
358 if (!b_quic_dec_int(&strm_type, rxbuf, NULL) || strm_type > H3_UNI_STRM_TP_MAX)
359 return 0;
360
361 /* Note that for all the uni-streams below, this is an error to receive two times the
362 * same type of uni-stream (even for Push stream which is not supported at this time.
363 */
364 switch (strm_type) {
365 case H3_UNI_STRM_TP_CONTROL_STREAM:
366 if (h3->rctrl.qcs) {
367 h3->err = H3_STREAM_CREATION_ERROR;
368 return 0;
369 }
370
371 h3->rctrl.qcs = qcs;
372 h3->rctrl.cb = h3_control_recv;
373 h3->qcc->conn->mux->ruqs_subscribe(qcs, SUB_RETRY_RECV, &h3->rctrl.wait_event);
374 break;
375 case H3_UNI_STRM_TP_PUSH_STREAM:
376 /* NOT SUPPORTED */
377 break;
378 case H3_UNI_STRM_TP_QPACK_ENCODER:
379 if (h3->rqpack_enc.qcs) {
380 h3->err = H3_STREAM_CREATION_ERROR;
381 return 0;
382 }
383
384 h3->rqpack_enc.qcs = qcs;
385 h3->rqpack_enc.cb = qpack_decode_enc;
386 h3->qcc->conn->mux->ruqs_subscribe(qcs, SUB_RETRY_RECV, &h3->rqpack_enc.wait_event);
387 break;
388 case H3_UNI_STRM_TP_QPACK_DECODER:
389 if (h3->rqpack_dec.qcs) {
390 h3->err = H3_STREAM_CREATION_ERROR;
391 return 0;
392 }
393
394 h3->rqpack_dec.qcs = qcs;
395 h3->rqpack_dec.cb = qpack_decode_dec;
396 h3->qcc->conn->mux->ruqs_subscribe(qcs, SUB_RETRY_RECV, &h3->rqpack_dec.wait_event);
397 break;
398 default:
399 /* Error */
400 h3->err = H3_STREAM_CREATION_ERROR;
401 return 0;
402 }
403
404 return 1;
405}
406
407static int h3_finalize(void *ctx)
408{
409 struct h3 *h3 = ctx;
410
411 h3->lctrl.qcs = luqs_new(h3->qcc);
412 if (!h3->lctrl.qcs)
413 return 0;
414
415 /* Wakeup ->lctrl uni-stream */
Frédéric Lécaillee16f0bd2021-08-23 09:50:29 +0200416 h3_control_send(&h3->lctrl, h3);
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100417
418 return 1;
419}
420
421/* Tasklet dedicated to h3 incoming uni-streams */
422static struct task *h3_uqs_task(struct task *t, void *ctx, unsigned int state)
423{
424 struct h3_uqs *h3_uqs = ctx;
425 struct h3 *h3 = h3_uqs->qcs->qcc->ctx;
426
427 h3_uqs->cb(h3_uqs, h3);
428 return NULL;
429}
430
431#if 0
432/* Initialiaze <h3_uqs> uni-stream with <t> as tasklet */
433static int h3_uqs_init(struct h3_uqs *h3_uqs,
434 struct task *(*t)(struct task *, void *, unsigned int))
435{
436 h3_uqs->qcs = NULL;
437 h3_uqs->cb = NULL;
438 h3_uqs->wait_event.tasklet = tasklet_new();
439 if (!h3_uqs->wait_event.tasklet)
440 return 0;
441
442 h3_uqs->wait_event.tasklet->process = t;
443 h3_uqs->wait_event.tasklet->context = h3_uqs;
444 return 1;
445}
446#endif
447
448/* Release all the tasklet attached to <h3_uqs> uni-stream */
449static inline void h3_uqs_tasklet_release(struct h3_uqs *h3_uqs)
450{
451 struct tasklet *t = h3_uqs->wait_event.tasklet;
452
453 if (t)
454 tasklet_free(t);
455}
456
457/* Release all the tasklet attached to <h3> uni-streams */
458static void h3_uqs_tasklets_release(struct h3 *h3)
459{
460 h3_uqs_tasklet_release(&h3->rqpack_enc);
461 h3_uqs_tasklet_release(&h3->rqpack_dec);
462 h3_uqs_tasklet_release(&h3->rctrl);
463}
464
465/* Tasklet dedicated to h3 outgoing uni-streams */
466__maybe_unused
467static struct task *h3_uqs_send_task(struct task *t, void *ctx, unsigned int state)
468{
469 struct h3_uqs *h3_uqs = ctx;
470 struct h3 *h3 = h3_uqs->qcs->qcc->ctx;
471
472 h3_uqs->cb(h3_uqs, h3);
473 return NULL;
474}
475
476/* Initialiaze <h3_uqs> uni-stream with <t> as tasklet */
477static int h3_uqs_init(struct h3_uqs *h3_uqs, struct h3 *h3,
478 int (*cb)(struct h3_uqs *h3_uqs, void *ctx),
479 struct task *(*t)(struct task *, void *, unsigned int))
480{
481 h3_uqs->qcs = NULL;
482 h3_uqs->cb = cb;
483 h3_uqs->wait_event.tasklet = tasklet_new();
484 if (!h3_uqs->wait_event.tasklet)
485 return 0;
486
487 h3_uqs->wait_event.tasklet->process = t;
488 h3_uqs->wait_event.tasklet->context = h3_uqs;
489 return 1;
490
491 err:
492 tasklet_free(h3_uqs->wait_event.tasklet);
493 return 0;
494}
495
496static inline void h3_uqs_release(struct h3_uqs *h3_uqs)
497{
498 if (h3_uqs->qcs)
499 qcs_release(h3_uqs->qcs);
500}
501
502static inline void h3_uqs_release_all(struct h3 *h3)
503{
504 h3_uqs_tasklet_release(&h3->lctrl);
505 h3_uqs_release(&h3->lctrl);
506 h3_uqs_tasklet_release(&h3->lqpack_enc);
507 h3_uqs_release(&h3->lqpack_enc);
508 h3_uqs_tasklet_release(&h3->lqpack_dec);
509 h3_uqs_release(&h3->lqpack_dec);
510}
511
512/* Initialize the HTTP/3 context for <qcc> mux.
513 * Return 1 if succeeded, 0 if not.
514 */
515static int h3_init(struct qcc *qcc)
516{
517 struct h3 *h3;
518
519 h3 = pool_alloc(pool_head_h3);
520 if (!h3)
521 goto fail_no_h3;
522
523 h3->qcc = qcc;
524 h3->err = H3_NO_ERROR;
525 h3->flags = 0;
526
527 if (!h3_uqs_init(&h3->rqpack_enc, h3, NULL, h3_uqs_task) ||
528 !h3_uqs_init(&h3->rqpack_dec, h3, NULL, h3_uqs_task) ||
529 !h3_uqs_init(&h3->rctrl, h3, h3_control_recv, h3_uqs_task))
530 goto fail_no_h3_ruqs;
531
532 if (!h3_uqs_init(&h3->lctrl, h3, h3_control_send, h3_uqs_task) ||
533 !h3_uqs_init(&h3->lqpack_enc, h3, NULL, h3_uqs_task) ||
534 !h3_uqs_init(&h3->lqpack_dec, h3, NULL, h3_uqs_task))
535 goto fail_no_h3_luqs;
536
537 qcc->ctx = h3;
538 LIST_INIT(&h3->buf_wait.list);
539
540 return 1;
541
542 fail_no_h3_ruqs:
543 h3_uqs_release_all(h3);
544 fail_no_h3_luqs:
545 h3_uqs_tasklets_release(h3);
546 pool_free(pool_head_h3, h3);
547 fail_no_h3:
548 return 0;
549}
550
551/* HTTP/3 application layer operations */
552const struct qcc_app_ops h3_ops = {
553 .init = h3_init,
554 .attach_ruqs = h3_attach_ruqs,
555 .decode_qcs = h3_decode_qcs,
556 .finalize = h3_finalize,
557};