blob: ba3331120ffa411bd983363566d3b7d98403e487 [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
Amaury Denoyelle5c25dc52022-09-30 17:44:15 +020019#include <import/ist.h>
20
21#include <haproxy/api.h>
Frédéric Lécailleccac11f2021-03-03 16:09:02 +010022#include <haproxy/buf.h>
Amaury Denoyelle5c25dc52022-09-30 17:44:15 +020023#include <haproxy/chunk.h>
Amaury Denoyelle99043552021-08-24 15:36:02 +020024#include <haproxy/connection.h>
Frédéric Lécailleccac11f2021-03-03 16:09:02 +010025#include <haproxy/dynbuf.h>
26#include <haproxy/h3.h>
Frédéric Lécaille6f7607e2022-05-25 22:25:37 +020027#include <haproxy/h3_stats.h>
Amaury Denoyelleb49fa1a2021-08-24 15:30:12 +020028#include <haproxy/http.h>
Amaury Denoyelle5c25dc52022-09-30 17:44:15 +020029#include <haproxy/http-hdr-t.h>
Amaury Denoyelle115ccce2022-08-17 18:02:47 +020030#include <haproxy/http_htx.h>
Amaury Denoyelleb49fa1a2021-08-24 15:30:12 +020031#include <haproxy/htx.h>
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +020032#include <haproxy/intops.h>
Frédéric Lécailleccac11f2021-03-03 16:09:02 +010033#include <haproxy/istbuf.h>
Amaury Denoyelle846cc042022-04-04 16:13:44 +020034#include <haproxy/mux_quic.h>
Frédéric Lécailleccac11f2021-03-03 16:09:02 +010035#include <haproxy/pool.h>
36#include <haproxy/qpack-dec.h>
Amaury Denoyelle15b09612021-08-24 16:20:27 +020037#include <haproxy/qpack-enc.h>
Amaury Denoyelle92fa63f2022-09-30 18:11:13 +020038#include <haproxy/quic_conn-t.h>
Amaury Denoyelle15b09612021-08-24 16:20:27 +020039#include <haproxy/quic_enc.h>
Amaury Denoyelle5c25dc52022-09-30 17:44:15 +020040#include <haproxy/stats-t.h>
Frédéric Lécailleccac11f2021-03-03 16:09:02 +010041#include <haproxy/tools.h>
Amaury Denoyelle016aa932022-05-30 15:49:36 +020042#include <haproxy/trace.h>
Frédéric Lécailleccac11f2021-03-03 16:09:02 +010043
Amaury Denoyelle016aa932022-05-30 15:49:36 +020044/* trace source and events */
45static void h3_trace(enum trace_level level, uint64_t mask,
46 const struct trace_source *src,
47 const struct ist where, const struct ist func,
48 const void *a1, const void *a2, const void *a3, const void *a4);
49
50static const struct trace_event h3_trace_events[] = {
Amaury Denoyelle494512d2022-05-30 15:50:34 +020051#define H3_EV_RX_FRAME (1ULL << 0)
52 { .mask = H3_EV_RX_FRAME, .name = "rx_frame", .desc = "receipt of any H3 frame" },
53#define H3_EV_RX_DATA (1ULL << 1)
54 { .mask = H3_EV_RX_DATA, .name = "rx_data", .desc = "receipt of H3 DATA frame" },
55#define H3_EV_RX_HDR (1ULL << 2)
56 { .mask = H3_EV_RX_HDR, .name = "rx_hdr", .desc = "receipt of H3 HEADERS frame" },
57#define H3_EV_RX_SETTINGS (1ULL << 3)
58 { .mask = H3_EV_RX_SETTINGS, .name = "rx_settings", .desc = "receipt of H3 SETTINGS frame" },
Amaury Denoyellea717eb72022-05-30 15:51:01 +020059#define H3_EV_TX_DATA (1ULL << 4)
60 { .mask = H3_EV_TX_DATA, .name = "tx_data", .desc = "transmission of H3 DATA frame" },
61#define H3_EV_TX_HDR (1ULL << 5)
62 { .mask = H3_EV_TX_HDR, .name = "tx_hdr", .desc = "transmission of H3 HEADERS frame" },
63#define H3_EV_TX_SETTINGS (1ULL << 6)
64 { .mask = H3_EV_TX_SETTINGS, .name = "tx_settings", .desc = "transmission of H3 SETTINGS frame" },
Amaury Denoyelled5581d52022-05-30 15:51:31 +020065#define H3_EV_H3S_NEW (1ULL << 7)
66 { .mask = H3_EV_H3S_NEW, .name = "h3s_new", .desc = "new H3 stream" },
67#define H3_EV_H3S_END (1ULL << 8)
68 { .mask = H3_EV_H3S_END, .name = "h3s_end", .desc = "H3 stream terminated" },
Amaury Denoyelle56a86dd2023-01-30 15:36:51 +010069#define H3_EV_H3C_END (1ULL << 9)
70 { .mask = H3_EV_H3C_END, .name = "h3c_end", .desc = "H3 connection terminated" },
Amaury Denoyelle016aa932022-05-30 15:49:36 +020071 { }
72};
73
74static const struct name_desc h3_trace_lockon_args[4] = {
75 /* arg1 */ { /* already used by the connection */ },
76 /* arg2 */ { .name="qcs", .desc="QUIC stream" },
77 /* arg3 */ { },
78 /* arg4 */ { }
79};
80
81static const struct name_desc h3_trace_decoding[] = {
82#define H3_VERB_CLEAN 1
83 { .name="clean", .desc="only user-friendly stuff, generally suitable for level \"user\"" },
84#define H3_VERB_MINIMAL 2
85 { .name="minimal", .desc="report only qcc/qcs state and flags, no real decoding" },
86 { /* end */ }
87};
88
89struct trace_source trace_h3 = {
90 .name = IST("h3"),
91 .desc = "HTTP/3 transcoder",
92 .arg_def = TRC_ARG1_CONN, /* TRACE()'s first argument is always a connection */
93 .default_cb = h3_trace,
94 .known_events = h3_trace_events,
95 .lockon_args = h3_trace_lockon_args,
96 .decoding = h3_trace_decoding,
97 .report_events = ~0, /* report everything by default */
98};
99
100#define TRACE_SOURCE &trace_h3
101INITCALL1(STG_REGISTER, trace_register_source, TRACE_SOURCE);
102
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100103#if defined(DEBUG_H3)
104#define h3_debug_printf fprintf
105#define h3_debug_hexdump debug_hexdump
106#else
107#define h3_debug_printf(...) do { } while (0)
108#define h3_debug_hexdump(...) do { } while (0)
109#endif
110
Amaury Denoyelle302ecd42022-05-24 15:24:32 +0200111#define H3_CF_SETTINGS_SENT 0x00000001 /* SETTINGS frame already sent on local control stream */
112#define H3_CF_SETTINGS_RECV 0x00000002 /* SETTINGS frame already received on remote control stream */
113#define H3_CF_UNI_CTRL_SET 0x00000004 /* Remote H3 Control stream opened */
114#define H3_CF_UNI_QPACK_DEC_SET 0x00000008 /* Remote QPACK decoder stream opened */
115#define H3_CF_UNI_QPACK_ENC_SET 0x00000010 /* Remote QPACK encoder stream opened */
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100116
117/* Default settings */
Amaury Denoyelle33949392021-08-24 15:16:58 +0200118static uint64_t h3_settings_qpack_max_table_capacity = 0;
119static uint64_t h3_settings_qpack_blocked_streams = 4096;
120static uint64_t h3_settings_max_field_section_size = QUIC_VARINT_8_BYTE_MAX; /* Unlimited */
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100121
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +0200122struct h3c {
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100123 struct qcc *qcc;
Amaury Denoyelled7010392022-07-13 15:17:29 +0200124 struct qcs *ctrl_strm; /* Control stream */
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100125 enum h3_err err;
126 uint32_t flags;
Amaury Denoyelle9cc47512022-05-24 16:27:41 +0200127
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100128 /* Settings */
129 uint64_t qpack_max_table_capacity;
130 uint64_t qpack_blocked_streams;
131 uint64_t max_field_section_size;
Amaury Denoyelle9cc47512022-05-24 16:27:41 +0200132
Amaury Denoyelle114c9c82022-03-28 14:53:45 +0200133 uint64_t id_goaway; /* stream ID used for a GOAWAY frame */
134
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100135 struct buffer_wait buf_wait; /* wait list for buffer allocations */
Frédéric Lécaille6f7607e2022-05-25 22:25:37 +0200136 /* Stats counters */
137 struct h3_counters *prx_counters;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100138};
139
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +0200140DECLARE_STATIC_POOL(pool_head_h3c, "h3c", sizeof(struct h3c));
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100141
Amaury Denoyelle35550642022-05-24 15:14:53 +0200142#define H3_SF_UNI_INIT 0x00000001 /* stream type not parsed for unidirectional stream */
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200143#define H3_SF_UNI_NO_H3 0x00000002 /* unidirectional stream does not carry H3 frames */
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +0100144#define H3_SF_HAVE_CLEN 0x00000004 /* content-length header is present */
Amaury Denoyelle35550642022-05-24 15:14:53 +0200145
Amaury Denoyelle67e92d32022-04-27 18:04:01 +0200146struct h3s {
Amaury Denoyellec0156792022-06-03 15:29:07 +0200147 struct h3c *h3c;
148
Amaury Denoyelle3236a8e2022-05-24 15:24:03 +0200149 enum h3s_t type;
Amaury Denoyelle8d818c62022-08-02 11:32:45 +0200150 enum h3s_st_req st_req; /* only used for request streams */
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +0200151 int demux_frame_len;
152 int demux_frame_type;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200153
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +0100154 unsigned long long body_len; /* known request body length from content-length header if present */
155 unsigned long long data_len; /* total length of all parsed DATA */
156
Amaury Denoyelle35550642022-05-24 15:14:53 +0200157 int flags;
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100158 int err; /* used for stream reset */
Amaury Denoyelle67e92d32022-04-27 18:04:01 +0200159};
160
161DECLARE_STATIC_POOL(pool_head_h3s, "h3s", sizeof(struct h3s));
162
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200163/* Initialize an uni-stream <qcs> by reading its type from <b>.
Amaury Denoyelle35550642022-05-24 15:14:53 +0200164 *
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200165 * Returns the count of consumed bytes or a negative error code.
Amaury Denoyelle35550642022-05-24 15:14:53 +0200166 */
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200167static ssize_t h3_init_uni_stream(struct h3c *h3c, struct qcs *qcs,
168 struct buffer *b)
Amaury Denoyelle35550642022-05-24 15:14:53 +0200169{
170 /* decode unidirectional stream type */
171 struct h3s *h3s = qcs->ctx;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200172 uint64_t type;
173 size_t len = 0, ret;
174
Amaury Denoyelled5581d52022-05-30 15:51:31 +0200175 TRACE_ENTER(H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
176
Amaury Denoyelle35550642022-05-24 15:14:53 +0200177 BUG_ON_HOT(!quic_stream_is_uni(qcs->id) ||
178 h3s->flags & H3_SF_UNI_INIT);
179
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200180 ret = b_quic_dec_int(&type, b, &len);
Amaury Denoyelle35550642022-05-24 15:14:53 +0200181 if (!ret) {
182 ABORT_NOW();
183 }
184
185 switch (type) {
186 case H3_UNI_S_T_CTRL:
187 if (h3c->flags & H3_CF_UNI_CTRL_SET) {
Amaury Denoyelled666d742022-07-13 15:15:58 +0200188 qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200189 return -1;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200190 }
191 h3c->flags |= H3_CF_UNI_CTRL_SET;
192 h3s->type = H3S_T_CTRL;
193 break;
194
195 case H3_UNI_S_T_PUSH:
196 /* TODO not supported for the moment */
197 h3s->type = H3S_T_PUSH;
198 break;
199
200 case H3_UNI_S_T_QPACK_DEC:
201 if (h3c->flags & H3_CF_UNI_QPACK_DEC_SET) {
Amaury Denoyelled666d742022-07-13 15:15:58 +0200202 qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200203 return -1;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200204 }
205 h3c->flags |= H3_CF_UNI_QPACK_DEC_SET;
206 h3s->type = H3S_T_QPACK_DEC;
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200207 h3s->flags |= H3_SF_UNI_NO_H3;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200208 break;
209
210 case H3_UNI_S_T_QPACK_ENC:
211 if (h3c->flags & H3_CF_UNI_QPACK_ENC_SET) {
Amaury Denoyelled666d742022-07-13 15:15:58 +0200212 qcc_emit_cc_app(qcs->qcc, H3_STREAM_CREATION_ERROR, 1);
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200213 return -1;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200214 }
215 h3c->flags |= H3_CF_UNI_QPACK_ENC_SET;
216 h3s->type = H3S_T_QPACK_ENC;
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200217 h3s->flags |= H3_SF_UNI_NO_H3;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200218 break;
219
220 default:
Amaury Denoyelle849b24f2022-05-24 17:22:07 +0200221 /* draft-ietf-quic-http34 9. Extensions to HTTP/3
222 *
223 * Implementations MUST [...] abort reading on unidirectional
224 * streams that have unknown or unsupported types.
225 */
Amaury Denoyelle663e8722022-12-09 14:58:28 +0100226 qcc_abort_stream_read(qcs);
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200227 return -1;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200228 };
229
230 h3s->flags |= H3_SF_UNI_INIT;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200231
Amaury Denoyelled5581d52022-05-30 15:51:31 +0200232 TRACE_LEAVE(H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200233 return len;
Amaury Denoyelle35550642022-05-24 15:14:53 +0200234}
235
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200236/* Parse a buffer <b> for a <qcs> uni-stream which does not contains H3 frames.
237 * This may be used for QPACK encoder/decoder streams for example. <fin> is set
238 * if this is the last frame of the stream.
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200239 *
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200240 * Returns the number of consumed bytes or a negative error code.
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200241 */
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200242static ssize_t h3_parse_uni_stream_no_h3(struct qcs *qcs, struct buffer *b, int fin)
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200243{
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200244 struct h3s *h3s = qcs->ctx;
245
246 BUG_ON_HOT(!quic_stream_is_uni(qcs->id) ||
247 !(h3s->flags & H3_SF_UNI_NO_H3));
248
249 switch (h3s->type) {
250 case H3S_T_QPACK_DEC:
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200251 if (qpack_decode_dec(b, fin, qcs))
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200252 return -1;
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200253 break;
254 case H3S_T_QPACK_ENC:
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200255 if (qpack_decode_enc(b, fin, qcs))
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200256 return -1;
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200257 break;
Amaury Denoyelle849b24f2022-05-24 17:22:07 +0200258 case H3S_T_UNKNOWN:
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200259 default:
Amaury Denoyelle849b24f2022-05-24 17:22:07 +0200260 /* Unknown stream should be flagged with QC_SF_READ_ABORTED. */
261 ABORT_NOW();
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200262 }
263
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200264 /* TODO adjust return code */
Amaury Denoyellefc99a692022-05-24 15:25:19 +0200265 return 0;
266}
267
Amaury Denoyelle88d5dd12022-05-31 11:44:52 +0200268/* Decode a H3 frame header from <rxbuf> buffer. The frame type is stored in
269 * <ftype> and length in <flen>.
270 *
271 * Returns the size of the H3 frame header. Note that the input buffer is not
272 * consumed.
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100273 */
274static inline size_t h3_decode_frm_header(uint64_t *ftype, uint64_t *flen,
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200275 struct buffer *b)
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100276{
277 size_t hlen;
278
279 hlen = 0;
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200280 if (!b_quic_dec_int(ftype, b, &hlen) ||
281 !b_quic_dec_int(flen, b, &hlen)) {
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100282 return 0;
Amaury Denoyelle88d5dd12022-05-31 11:44:52 +0200283 }
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100284
285 return hlen;
286}
287
Amaury Denoyelle302ecd42022-05-24 15:24:32 +0200288/* Check if H3 frame of type <ftype> is valid when received on stream <qcs>.
289 *
290 * Returns a boolean. If false, a connection error H3_FRAME_UNEXPECTED should
291 * be reported.
292 */
293static int h3_is_frame_valid(struct h3c *h3c, struct qcs *qcs, uint64_t ftype)
294{
295 struct h3s *h3s = qcs->ctx;
296 const uint64_t id = qcs->id;
297
298 BUG_ON_HOT(h3s->type == H3S_T_UNKNOWN);
299
300 switch (ftype) {
301 case H3_FT_DATA:
Amaury Denoyelle8d818c62022-08-02 11:32:45 +0200302 return h3s->type != H3S_T_CTRL && (h3s->st_req == H3S_ST_REQ_HEADERS ||
303 h3s->st_req == H3S_ST_REQ_DATA);
304
Amaury Denoyelle302ecd42022-05-24 15:24:32 +0200305 case H3_FT_HEADERS:
Amaury Denoyelle8d818c62022-08-02 11:32:45 +0200306 return h3s->type != H3S_T_CTRL && h3s->st_req != H3S_ST_REQ_TRAILERS;
Amaury Denoyelle302ecd42022-05-24 15:24:32 +0200307
308 case H3_FT_CANCEL_PUSH:
309 case H3_FT_GOAWAY:
310 case H3_FT_MAX_PUSH_ID:
311 /* Only allowed for control stream. First frame of control
312 * stream MUST be SETTINGS.
313 */
314 return h3s->type == H3S_T_CTRL &&
315 (h3c->flags & H3_CF_SETTINGS_RECV);
316
317 case H3_FT_SETTINGS:
318 /* draft-ietf-quic-http34 7.2.4. SETTINGS
319 *
320 * If an endpoint receives a second SETTINGS frame on the control
321 * stream, the endpoint MUST respond with a connection error of type
322 * H3_FRAME_UNEXPECTED.
323 */
324 return h3s->type == H3S_T_CTRL &&
325 !(h3c->flags & H3_CF_SETTINGS_RECV);
326
327 case H3_FT_PUSH_PROMISE:
328 return h3s->type != H3S_T_CTRL &&
329 (id & QCS_ID_SRV_INTIATOR_BIT);
330
331 default:
332 /* draft-ietf-quic-http34 9. Extensions to HTTP/3
333 *
334 * Implementations MUST discard frames [...] that have unknown
335 * or unsupported types.
336 */
337 return h3s->type != H3S_T_CTRL || (h3c->flags & H3_CF_SETTINGS_RECV);
338 }
339}
340
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +0100341/* Check from stream <qcs> that length of all DATA frames does not exceed with
342 * a previously parsed content-length header. <fin> must be set for the last
343 * data of the stream so that length of DATA frames must be equal to the
344 * content-length.
345 *
346 * This must only be called for a stream with H3_SF_HAVE_CLEN flag.
347 *
348 * Return 0 on valid else non-zero.
349 */
350static int h3_check_body_size(struct qcs *qcs, int fin)
351{
352 struct h3s *h3s = qcs->ctx;
353 int ret = 0;
354 TRACE_ENTER(H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
355
356 /* Reserved for streams with a previously parsed content-length header. */
357 BUG_ON(!(h3s->flags & H3_SF_HAVE_CLEN));
358
359 /* RFC 9114 4.1.2. Malformed Requests and Responses
360 *
361 * A request or response that is defined as having content when it
362 * contains a Content-Length header field (Section 8.6 of [HTTP]) is
363 * malformed if the value of the Content-Length header field does not
364 * equal the sum of the DATA frame lengths received.
365 *
366 * TODO for backend support
367 * A response that is
368 * defined as never having content, even when a Content-Length is
369 * present, can have a non-zero Content-Length header field even though
370 * no content is included in DATA frames.
371 */
372 if (h3s->data_len > h3s->body_len ||
373 (fin && h3s->data_len < h3s->body_len)) {
374 TRACE_ERROR("Content-length does not match DATA frame size", H3_EV_RX_FRAME|H3_EV_RX_DATA, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100375 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +0100376 ret = -1;
377 }
378
379 TRACE_LEAVE(H3_EV_RX_FRAME, qcs->qcc->conn, qcs);
380 return ret;
381}
382
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100383/* Parse from buffer <buf> a H3 HEADERS frame of length <len>. Data are copied
Willy Tarreau4596fe22022-05-17 19:07:51 +0200384 * in a local HTX buffer and transfer to the stream connector layer. <fin> must be
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100385 * set if this is the last data to transfer from this stream.
386 *
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100387 * Returns the number of consumed bytes or a negative error code. On error
388 * either the connection should be closed or the stream reset using codes
389 * provided in h3c.err / h3s.err.
Amaury Denoyelleb9ce14e2021-11-08 09:13:42 +0100390 */
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200391static ssize_t h3_headers_to_htx(struct qcs *qcs, const struct buffer *buf,
392 uint64_t len, char fin)
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100393{
Amaury Denoyelle2bc47862022-06-30 10:04:42 +0200394 struct h3s *h3s = qcs->ctx;
395 struct h3c *h3c = h3s->h3c;
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100396 struct buffer htx_buf = BUF_NULL;
397 struct buffer *tmp = get_trash_chunk();
Amaury Denoyelle7059ebc2021-12-08 15:51:04 +0100398 struct htx *htx = NULL;
Amaury Denoyelleb49fa1a2021-08-24 15:30:12 +0200399 struct htx_sl *sl;
Amaury Denoyellefd7cdc32021-08-24 15:13:20 +0200400 struct http_hdr list[global.tune.max_http_hdr];
Amaury Denoyelleb49fa1a2021-08-24 15:30:12 +0200401 unsigned int flags = HTX_SL_F_NONE;
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100402 struct ist meth = IST_NULL, path = IST_NULL;
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100403 struct ist scheme = IST_NULL, authority = IST_NULL;
Amaury Denoyelle2bc47862022-06-30 10:04:42 +0200404 int hdr_idx, ret;
Amaury Denoyelled6fb7a02022-12-07 14:31:42 +0100405 int cookie = -1, last_cookie = -1, i;
406
407 /* RFC 9114 4.1.2. Malformed Requests and Responses
408 *
409 * A malformed request or response is one that is an otherwise valid
410 * sequence of frames but is invalid due to:
411 * - the presence of prohibited fields or pseudo-header fields,
412 * - the absence of mandatory pseudo-header fields,
413 * - invalid values for pseudo-header fields,
414 * - pseudo-header fields after fields,
415 * - an invalid sequence of HTTP messages,
416 * - the inclusion of uppercase field names, or
417 * - the inclusion of invalid characters in field names or values.
418 *
419 * [...]
420 *
421 * Intermediaries that process HTTP requests or responses (i.e., any
422 * intermediary not acting as a tunnel) MUST NOT forward a malformed
423 * request or response. Malformed requests or responses that are
424 * detected MUST be treated as a stream error of type H3_MESSAGE_ERROR.
425 */
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100426
Amaury Denoyelle494512d2022-05-30 15:50:34 +0200427 TRACE_ENTER(H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
428
Amaury Denoyelle8d818c62022-08-02 11:32:45 +0200429 /* TODO support trailer parsing in this function */
430
Amaury Denoyelle30f23f52022-04-27 14:41:53 +0200431 /* TODO support buffer wrapping */
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200432 BUG_ON(b_head(buf) + len >= b_wrap(buf));
Amaury Denoyelle2bc47862022-06-30 10:04:42 +0200433 ret = qpack_decode_fs((const unsigned char *)b_head(buf), len, tmp,
434 list, sizeof(list) / sizeof(list[0]));
435 if (ret < 0) {
436 TRACE_ERROR("QPACK decoding error", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
437 h3c->err = -ret;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100438 len = -1;
439 goto out;
Amaury Denoyelle60ef19f2022-06-14 17:38:36 +0200440 }
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100441
442 qc_get_buf(qcs, &htx_buf);
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100443 BUG_ON(!b_size(&htx_buf)); /* TODO */
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100444 htx = htx_from_buf(&htx_buf);
445
446 /* first treat pseudo-header to build the start line */
447 hdr_idx = 0;
448 while (1) {
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100449 /* RFC 9114 4.3. HTTP Control Data
450 *
451 * Endpoints MUST treat a request or response that contains
452 * undefined or invalid pseudo-header fields as malformed.
453 *
454 * All pseudo-header fields MUST appear in the header section before
455 * regular header fields. Any request or response that contains a
456 * pseudo-header field that appears in a header section after a regular
457 * header field MUST be treated as malformed.
458 */
459
460 /* Stop at first non pseudo-header. */
461 if (!istmatch(list[hdr_idx].n, ist(":")))
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100462 break;
463
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100464 /* pseudo-header. Malformed name with uppercase character or
465 * invalid token will be rejected in the else clause.
466 */
467 if (isteq(list[hdr_idx].n, ist(":method"))) {
468 if (isttest(meth)) {
469 TRACE_ERROR("duplicated method pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100470 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100471 len = -1;
472 goto out;
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100473 }
474 meth = list[hdr_idx].v;
475 }
476 else if (isteq(list[hdr_idx].n, ist(":path"))) {
477 if (isttest(path)) {
478 TRACE_ERROR("duplicated path pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100479 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100480 len = -1;
481 goto out;
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100482 }
483 path = list[hdr_idx].v;
484 }
485 else if (isteq(list[hdr_idx].n, ist(":scheme"))) {
486 if (isttest(scheme)) {
487 /* duplicated pseudo-header */
488 TRACE_ERROR("duplicated scheme pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100489 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100490 len = -1;
491 goto out;
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100492 }
493 scheme = list[hdr_idx].v;
494 }
495 else if (isteq(list[hdr_idx].n, ist(":authority"))) {
496 if (isttest(authority)) {
497 TRACE_ERROR("duplicated authority pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100498 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100499 len = -1;
500 goto out;
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100501 }
502 authority = list[hdr_idx].v;
503 }
504 else {
505 TRACE_ERROR("unknown pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100506 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100507 len = -1;
508 goto out;
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100509 }
510
511 ++hdr_idx;
512 }
513
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100514 if (!istmatch(meth, ist("CONNECT"))) {
515 /* RFC 9114 4.3.1. Request Pseudo-Header Fields
516 *
517 * All HTTP/3 requests MUST include exactly one value for the :method,
518 * :scheme, and :path pseudo-header fields, unless the request is a
519 * CONNECT request; see Section 4.4.
520 */
521 if (!isttest(meth) || !isttest(scheme) || !isttest(path)) {
522 TRACE_ERROR("missing mandatory pseudo-header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100523 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100524 len = -1;
525 goto out;
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100526 }
527 }
528
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100529 flags |= HTX_SL_F_VER_11;
Amaury Denoyelle0fa14a62022-04-26 16:24:39 +0200530 flags |= HTX_SL_F_XFER_LEN;
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100531
532 sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth, path, ist("HTTP/3.0"));
Amaury Denoyelle2bc47862022-06-30 10:04:42 +0200533 if (!sl) {
534 h3c->err = H3_INTERNAL_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100535 len = -1;
536 goto out;
Amaury Denoyelle2bc47862022-06-30 10:04:42 +0200537 }
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100538
539 if (fin)
540 sl->flags |= HTX_SL_F_BODYLESS;
541
542 sl->info.req.meth = find_http_meth(meth.ptr, meth.len);
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100543
Amaury Denoyellec4913f62022-12-15 10:58:05 +0100544 if (isttest(authority)) {
545 if (!htx_add_header(htx, ist("host"), authority)) {
546 h3c->err = H3_INTERNAL_ERROR;
547 len = -1;
548 goto out;
549 }
550 }
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100551
552 /* now treat standard headers */
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100553 while (1) {
554 if (isteq(list[hdr_idx].n, ist("")))
555 break;
556
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100557 if (istmatch(list[hdr_idx].n, ist(":"))) {
558 TRACE_ERROR("pseudo-header field after fields", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100559 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100560 len = -1;
561 goto out;
Amaury Denoyelle7b5a6712022-12-07 14:33:26 +0100562 }
563
Amaury Denoyelled6fb7a02022-12-07 14:31:42 +0100564 for (i = 0; i < list[hdr_idx].n.len; ++i) {
565 const char c = list[hdr_idx].n.ptr[i];
566 if ((uint8_t)(c - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(c)) {
567 TRACE_ERROR("invalid characters in field name", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100568 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100569 len = -1;
570 goto out;
Amaury Denoyelled6fb7a02022-12-07 14:31:42 +0100571 }
572 }
573
Amaury Denoyelle115ccce2022-08-17 18:02:47 +0200574 if (isteq(list[hdr_idx].n, ist("cookie"))) {
575 http_cookie_register(list, hdr_idx, &cookie, &last_cookie);
Amaury Denoyelle19942e32022-12-15 09:18:25 +0100576 ++hdr_idx;
Amaury Denoyelle115ccce2022-08-17 18:02:47 +0200577 continue;
578 }
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +0100579 else if (isteq(list[hdr_idx].n, ist("content-length"))) {
580 ret = http_parse_cont_len_header(&list[hdr_idx].v,
581 &h3s->body_len,
582 h3s->flags & H3_SF_HAVE_CLEN);
583 if (ret < 0) {
584 TRACE_ERROR("invalid content-length", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +0100585 h3s->err = H3_MESSAGE_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100586 len = -1;
587 goto out;
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +0100588 }
589 else if (!ret) {
590 /* Skip duplicated value. */
591 ++hdr_idx;
592 continue;
593 }
594
595 h3s->flags |= H3_SF_HAVE_CLEN;
596 /* This will fail if current frame is the last one and
597 * content-length is not null.
598 */
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100599 if (h3_check_body_size(qcs, fin)) {
600 len = -1;
601 goto out;
602 }
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +0100603 }
Amaury Denoyelle8ad26692023-01-17 17:47:06 +0100604 else if (isteq(list[hdr_idx].n, ist("connection")) ||
605 isteq(list[hdr_idx].n, ist("proxy-connection")) ||
606 isteq(list[hdr_idx].n, ist("keep-alive")) ||
607 isteq(list[hdr_idx].n, ist("transfer-encoding"))) {
608 /* RFC 9114 4.2. HTTP Fields
609 *
610 * HTTP/3 does not use the Connection header field to indicate
611 * connection-specific fields; in this protocol, connection-
612 * specific metadata is conveyed by other means. An endpoint
613 * MUST NOT generate an HTTP/3 field section containing
614 * connection-specific fields; any message containing
615 * connection-specific fields MUST be treated as malformed.
616 */
617 TRACE_ERROR("invalid connection header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
618 h3s->err = H3_MESSAGE_ERROR;
619 len = -1;
620 goto out;
621 }
622 else if (isteq(list[hdr_idx].n, ist("te")) &&
623 !isteq(list[hdr_idx].v, ist("trailers"))) {
624 /* RFC 9114 4.2. HTTP Fields
625 *
626 * The only exception to this is the TE header field, which MAY
627 * be present in an HTTP/3 request header; when it is, it MUST
628 * NOT contain any value other than "trailers".
629 */
630 TRACE_ERROR("invalid te header", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
631 h3s->err = H3_MESSAGE_ERROR;
632 len = -1;
633 goto out;
634 }
Amaury Denoyelle115ccce2022-08-17 18:02:47 +0200635
Amaury Denoyellec4913f62022-12-15 10:58:05 +0100636 if (!htx_add_header(htx, list[hdr_idx].n, list[hdr_idx].v)) {
637 h3c->err = H3_INTERNAL_ERROR;
638 len = -1;
639 goto out;
640 }
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100641 ++hdr_idx;
642 }
643
Amaury Denoyelle115ccce2022-08-17 18:02:47 +0200644 if (cookie >= 0) {
645 if (http_cookie_merge(htx, list, cookie)) {
646 h3c->err = H3_INTERNAL_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100647 len = -1;
648 goto out;
Amaury Denoyelle115ccce2022-08-17 18:02:47 +0200649 }
650 }
651
Amaury Denoyellec4913f62022-12-15 10:58:05 +0100652 if (!htx_add_endof(htx, HTX_BLK_EOH)) {
653 h3c->err = H3_INTERNAL_ERROR;
654 len = -1;
655 goto out;
656 }
657
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100658 if (fin)
659 htx->flags |= HTX_FL_EOM;
660
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100661 htx_to_buf(htx, &htx_buf);
662 htx = NULL;
663
Amaury Denoyelle2bc47862022-06-30 10:04:42 +0200664 if (!qc_attach_sc(qcs, &htx_buf)) {
665 h3c->err = H3_INTERNAL_ERROR;
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100666 len = -1;
667 goto out;
Amaury Denoyelle2bc47862022-06-30 10:04:42 +0200668 }
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100669
Amaury Denoyelle114c9c82022-03-28 14:53:45 +0200670 /* RFC 9114 5.2. Connection Shutdown
671 *
672 * The GOAWAY frame contains an identifier that
673 * indicates to the receiver the range of requests or pushes that were
674 * or might be processed in this connection. The server sends a client-
675 * initiated bidirectional stream ID; the client sends a push ID.
676 * Requests or pushes with the indicated identifier or greater are
677 * rejected (Section 4.1.1) by the sender of the GOAWAY. This
678 * identifier MAY be zero if no requests or pushes were processed.
679 */
680 if (qcs->id >= h3c->id_goaway)
681 h3c->id_goaway = qcs->id + 4;
682
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100683 out:
684 /* HTX may be non NULL if error before previous htx_to_buf(). */
685 if (htx)
686 htx_to_buf(htx, &htx_buf);
687
Willy Tarreau4596fe22022-05-17 19:07:51 +0200688 /* buffer is transferred to the stream connector and set to NULL
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100689 * except on stream creation error.
690 */
Amaury Denoyelle788fc052022-12-15 10:53:55 +0100691 if (b_size(&htx_buf)) {
692 b_free(&htx_buf);
693 offer_buffers(NULL, 1);
694 }
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100695
Amaury Denoyelle494512d2022-05-30 15:50:34 +0200696 TRACE_LEAVE(H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle314578a2022-04-27 14:52:52 +0200697 return len;
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100698}
699
Amaury Denoyelleedfcb552023-01-13 16:40:31 +0100700/* Parse from buffer <buf> a H3 HEADERS frame of length <len> used as trailers.
701 * Data are copied in a local HTX buffer and transfer to the stream connector
702 * layer. <fin> must be set if this is the last data to transfer from this
703 * stream.
704 *
705 * Returns the number of consumed bytes or a negative error code. On error
706 * either the connection should be closed or the stream reset using codes
707 * provided in h3c.err / h3s.err.
708 */
709static ssize_t h3_trailers_to_htx(struct qcs *qcs, const struct buffer *buf,
710 uint64_t len, char fin)
711{
712 struct h3s *h3s = qcs->ctx;
713 struct h3c *h3c = h3s->h3c;
714 struct buffer htx_buf = BUF_NULL;
715 struct buffer *tmp = get_trash_chunk();
716 struct htx *htx = NULL;
717 struct htx_sl *sl;
718 struct http_hdr list[global.tune.max_http_hdr];
719 int hdr_idx, ret;
720 int i;
721
722 TRACE_ENTER(H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
723
724 /* TODO support buffer wrapping */
725 BUG_ON(b_head(buf) + len >= b_wrap(buf));
726 ret = qpack_decode_fs((const unsigned char *)b_head(buf), len, tmp,
727 list, sizeof(list) / sizeof(list[0]));
728 if (ret < 0) {
729 TRACE_ERROR("QPACK decoding error", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
730 h3c->err = -ret;
731 len = -1;
732 goto out;
733 }
734
735 qc_get_buf(qcs, &htx_buf);
736 BUG_ON(!b_size(&htx_buf)); /* TODO */
737 htx = htx_from_buf(&htx_buf);
738
739 if (!h3s->data_len) {
740 /* Notify that no body is present. This can only happens if
741 * there is H3 HEADERS as trailers without or empty H3 DATA
742 * frame. So this is probably not realistice ?
743 *
744 * TODO if sl is NULL because already consumed there is no way
745 * to notify about missing body.
746 */
747 sl = http_get_stline(htx);
748 if (sl)
749 sl->flags |= HTX_SL_F_BODYLESS;
750 else
751 TRACE_ERROR("cannot notify missing body after trailers", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
752 }
753
754 hdr_idx = 0;
755 while (1) {
756 if (isteq(list[hdr_idx].n, ist("")))
757 break;
758
759 /* RFC 9114 4.3. HTTP Control Data
760 *
761 * Pseudo-header
762 * fields MUST NOT appear in trailer sections.
763 */
764 if (istmatch(list[hdr_idx].n, ist(":"))) {
765 TRACE_ERROR("pseudo-header field in trailers", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
766 h3s->err = H3_MESSAGE_ERROR;
767 len = -1;
768 goto out;
769 }
770
771 for (i = 0; i < list[hdr_idx].n.len; ++i) {
772 const char c = list[hdr_idx].n.ptr[i];
773 if ((uint8_t)(c - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(c)) {
774 TRACE_ERROR("invalid characters in field name", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
775 h3s->err = H3_MESSAGE_ERROR;
776 len = -1;
777 goto out;
778 }
779 }
780
781 /* forbidden HTTP/3 headers, cf h3_headers_to_htx() */
782 if (isteq(list[hdr_idx].n, ist("host")) ||
783 isteq(list[hdr_idx].n, ist("content-length")) ||
784 isteq(list[hdr_idx].n, ist("connection")) ||
785 isteq(list[hdr_idx].n, ist("proxy-connection")) ||
786 isteq(list[hdr_idx].n, ist("keep-alive")) ||
787 isteq(list[hdr_idx].n, ist("te")) ||
788 isteq(list[hdr_idx].n, ist("transfer-encoding"))) {
789 TRACE_ERROR("forbidden HTTP/3 headers", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
790 h3s->err = H3_MESSAGE_ERROR;
791 len = -1;
792 goto out;
793 }
794
795 if (!htx_add_trailer(htx, list[hdr_idx].n, list[hdr_idx].v)) {
796 TRACE_ERROR("cannot add trailer", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
797 h3c->err = H3_INTERNAL_ERROR;
798 len = -1;
799 goto out;
800 }
801
802 ++hdr_idx;
803 }
804
805 if (!htx_add_endof(htx, HTX_BLK_EOT)) {
806 TRACE_ERROR("cannot add trailer", H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
807 h3c->err = H3_INTERNAL_ERROR;
808 len = -1;
809 goto out;
810 }
811
812 if (fin)
813 htx->flags |= HTX_FL_EOM;
814
815 htx_to_buf(htx, &htx_buf);
816 htx = NULL;
817
818 out:
819 /* HTX may be non NULL if error before previous htx_to_buf(). */
820 if (htx)
821 htx_to_buf(htx, &htx_buf);
822
823 TRACE_LEAVE(H3_EV_RX_FRAME|H3_EV_RX_HDR, qcs->qcc->conn, qcs);
824 return len;
825}
826
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100827/* Copy from buffer <buf> a H3 DATA frame of length <len> in QUIC stream <qcs>
828 * HTX buffer. <fin> must be set if this is the last data to transfer from this
829 * stream.
830 *
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200831 * Returns the number of consumed bytes or a negative error code.
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100832 */
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200833static ssize_t h3_data_to_htx(struct qcs *qcs, const struct buffer *buf,
834 uint64_t len, char fin)
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100835{
836 struct buffer *appbuf;
837 struct htx *htx = NULL;
Amaury Denoyelle1290f1e2022-05-13 14:49:05 +0200838 size_t htx_sent = 0;
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100839 int htx_space;
Amaury Denoyelle30f23f52022-04-27 14:41:53 +0200840 char *head;
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100841
Amaury Denoyelle494512d2022-05-30 15:50:34 +0200842 TRACE_ENTER(H3_EV_RX_FRAME|H3_EV_RX_DATA, qcs->qcc->conn, qcs);
843
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100844 appbuf = qc_get_buf(qcs, &qcs->rx.app_buf);
845 BUG_ON(!appbuf);
846 htx = htx_from_buf(appbuf);
847
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200848 if (len > b_data(buf)) {
849 len = b_data(buf);
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +0200850 fin = 0;
851 }
852
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200853 head = b_head(buf);
Amaury Denoyelle30f23f52022-04-27 14:41:53 +0200854 retry:
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100855 htx_space = htx_free_data_space(htx);
Amaury Denoyellef1fc0b32022-05-02 11:07:06 +0200856 if (!htx_space) {
857 qcs->flags |= QC_SF_DEM_FULL;
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +0200858 goto out;
Amaury Denoyellef1fc0b32022-05-02 11:07:06 +0200859 }
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +0200860
861 if (len > htx_space) {
862 len = htx_space;
863 fin = 0;
Amaury Denoyelleff191de2022-02-21 18:38:29 +0100864 }
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100865
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200866 if (head + len > b_wrap(buf)) {
867 size_t contig = b_wrap(buf) - head;
868 htx_sent = htx_add_data(htx, ist2(b_head(buf), contig));
Amaury Denoyelle73d6ffe2022-05-16 13:54:31 +0200869 if (htx_sent < contig) {
870 qcs->flags |= QC_SF_DEM_FULL;
871 goto out;
872 }
873
Amaury Denoyelle30f23f52022-04-27 14:41:53 +0200874 len -= contig;
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200875 head = b_orig(buf);
Amaury Denoyelle30f23f52022-04-27 14:41:53 +0200876 goto retry;
Amaury Denoyelleff191de2022-02-21 18:38:29 +0100877 }
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100878
Amaury Denoyelle30f23f52022-04-27 14:41:53 +0200879 htx_sent += htx_add_data(htx, ist2(head, len));
Amaury Denoyelle73d6ffe2022-05-16 13:54:31 +0200880 if (htx_sent < len) {
881 qcs->flags |= QC_SF_DEM_FULL;
882 goto out;
883 }
Amaury Denoyelle30f23f52022-04-27 14:41:53 +0200884
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +0200885 if (fin && len == htx_sent)
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100886 htx->flags |= HTX_FL_EOM;
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100887
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +0200888 out:
889 htx_to_buf(htx, appbuf);
Amaury Denoyelle494512d2022-05-30 15:50:34 +0200890
891 TRACE_LEAVE(H3_EV_RX_FRAME|H3_EV_RX_DATA, qcs->qcc->conn, qcs);
Amaury Denoyelle314578a2022-04-27 14:52:52 +0200892 return htx_sent;
Amaury Denoyelle91379f72022-02-14 17:14:59 +0100893}
894
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200895/* Parse a SETTINGS frame of length <len> of payload <buf>.
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200896 *
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200897 * Returns the number of consumed bytes or a negative error code.
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200898 */
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200899static ssize_t h3_parse_settings_frm(struct h3c *h3c, const struct buffer *buf,
900 size_t len)
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200901{
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +0200902 struct buffer b;
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200903 uint64_t id, value;
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +0200904 size_t ret = 0;
905 long mask = 0; /* used to detect duplicated settings identifier */
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200906
Amaury Denoyelle494512d2022-05-30 15:50:34 +0200907 TRACE_ENTER(H3_EV_RX_FRAME|H3_EV_RX_SETTINGS, h3c->qcc->conn);
908
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200909 /* Work on a copy of <buf>. */
Amaury Denoyelle3a2fcfd2022-06-09 11:54:38 +0200910 b = b_make(b_orig(buf), b_size(buf), b_head_ofs(buf), len);
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200911
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +0200912 while (b_data(&b)) {
913 if (!b_quic_dec_int(&id, &b, &ret) || !b_quic_dec_int(&value, &b, &ret)) {
914 h3c->err = H3_FRAME_ERROR;
915 return -1;
916 }
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200917
918 h3_debug_printf(stderr, "%s id: %llu value: %llu\n",
919 __func__, (unsigned long long)id, (unsigned long long)value);
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +0200920
921 /* draft-ietf-quic-http34 7.2.4. SETTINGS
922 *
923 * The same setting identifier MUST NOT occur more than once in the
924 * SETTINGS frame. A receiver MAY treat the presence of duplicate
925 * setting identifiers as a connection error of type H3_SETTINGS_ERROR.
926 */
927
928 /* Ignore duplicate check for ID too big used for GREASE. */
929 if (id < sizeof(mask)) {
930 if (ha_bit_test(id, &mask)) {
931 h3c->err = H3_SETTINGS_ERROR;
932 return -1;
933 }
934 ha_bit_set(id, &mask);
935 }
936
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200937 switch (id) {
938 case H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY:
939 h3c->qpack_max_table_capacity = value;
940 break;
941 case H3_SETTINGS_MAX_FIELD_SECTION_SIZE:
942 h3c->max_field_section_size = value;
943 break;
944 case H3_SETTINGS_QPACK_BLOCKED_STREAMS:
945 h3c->qpack_blocked_streams = value;
946 break;
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +0200947
948 case H3_SETTINGS_RESERVED_0:
949 case H3_SETTINGS_RESERVED_2:
950 case H3_SETTINGS_RESERVED_3:
951 case H3_SETTINGS_RESERVED_4:
952 case H3_SETTINGS_RESERVED_5:
953 /* draft-ietf-quic-http34 7.2.4.1. Defined SETTINGS Parameters
954 *
955 * Setting identifiers which were defined in [HTTP2] where there is no
956 * corresponding HTTP/3 setting have also been reserved
957 * (Section 11.2.2). These reserved settings MUST NOT be sent, and
958 * their receipt MUST be treated as a connection error of type
959 * H3_SETTINGS_ERROR.
960 */
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200961 h3c->err = H3_SETTINGS_ERROR;
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +0200962 return -1;
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200963 default:
964 /* MUST be ignored */
965 break;
966 }
967 }
968
Frédéric Lécaillebefcf702022-09-08 16:04:55 +0200969 TRACE_LEAVE(H3_EV_RX_FRAME|H3_EV_RX_SETTINGS, h3c->qcc->conn);
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +0200970 return ret;
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200971}
972
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100973/* Decode <qcs> remotely initiated bidi-stream. <fin> must be set to indicate
974 * that we received the last data of the stream.
Amaury Denoyelle0ffd6e72022-05-24 11:07:28 +0200975 *
976 * Returns 0 on success else non-zero.
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100977 */
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200978static ssize_t h3_decode_qcs(struct qcs *qcs, struct buffer *b, int fin)
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100979{
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +0200980 struct h3s *h3s = qcs->ctx;
Amaury Denoyellec0156792022-06-03 15:29:07 +0200981 struct h3c *h3c = h3s->h3c;
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200982 ssize_t total = 0, ret;
Amaury Denoyelle7b0f1222022-02-14 17:13:55 +0100983
Amaury Denoyellebb970422022-04-12 16:40:52 +0200984 h3_debug_printf(stderr, "%s: STREAM ID: %lu\n", __func__, qcs->id);
Amaury Denoyelle62eef852022-06-03 16:40:34 +0200985 if (!b_data(b))
Frédéric Lécailleccac11f2021-03-03 16:09:02 +0100986 return 0;
987
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200988 if (quic_stream_is_uni(qcs->id) && !(h3s->flags & H3_SF_UNI_INIT)) {
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200989 if ((ret = h3_init_uni_stream(h3c, qcs, b)) < 0)
990 return -1;
991
992 total += ret;
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +0200993 }
994
995 if (quic_stream_is_uni(qcs->id) && (h3s->flags & H3_SF_UNI_NO_H3)) {
996 /* For non-h3 STREAM, parse it and return immediately. */
Amaury Denoyelle26aa3992022-08-16 17:42:47 +0200997 if ((ret = h3_parse_uni_stream_no_h3(qcs, b, fin)) < 0)
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +0200998 return -1;
999
1000 total += ret;
1001 return total;
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +02001002 }
1003
Amaury Denoyelle6b02c6b2022-08-16 17:16:47 +02001004 /* RFC 9114 6.2.1. Control Streams
1005 *
1006 * The sender MUST NOT close the control stream, and the receiver MUST NOT
1007 * request that the sender close the control stream. If either control
1008 * stream is closed at any point, this MUST be treated as a connection
1009 * error of type H3_CLOSED_CRITICAL_STREAM.
1010 */
1011 if (h3s->type == H3S_T_CTRL && fin) {
1012 qcc_emit_cc_app(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
1013 return -1;
1014 }
1015
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +01001016 while (b_data(b) && !(qcs->flags & QC_SF_DEM_FULL) && !h3c->err && !h3s->err) {
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001017 uint64_t ftype, flen;
Amaury Denoyelle95b93a32022-02-14 15:49:53 +01001018 char last_stream_frame = 0;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001019
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001020 if (!h3s->demux_frame_len) {
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +01001021 /* Switch to a new frame. */
Amaury Denoyelle62eef852022-06-03 16:40:34 +02001022 size_t hlen = h3_decode_frm_header(&ftype, &flen, b);
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001023 if (!hlen)
1024 break;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001025
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001026 h3_debug_printf(stderr, "%s: ftype: %lu, flen: %lu\n",
1027 __func__, ftype, flen);
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001028
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001029 h3s->demux_frame_type = ftype;
1030 h3s->demux_frame_len = flen;
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +02001031 total += hlen;
Amaury Denoyelle417c7c02022-05-31 14:18:33 +02001032
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +01001033 /* Check that content-length is not exceeded on a new DATA frame. */
1034 if (ftype == H3_FT_DATA) {
1035 h3s->data_len += flen;
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +01001036 if (h3s->flags & H3_SF_HAVE_CLEN && h3_check_body_size(qcs, fin))
1037 break;
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +01001038 }
1039
Amaury Denoyelle417c7c02022-05-31 14:18:33 +02001040 if (!h3_is_frame_valid(h3c, qcs, ftype)) {
Amaury Denoyelled666d742022-07-13 15:15:58 +02001041 qcc_emit_cc_app(qcs->qcc, H3_FRAME_UNEXPECTED, 1);
Amaury Denoyelledca4c532022-06-07 18:24:34 +02001042 return -1;
Amaury Denoyelle417c7c02022-05-31 14:18:33 +02001043 }
1044
Amaury Denoyelle62eef852022-06-03 16:40:34 +02001045 if (!b_data(b))
Amaury Denoyelle417c7c02022-05-31 14:18:33 +02001046 break;
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001047 }
Amaury Denoyelle0484f922022-02-15 16:59:39 +01001048
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001049 flen = h3s->demux_frame_len;
1050 ftype = h3s->demux_frame_type;
Amaury Denoyelle80097cc2022-05-24 11:13:46 +02001051
1052 /* Do not demux incomplete frames except H3 DATA which can be
1053 * fragmented in multiple HTX blocks.
1054 */
Amaury Denoyelle62eef852022-06-03 16:40:34 +02001055 if (flen > b_data(b) && ftype != H3_FT_DATA) {
Amaury Denoyelle80097cc2022-05-24 11:13:46 +02001056 /* Reject frames bigger than bufsize.
1057 *
1058 * TODO HEADERS should in complement be limited with H3
1059 * SETTINGS_MAX_FIELD_SECTION_SIZE parameter to prevent
1060 * excessive decompressed size.
1061 */
Amaury Denoyelle62eef852022-06-03 16:40:34 +02001062 if (flen > QC_S_RX_BUF_SZ) {
Amaury Denoyelled666d742022-07-13 15:15:58 +02001063 qcc_emit_cc_app(qcs->qcc, H3_EXCESSIVE_LOAD, 1);
Amaury Denoyelledca4c532022-06-07 18:24:34 +02001064 return -1;
Amaury Denoyelle80097cc2022-05-24 11:13:46 +02001065 }
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001066 break;
Amaury Denoyelleb5454d42022-05-12 16:56:16 +02001067 }
Amaury Denoyelle80097cc2022-05-24 11:13:46 +02001068
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +01001069 /* Check content-length equality with DATA frames length on the last frame. */
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +01001070 if (fin && h3s->flags & H3_SF_HAVE_CLEN && h3_check_body_size(qcs, fin))
1071 break;
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +01001072
Amaury Denoyelle62eef852022-06-03 16:40:34 +02001073 last_stream_frame = (fin && flen == b_data(b));
Amaury Denoyelle95b93a32022-02-14 15:49:53 +01001074
Frédéric Lécaille6f7607e2022-05-25 22:25:37 +02001075 h3_inc_frame_type_cnt(h3c->prx_counters, ftype);
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001076 switch (ftype) {
1077 case H3_FT_DATA:
Amaury Denoyelle62eef852022-06-03 16:40:34 +02001078 ret = h3_data_to_htx(qcs, b, flen, last_stream_frame);
Amaury Denoyelle8d818c62022-08-02 11:32:45 +02001079 h3s->st_req = H3S_ST_REQ_DATA;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001080 break;
1081 case H3_FT_HEADERS:
Amaury Denoyelleedfcb552023-01-13 16:40:31 +01001082 if (h3s->st_req == H3S_ST_REQ_BEFORE) {
1083 ret = h3_headers_to_htx(qcs, b, flen, last_stream_frame);
1084 h3s->st_req = H3S_ST_REQ_HEADERS;
1085 }
1086 else {
1087 ret = h3_trailers_to_htx(qcs, b, flen, last_stream_frame);
1088 h3s->st_req = H3S_ST_REQ_TRAILERS;
1089 }
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001090 break;
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +02001091 case H3_FT_CANCEL_PUSH:
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001092 case H3_FT_PUSH_PROMISE:
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +02001093 case H3_FT_MAX_PUSH_ID:
1094 case H3_FT_GOAWAY:
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001095 /* Not supported */
Amaury Denoyelle80097cc2022-05-24 11:13:46 +02001096 ret = flen;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001097 break;
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +02001098 case H3_FT_SETTINGS:
Amaury Denoyelle62eef852022-06-03 16:40:34 +02001099 ret = h3_parse_settings_frm(qcs->qcc->ctx, b, flen);
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +02001100 if (ret < 0) {
Amaury Denoyelled666d742022-07-13 15:15:58 +02001101 qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
Amaury Denoyelledca4c532022-06-07 18:24:34 +02001102 return -1;
Amaury Denoyelle8c6176b2022-05-24 18:16:49 +02001103 }
1104 h3c->flags |= H3_CF_SETTINGS_RECV;
Amaury Denoyellef8db5aa2022-05-24 15:26:07 +02001105 break;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001106 default:
Amaury Denoyelled1acaf92021-11-15 15:52:55 +01001107 /* draft-ietf-quic-http34 9. Extensions to HTTP/3
Amaury Denoyelle302ecd42022-05-24 15:24:32 +02001108 *
1109 * Implementations MUST discard frames [...] that have unknown
1110 * or unsupported types.
Amaury Denoyelled1acaf92021-11-15 15:52:55 +01001111 */
1112 h3_debug_printf(stderr, "ignore unknown frame type 0x%lx\n", ftype);
Amaury Denoyelle80097cc2022-05-24 11:13:46 +02001113 ret = flen;
1114 break;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001115 }
Amaury Denoyelle314578a2022-04-27 14:52:52 +02001116
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +01001117 if (ret > 0) {
Amaury Denoyelle291ee252022-05-02 10:35:39 +02001118 BUG_ON(h3s->demux_frame_len < ret);
1119 h3s->demux_frame_len -= ret;
Amaury Denoyelle62eef852022-06-03 16:40:34 +02001120 b_del(b, ret);
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +02001121 total += ret;
Amaury Denoyelle291ee252022-05-02 10:35:39 +02001122 }
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001123 }
1124
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +01001125 /* Interrupt decoding on stream/connection error detected. */
1126 if (h3s->err) {
1127 qcc_abort_stream_read(qcs);
1128 qcc_reset_stream(qcs, h3s->err);
1129 return b_data(b);
1130 }
1131 else if (h3c->err) {
1132 qcc_emit_cc_app(qcs->qcc, h3c->err, 1);
1133 return b_data(b);
1134 }
1135
Amaury Denoyelle03cc62c2022-04-27 16:53:16 +02001136 /* TODO may be useful to wakeup the MUX if blocked due to full buffer.
1137 * However, currently, io-cb of MUX does not handle Rx.
1138 */
1139
Amaury Denoyelle1f21ebd2022-06-07 17:30:55 +02001140 return total;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001141}
1142
Amaury Denoyellea5871362021-10-07 16:26:12 +02001143/* Returns buffer for data sending.
1144 * May be NULL if the allocation failed.
1145 */
1146static struct buffer *mux_get_buf(struct qcs *qcs)
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001147{
Amaury Denoyellea5871362021-10-07 16:26:12 +02001148 if (!b_size(&qcs->tx.buf))
1149 b_alloc(&qcs->tx.buf);
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001150
Amaury Denoyellea5871362021-10-07 16:26:12 +02001151 return &qcs->tx.buf;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001152}
1153
Amaury Denoyelle6b923942022-05-23 14:25:53 +02001154/* Function used to emit stream data from <qcs> control uni-stream */
1155static int h3_control_send(struct qcs *qcs, void *ctx)
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001156{
1157 int ret;
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001158 struct h3c *h3c = ctx;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001159 unsigned char data[(2 + 3) * 2 * QUIC_VARINT_MAX_SIZE]; /* enough for 3 settings */
Amaury Denoyellea5871362021-10-07 16:26:12 +02001160 struct buffer pos, *res;
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001161 size_t frm_len;
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001162
Amaury Denoyellea717eb72022-05-30 15:51:01 +02001163 TRACE_ENTER(H3_EV_TX_SETTINGS, qcs->qcc->conn, qcs);
1164
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001165 BUG_ON_HOT(h3c->flags & H3_CF_SETTINGS_SENT);
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001166
1167 ret = 0;
Amaury Denoyellea5871362021-10-07 16:26:12 +02001168 pos = b_make((char *)data, sizeof(data), 0, 0);
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001169
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001170 frm_len = quic_int_getsize(H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY) +
1171 quic_int_getsize(h3_settings_qpack_max_table_capacity) +
1172 quic_int_getsize(H3_SETTINGS_QPACK_BLOCKED_STREAMS) +
1173 quic_int_getsize(h3_settings_qpack_blocked_streams);
1174 if (h3_settings_max_field_section_size) {
1175 frm_len += quic_int_getsize(H3_SETTINGS_MAX_FIELD_SECTION_SIZE) +
1176 quic_int_getsize(h3_settings_max_field_section_size);
1177 }
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001178
Amaury Denoyelle7d78eff2023-01-17 15:21:16 +01001179 b_quic_enc_int(&pos, H3_UNI_S_T_CTRL, 0);
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001180 /* Build a SETTINGS frame */
Amaury Denoyelle7d78eff2023-01-17 15:21:16 +01001181 b_quic_enc_int(&pos, H3_FT_SETTINGS, 0);
1182 b_quic_enc_int(&pos, frm_len, 0);
1183 b_quic_enc_int(&pos, H3_SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0);
1184 b_quic_enc_int(&pos, h3_settings_qpack_max_table_capacity, 0);
1185 b_quic_enc_int(&pos, H3_SETTINGS_QPACK_BLOCKED_STREAMS, 0);
1186 b_quic_enc_int(&pos, h3_settings_qpack_blocked_streams, 0);
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001187 if (h3_settings_max_field_section_size) {
Amaury Denoyelle7d78eff2023-01-17 15:21:16 +01001188 b_quic_enc_int(&pos, H3_SETTINGS_MAX_FIELD_SECTION_SIZE, 0);
1189 b_quic_enc_int(&pos, h3_settings_max_field_section_size, 0);
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001190 }
Amaury Denoyellea5871362021-10-07 16:26:12 +02001191
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001192 res = mux_get_buf(qcs);
1193 if (b_room(res) < b_data(&pos)) {
1194 // TODO the mux should be put in blocked state, with
1195 // the stream in state waiting for settings to be sent
1196 ABORT_NOW();
1197 }
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001198
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001199 ret = b_force_xfer(res, &pos, b_data(&pos));
Amaury Denoyelle20f2a422023-01-03 14:39:24 +01001200 if (ret > 0) {
1201 /* Register qcs for sending before other streams. */
Amaury Denoyellef9b03262023-01-09 10:34:25 +01001202 qcc_send_stream(qcs, 1);
Amaury Denoyelle65df3ad2022-05-24 15:06:10 +02001203 h3c->flags |= H3_CF_SETTINGS_SENT;
Amaury Denoyelle20f2a422023-01-03 14:39:24 +01001204 }
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001205
Amaury Denoyellea717eb72022-05-30 15:51:01 +02001206 TRACE_LEAVE(H3_EV_TX_SETTINGS, qcs->qcc->conn, qcs);
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001207 return ret;
1208}
1209
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001210static int h3_resp_headers_send(struct qcs *qcs, struct htx *htx)
1211{
1212 struct buffer outbuf;
1213 struct buffer headers_buf = BUF_NULL;
1214 struct buffer *res;
1215 struct http_hdr list[global.tune.max_http_hdr];
1216 struct htx_sl *sl;
1217 struct htx_blk *blk;
1218 enum htx_blk_type type;
1219 int frame_length_size; /* size in bytes of frame length varint field */
1220 int ret = 0;
1221 int hdr;
1222 int status = 0;
1223
Amaury Denoyellea717eb72022-05-30 15:51:01 +02001224 TRACE_ENTER(H3_EV_TX_HDR, qcs->qcc->conn, qcs);
1225
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001226 sl = NULL;
1227 hdr = 0;
1228 for (blk = htx_get_head_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) {
1229 type = htx_get_blk_type(blk);
1230
1231 if (type == HTX_BLK_UNUSED)
1232 continue;
1233
1234 if (type == HTX_BLK_EOH)
1235 break;
1236
1237 if (type == HTX_BLK_RES_SL) {
1238 /* start-line -> HEADERS h3 frame */
1239 BUG_ON(sl);
1240 sl = htx_get_blk_ptr(htx, blk);
1241 /* TODO should be on h3 layer */
1242 status = sl->info.res.status;
1243 }
1244 else if (type == HTX_BLK_HDR) {
Amaury Denoyelle60ef19f2022-06-14 17:38:36 +02001245 if (unlikely(hdr >= sizeof(list) / sizeof(list[0]) - 1))
Amaury Denoyellefa7fadc2022-06-15 15:52:27 +02001246 goto err;
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001247 list[hdr].n = htx_get_blk_name(htx, blk);
1248 list[hdr].v = htx_get_blk_value(htx, blk);
1249 hdr++;
1250 }
1251 else {
1252 ABORT_NOW();
1253 goto err;
1254 }
1255 }
1256
1257 BUG_ON(!sl);
1258
1259 list[hdr].n = ist("");
1260
Amaury Denoyelled3d97c62021-10-05 11:45:58 +02001261 res = mux_get_buf(qcs);
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001262
1263 /* At least 5 bytes to store frame type + length as a varint max size */
1264 if (b_room(res) < 5)
1265 ABORT_NOW();
1266
1267 b_reset(&outbuf);
1268 outbuf = b_make(b_tail(res), b_contig_space(res), 0, 0);
1269 /* Start the headers after frame type + length */
1270 headers_buf = b_make(b_head(res) + 5, b_size(res) - 5, 0, 0);
1271
1272 if (qpack_encode_field_section_line(&headers_buf))
1273 ABORT_NOW();
1274 if (qpack_encode_int_status(&headers_buf, status))
1275 ABORT_NOW();
1276
1277 for (hdr = 0; hdr < sizeof(list) / sizeof(list[0]); ++hdr) {
1278 if (isteq(list[hdr].n, ist("")))
1279 break;
1280
Amaury Denoyelle8ad26692023-01-17 17:47:06 +01001281 /* RFC 9114 4.2. HTTP Fields
1282 *
1283 * An intermediary transforming an HTTP/1.x message to HTTP/3
1284 * MUST remove connection-specific header fields as discussed in
1285 * Section 7.6.1 of [HTTP], or their messages will be treated by
1286 * other HTTP/3 endpoints as malformed.
Amaury Denoyelleffafb3d2022-02-15 16:10:42 +01001287 */
Amaury Denoyelle8ad26692023-01-17 17:47:06 +01001288 if (isteq(list[hdr].n, ist("connection")) ||
1289 isteq(list[hdr].n, ist("proxy-connection")) ||
1290 isteq(list[hdr].n, ist("keep-alive")) ||
1291 isteq(list[hdr].n, ist("transfer-encoding"))) {
Amaury Denoyelleffafb3d2022-02-15 16:10:42 +01001292 continue;
Amaury Denoyelle8ad26692023-01-17 17:47:06 +01001293 }
1294 else if (isteq(list[hdr].n, ist("te"))) {
1295 /* "te" may only be sent with "trailers" if this value
1296 * is present, otherwise it must be deleted.
1297 */
1298 const struct ist v = istist(list[hdr].v, ist("trailers"));
1299 if (!isttest(v) || (v.len > 8 && v.ptr[8] != ','))
1300 continue;
1301 list[hdr].v = ist("trailers");
1302 }
Amaury Denoyelleffafb3d2022-02-15 16:10:42 +01001303
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001304 if (qpack_encode_header(&headers_buf, list[hdr].n, list[hdr].v))
1305 ABORT_NOW();
1306 }
1307
1308 /* Now that all headers are encoded, we are certain that res buffer is
1309 * big enough
1310 */
1311 frame_length_size = quic_int_getsize(b_data(&headers_buf));
1312 res->head += 4 - frame_length_size;
1313 b_putchr(res, 0x01); /* h3 HEADERS frame type */
Amaury Denoyelle7d78eff2023-01-17 15:21:16 +01001314 if (!b_quic_enc_int(res, b_data(&headers_buf), 0))
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001315 ABORT_NOW();
1316 b_add(res, b_data(&headers_buf));
1317
1318 ret = 0;
1319 blk = htx_get_head_blk(htx);
1320 while (blk) {
1321 type = htx_get_blk_type(blk);
1322 ret += htx_get_blksz(blk);
1323 blk = htx_remove_blk(htx, blk);
1324 if (type == HTX_BLK_EOH)
1325 break;
1326 }
1327
Amaury Denoyellea717eb72022-05-30 15:51:01 +02001328 TRACE_LEAVE(H3_EV_TX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001329 return ret;
1330
1331 err:
Amaury Denoyellea717eb72022-05-30 15:51:01 +02001332 TRACE_DEVEL("leaving on error", H3_EV_TX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001333 return 0;
1334}
1335
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001336/* Convert a series of HTX trailer blocks from <htx> buffer into <qcs> buffer
1337 * as a H3 HEADERS frame. H3 forbidden trailers are skipped. HTX trailer blocks
1338 * are removed from <htx> until EOT is found and itself removed.
1339 *
1340 * If only a EOT HTX block is present without trailer, no H3 frame is produced.
1341 * Caller is responsible to emit an empty QUIC STREAM frame to signal the end
1342 * of the stream.
1343 *
1344 * Returns the size of HTX blocks removed.
1345 */
1346static int h3_resp_trailers_send(struct qcs *qcs, struct htx *htx)
1347{
1348 struct buffer headers_buf = BUF_NULL;
1349 struct buffer *res;
1350 struct http_hdr list[global.tune.max_http_hdr];
1351 struct htx_blk *blk;
1352 enum htx_blk_type type;
1353 char *tail;
1354 int ret = 0;
1355 int hdr;
1356
1357 TRACE_ENTER(H3_EV_TX_HDR, qcs->qcc->conn, qcs);
1358
1359 hdr = 0;
1360 for (blk = htx_get_head_blk(htx); blk; blk = htx_get_next_blk(htx, blk)) {
1361 type = htx_get_blk_type(blk);
1362
1363 if (type == HTX_BLK_UNUSED)
1364 continue;
1365
1366 if (type == HTX_BLK_EOT)
1367 break;
1368
1369 if (type == HTX_BLK_TLR) {
1370 if (unlikely(hdr >= sizeof(list) / sizeof(list[0]) - 1))
1371 goto err;
1372 list[hdr].n = htx_get_blk_name(htx, blk);
1373 list[hdr].v = htx_get_blk_value(htx, blk);
1374 hdr++;
1375 }
1376 else {
1377 TRACE_ERROR("unexpected HTX block", H3_EV_TX_HDR, qcs->qcc->conn, qcs);
1378 goto err;
1379 }
1380 }
1381
Amaury Denoyelle4be54352023-01-26 17:49:21 +01001382 if (!hdr) {
1383 /* No headers encoded here so no need to generate a H3 HEADERS
1384 * frame. Mux will send an empty QUIC STREAM frame with FIN.
1385 */
1386 TRACE_DATA("skipping trailer", H3_EV_TX_HDR, qcs->qcc->conn, qcs);
1387 goto end;
1388 }
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001389 list[hdr].n = ist("");
1390
1391 res = mux_get_buf(qcs);
1392
1393 /* At least 9 bytes to store frame type + length as a varint max size */
1394 if (b_room(res) < 9) {
1395 qcs->flags |= QC_SF_BLK_MROOM;
1396 goto err;
1397 }
1398
1399 /* Force buffer realignment as size required to encode headers is unknown. */
1400 if (b_space_wraps(res))
1401 b_slow_realign(res, trash.area, b_data(res));
1402 /* Start the headers after frame type + length */
1403 headers_buf = b_make(b_peek(res, b_data(res) + 9), b_contig_space(res) - 9, 0, 0);
1404
Amaury Denoyelle224ba5c2023-01-26 17:41:58 +01001405 if (qpack_encode_field_section_line(&headers_buf)) {
1406 qcs->flags |= QC_SF_BLK_MROOM;
1407 goto err;
1408 }
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001409
1410 tail = b_tail(&headers_buf);
1411 for (hdr = 0; hdr < sizeof(list) / sizeof(list[0]); ++hdr) {
1412 if (isteq(list[hdr].n, ist("")))
1413 break;
1414
1415 /* forbidden HTTP/3 headers, cf h3_resp_headers_send() */
1416 if (isteq(list[hdr].n, ist("host")) ||
1417 isteq(list[hdr].n, ist("content-length")) ||
1418 isteq(list[hdr].n, ist("connection")) ||
1419 isteq(list[hdr].n, ist("proxy-connection")) ||
1420 isteq(list[hdr].n, ist("keep-alive")) ||
1421 isteq(list[hdr].n, ist("te")) ||
1422 isteq(list[hdr].n, ist("transfer-encoding"))) {
1423 continue;
1424 }
1425
Amaury Denoyelle224ba5c2023-01-26 17:41:58 +01001426 if (qpack_encode_header(&headers_buf, list[hdr].n, list[hdr].v)) {
1427 qcs->flags |= QC_SF_BLK_MROOM;
1428 goto err;
1429 }
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001430 }
1431
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001432 /* Check that at least one header was encoded in buffer. */
Amaury Denoyelle4be54352023-01-26 17:49:21 +01001433 if (b_tail(&headers_buf) == tail) {
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001434 /* No headers encoded here so no need to generate a H3 HEADERS
1435 * frame. Mux will send an empty QUIC STREAM frame with FIN.
1436 */
1437 TRACE_DATA("skipping trailer", H3_EV_TX_HDR, qcs->qcc->conn, qcs);
Amaury Denoyelle4be54352023-01-26 17:49:21 +01001438 goto end;
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001439 }
1440
Amaury Denoyelle4be54352023-01-26 17:49:21 +01001441 /* Now that all headers are encoded, we are certain that res buffer is
1442 * big enough.
1443 */
1444 b_putchr(res, 0x01); /* h3 HEADERS frame type */
1445 if (!b_quic_enc_int(res, b_data(&headers_buf), 8))
1446 ABORT_NOW();
1447 b_add(res, b_data(&headers_buf));
1448
1449 end:
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001450 ret = 0;
1451 blk = htx_get_head_blk(htx);
1452 while (blk) {
1453 type = htx_get_blk_type(blk);
1454 ret += htx_get_blksz(blk);
1455 blk = htx_remove_blk(htx, blk);
1456 if (type == HTX_BLK_EOT)
1457 break;
1458 }
1459
1460 TRACE_LEAVE(H3_EV_TX_HDR, qcs->qcc->conn, qcs);
1461 return ret;
1462
1463 err:
1464 TRACE_DEVEL("leaving on error", H3_EV_TX_HDR, qcs->qcc->conn, qcs);
1465 return 0;
1466}
1467
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001468/* Returns the total of bytes sent. */
Amaury Denoyelle9534e592022-09-19 17:14:27 +02001469static int h3_resp_data_send(struct qcs *qcs, struct htx *htx, size_t count)
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001470{
1471 struct buffer outbuf;
1472 struct buffer *res;
1473 size_t total = 0;
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001474 int bsize, fsize, hsize;
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001475 struct htx_blk *blk;
1476 enum htx_blk_type type;
1477
Amaury Denoyellea717eb72022-05-30 15:51:01 +02001478 TRACE_ENTER(H3_EV_TX_DATA, qcs->qcc->conn, qcs);
1479
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001480 new_frame:
1481 if (!count || htx_is_empty(htx))
1482 goto end;
1483
1484 blk = htx_get_head_blk(htx);
1485 type = htx_get_blk_type(blk);
1486 fsize = bsize = htx_get_blksz(blk);
1487
1488 if (type != HTX_BLK_DATA)
1489 goto end;
1490
Amaury Denoyelled3d97c62021-10-05 11:45:58 +02001491 res = mux_get_buf(qcs);
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001492
1493 if (fsize > count)
1494 fsize = count;
1495
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001496 /* h3 DATA headers : 1-byte frame type + varint frame length */
1497 hsize = 1 + QUIC_VARINT_MAX_SIZE;
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001498
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001499 while (1) {
1500 b_reset(&outbuf);
1501 outbuf = b_make(b_tail(res), b_contig_space(res), 0, 0);
1502 if (b_size(&outbuf) > hsize || !b_space_wraps(res))
1503 break;
1504 b_slow_realign(res, trash.area, b_data(res));
1505 }
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001506
Amaury Denoyelle84ea8dc2021-12-03 14:40:01 +01001507 /* Not enough room for headers and at least one data byte, block the
Willy Tarreau4596fe22022-05-17 19:07:51 +02001508 * stream. It is expected that the stream connector layer will subscribe
1509 * on SEND.
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001510 */
Amaury Denoyelle84ea8dc2021-12-03 14:40:01 +01001511 if (b_size(&outbuf) <= hsize) {
1512 qcs->flags |= QC_SF_BLK_MROOM;
1513 goto end;
1514 }
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001515
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001516 if (b_size(&outbuf) < hsize + fsize)
1517 fsize = b_size(&outbuf) - hsize;
1518 BUG_ON(fsize <= 0);
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001519
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001520 b_putchr(&outbuf, 0x00); /* h3 frame type = DATA */
Amaury Denoyelle7d78eff2023-01-17 15:21:16 +01001521 b_quic_enc_int(&outbuf, fsize, 0); /* h3 frame length */
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001522
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001523 b_putblk(&outbuf, htx_get_blk_ptr(htx, blk), fsize);
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001524 total += fsize;
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001525 count -= fsize;
1526
1527 if (fsize == bsize)
1528 htx_remove_blk(htx, blk);
1529 else
1530 htx_cut_data_blk(htx, blk, fsize);
1531
Amaury Denoyellea543eb12021-10-06 14:53:13 +02001532 /* commit the buffer */
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001533 b_add(res, b_data(&outbuf));
1534 goto new_frame;
1535
1536 end:
Amaury Denoyellea717eb72022-05-30 15:51:01 +02001537 TRACE_LEAVE(H3_EV_TX_DATA, qcs->qcc->conn, qcs);
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001538 return total;
1539}
1540
Amaury Denoyelle9534e592022-09-19 17:14:27 +02001541static size_t h3_snd_buf(struct qcs *qcs, struct htx *htx, size_t count)
Amaury Denoyelle26dfd902021-08-24 16:33:53 +02001542{
1543 size_t total = 0;
Amaury Denoyelle26dfd902021-08-24 16:33:53 +02001544 enum htx_blk_type btype;
1545 struct htx_blk *blk;
1546 uint32_t bsize;
1547 int32_t idx;
1548 int ret;
1549
Amaury Denoyelled8769d12022-03-25 15:28:33 +01001550 h3_debug_printf(stderr, "%s\n", __func__);
Amaury Denoyelledeed7772021-12-03 11:36:46 +01001551
Amaury Denoyelle84ea8dc2021-12-03 14:40:01 +01001552 while (count && !htx_is_empty(htx) && !(qcs->flags & QC_SF_BLK_MROOM)) {
Amaury Denoyelle26dfd902021-08-24 16:33:53 +02001553 idx = htx_get_head(htx);
1554 blk = htx_get_blk(htx, idx);
1555 btype = htx_get_blk_type(blk);
1556 bsize = htx_get_blksz(blk);
1557
1558 /* Not implemented : QUIC on backend side */
1559 BUG_ON(btype == HTX_BLK_REQ_SL);
1560
1561 switch (btype) {
1562 case HTX_BLK_RES_SL:
Amaury Denoyelle15b09612021-08-24 16:20:27 +02001563 /* start-line -> HEADERS h3 frame */
1564 ret = h3_resp_headers_send(qcs, htx);
1565 if (ret > 0) {
1566 total += ret;
1567 count -= ret;
1568 if (ret < bsize)
1569 goto out;
1570 }
1571 break;
Amaury Denoyelle26dfd902021-08-24 16:33:53 +02001572
1573 case HTX_BLK_DATA:
Amaury Denoyelle9534e592022-09-19 17:14:27 +02001574 ret = h3_resp_data_send(qcs, htx, count);
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001575 if (ret > 0) {
Amaury Denoyelle8e2a9982021-08-24 16:24:37 +02001576 total += ret;
1577 count -= ret;
1578 if (ret < bsize)
1579 goto out;
1580 }
1581 break;
Amaury Denoyelle26dfd902021-08-24 16:33:53 +02001582
1583 case HTX_BLK_TLR:
1584 case HTX_BLK_EOT:
Amaury Denoyelle4e520102023-01-12 14:53:43 +01001585 ret = h3_resp_trailers_send(qcs, htx);
1586 if (ret > 0) {
1587 total += ret;
1588 count -= ret;
1589 if (ret < bsize)
1590 goto out;
1591 }
1592 break;
Amaury Denoyelle26dfd902021-08-24 16:33:53 +02001593
1594 default:
1595 htx_remove_blk(htx, blk);
1596 total += bsize;
1597 count -= bsize;
1598 break;
1599 }
1600 }
1601
Amaury Denoyelle26dfd902021-08-24 16:33:53 +02001602 out:
1603 return total;
Amaury Denoyellef52151d2021-08-24 16:11:18 +02001604}
1605
Amaury Denoyelle1e340ba2023-01-30 12:12:11 +01001606/* Notify about a closure on <qcs> stream requested by the remote peer.
1607 *
1608 * Stream channel <side> is explained relative to our endpoint : WR for
1609 * STOP_SENDING or RD for RESET_STREAM reception. Callback decode_qcs() is used
1610 * instead for closure performed using a STREAM frame with FIN bit.
1611 *
1612 * The main objective of this function is to check if closure is valid
1613 * according to HTTP/3 specification.
1614 *
1615 * Returns 0 on success else non-zero. A CONNECTION_CLOSE is generated on
1616 * error.
1617 */
1618static int h3_close(struct qcs *qcs, enum qcc_app_ops_close_side side)
1619{
Amaury Denoyelle87f87662023-01-30 12:12:43 +01001620 struct h3s *h3s = qcs->ctx;
1621 struct h3c *h3c = h3s->h3c;;
1622
1623 /* RFC 9114 6.2.1. Control Streams
1624 *
1625 * The sender
1626 * MUST NOT close the control stream, and the receiver MUST NOT
1627 * request that the sender close the control stream. If either
1628 * control stream is closed at any point, this MUST be treated
1629 * as a connection error of type H3_CLOSED_CRITICAL_STREAM.
1630 */
Amaury Denoyellee269aeb2023-01-30 12:13:22 +01001631 if (qcs == h3c->ctrl_strm || h3s->type == H3S_T_CTRL) {
Amaury Denoyellee31867b2023-01-31 16:01:22 +01001632 TRACE_ERROR("closure detected on control stream", H3_EV_H3S_END, qcs->qcc->conn, qcs);
Amaury Denoyelle87f87662023-01-30 12:12:43 +01001633 qcc_emit_cc_app(qcs->qcc, H3_CLOSED_CRITICAL_STREAM, 1);
1634 return 1;
1635 }
1636
Amaury Denoyelle1e340ba2023-01-30 12:12:11 +01001637 return 0;
1638}
1639
Amaury Denoyellec0156792022-06-03 15:29:07 +02001640static int h3_attach(struct qcs *qcs, void *conn_ctx)
Amaury Denoyelle67e92d32022-04-27 18:04:01 +02001641{
1642 struct h3s *h3s;
1643
Amaury Denoyelled5581d52022-05-30 15:51:31 +02001644 TRACE_ENTER(H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
1645
Amaury Denoyelle67e92d32022-04-27 18:04:01 +02001646 h3s = pool_alloc(pool_head_h3s);
1647 if (!h3s)
1648 return 1;
1649
1650 qcs->ctx = h3s;
Amaury Denoyellec0156792022-06-03 15:29:07 +02001651 h3s->h3c = conn_ctx;
1652
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001653 h3s->demux_frame_len = 0;
1654 h3s->demux_frame_type = 0;
Amaury Denoyelled2c5ee62022-12-08 16:54:42 +01001655 h3s->body_len = 0;
1656 h3s->data_len = 0;
Amaury Denoyelle35550642022-05-24 15:14:53 +02001657 h3s->flags = 0;
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +01001658 h3s->err = 0;
Amaury Denoyelle48f01bd2022-04-27 15:37:20 +02001659
Amaury Denoyelle3236a8e2022-05-24 15:24:03 +02001660 if (quic_stream_is_bidi(qcs->id)) {
1661 h3s->type = H3S_T_REQ;
Amaury Denoyelle8d818c62022-08-02 11:32:45 +02001662 h3s->st_req = H3S_ST_REQ_BEFORE;
Amaury Denoyelle30e260e2022-08-03 11:17:57 +02001663 qcs_wait_http_req(qcs);
Amaury Denoyelle3236a8e2022-05-24 15:24:03 +02001664 }
1665 else {
1666 /* stream type must be decoded for unidirectional streams */
1667 h3s->type = H3S_T_UNKNOWN;
1668 }
1669
Amaury Denoyelled5581d52022-05-30 15:51:31 +02001670 TRACE_LEAVE(H3_EV_H3S_NEW, qcs->qcc->conn, qcs);
Amaury Denoyelle67e92d32022-04-27 18:04:01 +02001671 return 0;
1672}
1673
Amaury Denoyelle67e92d32022-04-27 18:04:01 +02001674static void h3_detach(struct qcs *qcs)
1675{
1676 struct h3s *h3s = qcs->ctx;
Amaury Denoyelled5581d52022-05-30 15:51:31 +02001677
1678 TRACE_ENTER(H3_EV_H3S_END, qcs->qcc->conn, qcs);
1679
Amaury Denoyelle67e92d32022-04-27 18:04:01 +02001680 pool_free(pool_head_h3s, h3s);
1681 qcs->ctx = NULL;
Amaury Denoyelled5581d52022-05-30 15:51:31 +02001682
1683 TRACE_LEAVE(H3_EV_H3S_END, qcs->qcc->conn, qcs);
Amaury Denoyelle67e92d32022-04-27 18:04:01 +02001684}
1685
Amaury Denoyelle71fd0362023-01-24 17:35:37 +01001686/* Initialize H3 control stream and prepare SETTINGS emission.
1687 *
1688 * Returns 0 on success else non-zero.
1689 */
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001690static int h3_finalize(void *ctx)
1691{
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001692 struct h3c *h3c = ctx;
Amaury Denoyelle9cc47512022-05-24 16:27:41 +02001693 struct qcs *qcs;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001694
Amaury Denoyelleb1437232022-07-08 11:53:22 +02001695 qcs = qcc_init_stream_local(h3c->qcc, 0);
Amaury Denoyelle9cc47512022-05-24 16:27:41 +02001696 if (!qcs)
Amaury Denoyelle71fd0362023-01-24 17:35:37 +01001697 return 1;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001698
Amaury Denoyelle9cc47512022-05-24 16:27:41 +02001699 h3_control_send(qcs, h3c);
Amaury Denoyelled7010392022-07-13 15:17:29 +02001700 h3c->ctrl_strm = qcs;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001701
Amaury Denoyelle71fd0362023-01-24 17:35:37 +01001702 return 0;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001703}
1704
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001705/* Generate a GOAWAY frame for <h3c> connection on the control stream.
1706 *
1707 * Returns 0 on success else non-zero.
1708 */
1709static int h3_send_goaway(struct h3c *h3c)
1710{
1711 struct qcs *qcs = h3c->ctrl_strm;
1712 struct buffer pos, *res;
1713 unsigned char data[3 * QUIC_VARINT_MAX_SIZE];
1714 size_t frm_len = quic_int_getsize(h3c->id_goaway);
1715
Amaury Denoyelle78adb4b2023-01-31 15:50:16 +01001716 TRACE_ENTER(H3_EV_H3C_END, h3c->qcc->conn);
Amaury Denoyelle56a86dd2023-01-30 15:36:51 +01001717
1718 if (!qcs) {
Amaury Denoyelle78adb4b2023-01-31 15:50:16 +01001719 TRACE_ERROR("control stream not initialized", H3_EV_H3C_END, h3c->qcc->conn);
Amaury Denoyelle56a86dd2023-01-30 15:36:51 +01001720 goto err;
1721 }
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001722
1723 pos = b_make((char *)data, sizeof(data), 0, 0);
1724
Amaury Denoyelle7d78eff2023-01-17 15:21:16 +01001725 b_quic_enc_int(&pos, H3_FT_GOAWAY, 0);
1726 b_quic_enc_int(&pos, frm_len, 0);
1727 b_quic_enc_int(&pos, h3c->id_goaway, 0);
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001728
1729 res = mux_get_buf(qcs);
1730 if (!res || b_room(res) < b_data(&pos)) {
1731 /* Do not try forcefully to emit GOAWAY if no space left. */
Amaury Denoyelle78adb4b2023-01-31 15:50:16 +01001732 TRACE_ERROR("cannot send GOAWAY", H3_EV_H3C_END, h3c->qcc->conn, qcs);
Amaury Denoyelle56a86dd2023-01-30 15:36:51 +01001733 goto err;
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001734 }
1735
1736 b_force_xfer(res, &pos, b_data(&pos));
Amaury Denoyelle19adeb52023-01-25 10:50:03 +01001737 qcc_send_stream(qcs, 1);
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001738
Amaury Denoyelle78adb4b2023-01-31 15:50:16 +01001739 TRACE_LEAVE(H3_EV_H3C_END, h3c->qcc->conn);
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001740 return 0;
Amaury Denoyelle56a86dd2023-01-30 15:36:51 +01001741
1742 err:
Amaury Denoyelle78adb4b2023-01-31 15:50:16 +01001743 TRACE_DEVEL("leaving in error", H3_EV_H3C_END, h3c->qcc->conn);
Amaury Denoyelle56a86dd2023-01-30 15:36:51 +01001744 return 1;
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001745}
1746
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001747/* Initialize the HTTP/3 context for <qcc> mux.
1748 * Return 1 if succeeded, 0 if not.
1749 */
1750static int h3_init(struct qcc *qcc)
1751{
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001752 struct h3c *h3c;
Frédéric Lécaille6f7607e2022-05-25 22:25:37 +02001753 struct quic_conn *qc = qcc->conn->handle.qc;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001754
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001755 h3c = pool_alloc(pool_head_h3c);
1756 if (!h3c)
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001757 goto fail_no_h3;
1758
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001759 h3c->qcc = qcc;
Amaury Denoyelled7010392022-07-13 15:17:29 +02001760 h3c->ctrl_strm = NULL;
Amaury Denoyelle2fe93ab2022-12-09 15:01:31 +01001761 h3c->err = 0;
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001762 h3c->flags = 0;
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001763 h3c->id_goaway = 0;
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001764
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001765 qcc->ctx = h3c;
Amaury Denoyelle5c25dc52022-09-30 17:44:15 +02001766 /* TODO cleanup only ref to quic_conn */
Frédéric Lécaille6f7607e2022-05-25 22:25:37 +02001767 h3c->prx_counters =
1768 EXTRA_COUNTERS_GET(qc->li->bind_conf->frontend->extra_counters_fe,
1769 &h3_stats_module);
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001770 LIST_INIT(&h3c->buf_wait.list);
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001771
1772 return 1;
1773
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001774 fail_no_h3:
1775 return 0;
1776}
1777
Amaury Denoyellef8aaf8b2022-09-14 16:23:47 +02001778/* Send a HTTP/3 GOAWAY followed by a CONNECTION_CLOSE_APP. */
1779static void h3_shutdown(void *ctx)
Amaury Denoyelle8347f272022-03-29 14:46:55 +02001780{
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001781 struct h3c *h3c = ctx;
Amaury Denoyelle069288b2022-07-15 10:58:25 +02001782
Amaury Denoyelle78adb4b2023-01-31 15:50:16 +01001783 TRACE_ENTER(H3_EV_H3C_END, h3c->qcc->conn);
Amaury Denoyelle56a86dd2023-01-30 15:36:51 +01001784
Amaury Denoyelle069288b2022-07-15 10:58:25 +02001785 /* RFC 9114 5.2. Connection Shutdown
1786 *
Amaury Denoyelle114c9c82022-03-28 14:53:45 +02001787 * Even when a connection is not idle, either endpoint can decide to
1788 * stop using the connection and initiate a graceful connection close.
1789 * Endpoints initiate the graceful shutdown of an HTTP/3 connection by
1790 * sending a GOAWAY frame.
1791 */
1792 h3_send_goaway(h3c);
1793
1794 /* RFC 9114 5.2. Connection Shutdown
1795 *
Amaury Denoyelle069288b2022-07-15 10:58:25 +02001796 * An endpoint that completes a
1797 * graceful shutdown SHOULD use the H3_NO_ERROR error code when closing
1798 * the connection.
1799 */
1800 qcc_emit_cc_app(h3c->qcc, H3_NO_ERROR, 0);
Amaury Denoyelle56a86dd2023-01-30 15:36:51 +01001801
Amaury Denoyelle78adb4b2023-01-31 15:50:16 +01001802 TRACE_LEAVE(H3_EV_H3C_END, h3c->qcc->conn);
Amaury Denoyellef8aaf8b2022-09-14 16:23:47 +02001803}
Amaury Denoyelle069288b2022-07-15 10:58:25 +02001804
Amaury Denoyellef8aaf8b2022-09-14 16:23:47 +02001805static void h3_release(void *ctx)
1806{
1807 struct h3c *h3c = ctx;
Amaury Denoyelle8d1ecac2022-05-24 14:55:43 +02001808 pool_free(pool_head_h3c, h3c);
Amaury Denoyelle8347f272022-03-29 14:46:55 +02001809}
1810
Frédéric Lécaille6f7607e2022-05-25 22:25:37 +02001811/* Increment the h3 error code counters for <error_code> value */
1812static void h3_stats_inc_err_cnt(void *ctx, int err_code)
1813{
1814 struct h3c *h3c = ctx;
1815
1816 h3_inc_err_cnt(h3c->prx_counters, err_code);
1817}
1818
Amaury Denoyelle016aa932022-05-30 15:49:36 +02001819/* h3 trace handler */
1820static void h3_trace(enum trace_level level, uint64_t mask,
1821 const struct trace_source *src,
1822 const struct ist where, const struct ist func,
1823 const void *a1, const void *a2, const void *a3, const void *a4)
1824{
1825 const struct connection *conn = a1;
1826 const struct qcc *qcc = conn ? conn->ctx : NULL;
1827 const struct qcs *qcs = a2;
1828
Frédéric Lécaille1c725aa2022-09-08 15:49:37 +02001829 if (!qcc)
1830 return;
1831
Amaury Denoyelle016aa932022-05-30 15:49:36 +02001832 if (src->verbosity > H3_VERB_CLEAN) {
1833 chunk_appendf(&trace_buf, " : qcc=%p(F)", qcc);
Frédéric Lécaille2eb5faa2022-09-08 16:03:13 +02001834 if (qcc->conn->handle.qc)
1835 chunk_appendf(&trace_buf, " qc=%p", qcc->conn->handle.qc);
Amaury Denoyelle016aa932022-05-30 15:49:36 +02001836
1837 if (qcs)
Frédéric Lécaille628e89c2022-06-24 12:13:53 +02001838 chunk_appendf(&trace_buf, " qcs=%p(%llu)", qcs, (ull)qcs->id);
Amaury Denoyelle016aa932022-05-30 15:49:36 +02001839 }
1840}
1841
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001842/* HTTP/3 application layer operations */
1843const struct qcc_app_ops h3_ops = {
1844 .init = h3_init,
Amaury Denoyelle67e92d32022-04-27 18:04:01 +02001845 .attach = h3_attach,
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001846 .decode_qcs = h3_decode_qcs,
Amaury Denoyelleabbe91e2021-11-12 16:09:29 +01001847 .snd_buf = h3_snd_buf,
Amaury Denoyelle1e340ba2023-01-30 12:12:11 +01001848 .close = h3_close,
Amaury Denoyelle67e92d32022-04-27 18:04:01 +02001849 .detach = h3_detach,
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001850 .finalize = h3_finalize,
Amaury Denoyellef8aaf8b2022-09-14 16:23:47 +02001851 .shutdown = h3_shutdown,
Frédéric Lécaille6f7607e2022-05-25 22:25:37 +02001852 .inc_err_cnt = h3_stats_inc_err_cnt,
Amaury Denoyellef8aaf8b2022-09-14 16:23:47 +02001853 .release = h3_release,
Frédéric Lécailleccac11f2021-03-03 16:09:02 +01001854};