blob: f794262ee7af1bd5555425cc11c9b58bf54223e9 [file] [log] [blame]
Willy Tarreauf24ea8e2017-11-21 19:55:27 +01001/*
2 * HTTP/2 protocol processing
3 *
4 * Copyright 2017 Willy Tarreau <w@1wt.eu>
5 * Copyright (C) 2017 HAProxy Technologies
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 */
27
Willy Tarreaua1bd1fa2019-03-29 17:26:33 +010028#include <inttypes.h>
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020029#include <haproxy/api.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020030#include <haproxy/global.h>
Willy Tarreaubf073142020-06-03 12:04:01 +020031#include <haproxy/h2.h>
Willy Tarreau0017be02020-06-02 19:25:28 +020032#include <haproxy/http-hdr-t.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020033#include <haproxy/http.h>
Amaury Denoyelle4ca0f362021-07-07 10:49:28 +020034#include <haproxy/http_htx.h>
Willy Tarreau16f958c2020-06-03 08:44:35 +020035#include <haproxy/htx.h>
Willy Tarreaueb6f7012020-05-27 16:21:26 +020036#include <import/ist.h>
Willy Tarreaub2551052020-06-09 09:07:15 +020037
Willy Tarreauf24ea8e2017-11-21 19:55:27 +010038
Willy Tarreau9c84d822019-01-30 15:09:21 +010039struct h2_frame_definition h2_frame_definition[H2_FT_ENTRIES] = {
40 [H2_FT_DATA ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 0, .max_len = H2_MAX_FRAME_LEN, },
41 [H2_FT_HEADERS ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 1, .max_len = H2_MAX_FRAME_LEN, },
42 [H2_FT_PRIORITY ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 5, .max_len = 5, },
43 [H2_FT_RST_STREAM ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 4, .max_len = 4, },
44 [H2_FT_SETTINGS ] = { .dir = 3, .min_id = 0, .max_id = 0, .min_len = 0, .max_len = H2_MAX_FRAME_LEN, },
45 [H2_FT_PUSH_PROMISE ] = { .dir = 0, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 4, .max_len = H2_MAX_FRAME_LEN, },
46 [H2_FT_PING ] = { .dir = 3, .min_id = 0, .max_id = 0, .min_len = 8, .max_len = 8, },
47 [H2_FT_GOAWAY ] = { .dir = 3, .min_id = 0, .max_id = 0, .min_len = 8, .max_len = H2_MAX_FRAME_LEN, },
48 [H2_FT_WINDOW_UPDATE] = { .dir = 3, .min_id = 0, .max_id = H2_MAX_STREAM_ID, .min_len = 4, .max_len = 4, },
49 [H2_FT_CONTINUATION ] = { .dir = 3, .min_id = 1, .max_id = H2_MAX_STREAM_ID, .min_len = 0, .max_len = H2_MAX_FRAME_LEN, },
50};
Willy Tarreauf24ea8e2017-11-21 19:55:27 +010051
Willy Tarreau54f53ef2019-11-22 16:02:43 +010052/* Looks into <ist> for forbidden characters for header values (0x00, 0x0A,
53 * 0x0D), starting at pointer <start> which must be within <ist>. Returns
54 * non-zero if such a character is found, 0 otherwise. When run on unlikely
55 * header match, it's recommended to first check for the presence of control
56 * chars using ist_find_ctl().
57 */
58static int has_forbidden_char(const struct ist ist, const char *start)
59{
60 do {
61 if ((uint8_t)*start <= 0x0d &&
62 (1U << (uint8_t)*start) & ((1<<13) | (1<<10) | (1<<0)))
63 return 1;
64 start++;
Tim Duesterhus4c8f75f2021-11-06 15:14:44 +010065 } while (start < istend(ist));
Willy Tarreau54f53ef2019-11-22 16:02:43 +010066 return 0;
67}
68
Willy Tarreau6deb4122018-11-27 15:34:18 +010069/* Prepare the request line into <htx> from pseudo headers stored in <phdr[]>.
70 * <fields> indicates what was found so far. This should be called once at the
71 * detection of the first general header field or at the end of the request if
72 * no general header field was found yet. Returns the created start line on
73 * success, or NULL on failure. Upon success, <msgf> is updated with a few
74 * H2_MSGF_* flags indicating what was found while parsing.
Willy Tarreau2be362c2019-10-08 11:59:37 +020075 *
76 * The rules below deserve a bit of explanation. There tends to be some
77 * confusion regarding H2's authority vs the Host header. They are different
78 * though may sometimes be exchanged. In H2, the request line is broken into :
79 * - :method
80 * - :scheme
81 * - :authority
82 * - :path
83 *
84 * An equivalent HTTP/1.x absolute-form request would then look like :
85 * <:method> <:scheme>://<:authority><:path> HTTP/x.y
86 *
87 * Except for CONNECT which doesn't have scheme nor path and looks like :
88 * <:method> <:authority> HTTP/x.y
89 *
90 * It's worth noting that H2 still supports an encoding to map H1 origin-form
91 * and asterisk-form requests. These ones do not specify the authority. However
92 * in H2 they must still specify the scheme, which is not present in H1. Also,
93 * when encoding an absolute-form H1 request without a path, the path
94 * automatically becomes "/" except for the OPTIONS method where it
95 * becomes "*".
96 *
97 * As such it is explicitly permitted for an H2 client to send a request
98 * featuring a Host header and no :authority, though it's not the recommended
99 * way to use H2 for a client. It is however the only permitted way to encode
100 * an origin-form H1 request over H2. Thus we need to respect such differences
101 * as much as possible when re-encoding the H2 request into HTX.
Willy Tarreau6deb4122018-11-27 15:34:18 +0100102 */
103static struct htx_sl *h2_prepare_htx_reqline(uint32_t fields, struct ist *phdr, struct htx *htx, unsigned int *msgf)
104{
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100105 struct ist uri, meth_sl;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100106 unsigned int flags = HTX_SL_F_NONE;
107 struct htx_sl *sl;
Willy Tarreau9255e7e2019-03-05 10:47:37 +0100108 size_t i;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100109
110 if ((fields & H2_PHDR_FND_METH) && isteq(phdr[H2_PHDR_IDX_METH], ist("CONNECT"))) {
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100111 if (fields & H2_PHDR_FND_PROT) {
112 /* rfc 8441 Extended Connect Protocol
113 * #4 :scheme and :path must be present, as well as
114 * :authority like all h2 requests
115 */
116 if (!(fields & H2_PHDR_FND_SCHM)) {
117 /* missing scheme */
118 goto fail;
119 }
120 else if (!(fields & H2_PHDR_FND_PATH)) {
121 /* missing path */
122 goto fail;
123 }
124 else if (!(fields & H2_PHDR_FND_AUTH)) {
125 /* missing authority */
126 goto fail;
127 }
128
129 flags |= HTX_SL_F_HAS_SCHM;
130 if (isteqi(phdr[H2_PHDR_IDX_SCHM], ist("http")))
131 flags |= HTX_SL_F_SCHM_HTTP;
132 else if (isteqi(phdr[H2_PHDR_IDX_SCHM], ist("https")))
133 flags |= HTX_SL_F_SCHM_HTTPS;
Willy Tarreaua495e0d2021-08-10 15:37:34 +0200134 else if (!http_validate_scheme(phdr[H2_PHDR_IDX_SCHM]))
135 htx->flags |= HTX_FL_PARSING_ERROR;
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100136
137 meth_sl = ist("GET");
138
139 *msgf |= H2_MSGF_EXT_CONNECT;
140 /* no ES on the HEADERS frame but no body either for
141 * Extended CONNECT */
142 *msgf &= ~H2_MSGF_BODY;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100143 }
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100144 else {
145 /* RFC 7540 #8.2.6 regarding CONNECT: ":scheme" and ":path"
146 * MUST be omitted ; ":authority" contains the host and port
147 * to connect to.
148 */
149 if (fields & H2_PHDR_FND_SCHM) {
150 /* scheme not allowed */
151 goto fail;
152 }
153 else if (fields & H2_PHDR_FND_PATH) {
154 /* path not allowed */
155 goto fail;
156 }
157 else if (!(fields & H2_PHDR_FND_AUTH)) {
158 /* missing authority */
159 goto fail;
160 }
161
162 meth_sl = phdr[H2_PHDR_IDX_METH];
Willy Tarreau6deb4122018-11-27 15:34:18 +0100163 }
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100164
Willy Tarreau6deb4122018-11-27 15:34:18 +0100165 *msgf |= H2_MSGF_BODY_TUNNEL;
166 }
167 else if ((fields & (H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) !=
168 (H2_PHDR_FND_METH|H2_PHDR_FND_SCHM|H2_PHDR_FND_PATH)) {
169 /* RFC 7540 #8.1.2.3 : all requests MUST include exactly one
170 * valid value for the ":method", ":scheme" and ":path" phdr
171 * unless it is a CONNECT request.
172 */
173 if (!(fields & H2_PHDR_FND_METH)) {
174 /* missing method */
175 goto fail;
176 }
177 else if (!(fields & H2_PHDR_FND_SCHM)) {
178 /* missing scheme */
179 goto fail;
180 }
181 else {
182 /* missing path */
183 goto fail;
184 }
185 }
Willy Tarreau2be362c2019-10-08 11:59:37 +0200186 else { /* regular methods */
Willy Tarreau92919f72019-10-08 16:53:07 +0200187 /* RFC3986#6.2.2.1: scheme is case-insensitive. We need to
188 * classify the scheme as "present/http", "present/https",
189 * "present/other", "absent" so as to decide whether or not
190 * we're facing a normalized URI that will have to be encoded
191 * in origin or absolute form. Indeed, 7540#8.1.2.3 says that
192 * clients should use the absolute form, thus we cannot infer
193 * whether or not the client wanted to use a proxy here.
194 */
195 flags |= HTX_SL_F_HAS_SCHM;
196 if (isteqi(phdr[H2_PHDR_IDX_SCHM], ist("http")))
197 flags |= HTX_SL_F_SCHM_HTTP;
198 else if (isteqi(phdr[H2_PHDR_IDX_SCHM], ist("https")))
199 flags |= HTX_SL_F_SCHM_HTTPS;
Willy Tarreaua495e0d2021-08-10 15:37:34 +0200200 else if (!http_validate_scheme(phdr[H2_PHDR_IDX_SCHM]))
201 htx->flags |= HTX_FL_PARSING_ERROR;
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100202
203 meth_sl = phdr[H2_PHDR_IDX_METH];
Willy Tarreau92919f72019-10-08 16:53:07 +0200204 }
205
Willy Tarreau4b8852c2021-08-10 16:30:55 +0200206 if (fields & H2_PHDR_FND_PATH) {
207 /* 7540#8.1.2.3: :path must not be empty, and must be either
208 * '*' or an RFC3986 "path-absolute" starting with a "/" but
209 * not with "//".
Willy Tarreau46b7dff2021-08-19 23:06:58 +0200210 * However, this "path-absolute" was a mistake which was
211 * later fixed in http2bis as "absolute-path" to match
212 * HTTP/1, thus also allowing "//".
Willy Tarreau4b8852c2021-08-10 16:30:55 +0200213 */
214 if (unlikely(!phdr[H2_PHDR_IDX_PATH].len))
215 goto fail;
216 else if (unlikely(phdr[H2_PHDR_IDX_PATH].ptr[0] != '/')) {
217 if (!isteq(phdr[H2_PHDR_IDX_PATH], ist("*")))
218 goto fail;
219 }
Willy Tarreau4b8852c2021-08-10 16:30:55 +0200220 }
221
Willy Tarreau92919f72019-10-08 16:53:07 +0200222 if (!(flags & HTX_SL_F_HAS_SCHM)) {
223 /* no scheme, use authority only (CONNECT) */
224 uri = phdr[H2_PHDR_IDX_AUTH];
Willy Tarreau1440fe82019-10-08 17:34:50 +0200225 flags |= HTX_SL_F_HAS_AUTHORITY;
Willy Tarreau92919f72019-10-08 16:53:07 +0200226 }
Willy Tarreau30ee1ef2019-10-08 18:33:19 +0200227 else if (fields & H2_PHDR_FND_AUTH) {
228 /* authority is present, let's use the absolute form. We simply
229 * use the trash to concatenate them since all of them MUST fit
230 * in a bufsize since it's where they come from.
Willy Tarreau92919f72019-10-08 16:53:07 +0200231 */
232 uri = ist2bin(trash.area, phdr[H2_PHDR_IDX_SCHM]);
233 istcat(&uri, ist("://"), trash.size);
234 istcat(&uri, phdr[H2_PHDR_IDX_AUTH], trash.size);
235 if (!isteq(phdr[H2_PHDR_IDX_PATH], ist("*")))
236 istcat(&uri, phdr[H2_PHDR_IDX_PATH], trash.size);
Willy Tarreau1440fe82019-10-08 17:34:50 +0200237 flags |= HTX_SL_F_HAS_AUTHORITY;
Willy Tarreau30ee1ef2019-10-08 18:33:19 +0200238
239 if (flags & (HTX_SL_F_SCHM_HTTP|HTX_SL_F_SCHM_HTTPS)) {
240 /* we don't know if it was originally an absolute or a
241 * relative request because newer versions of HTTP use
242 * the absolute URI format by default, which we call
243 * the normalized URI format internally. This is the
244 * strongly recommended way of sending a request for
245 * a regular client, so we cannot distinguish this
246 * from a request intended for a proxy. For other
247 * schemes however there is no doubt.
248 */
249 flags |= HTX_SL_F_NORMALIZED_URI;
250 }
Willy Tarreau92919f72019-10-08 16:53:07 +0200251 }
252 else {
253 /* usual schemes with or without authority, use origin form */
254 uri = phdr[H2_PHDR_IDX_PATH];
Willy Tarreau1440fe82019-10-08 17:34:50 +0200255 if (fields & H2_PHDR_FND_AUTH)
256 flags |= HTX_SL_F_HAS_AUTHORITY;
Willy Tarreau2be362c2019-10-08 11:59:37 +0200257 }
Willy Tarreau6deb4122018-11-27 15:34:18 +0100258
Willy Tarreau89265222021-08-11 11:12:46 +0200259 /* The method is a non-empty token (RFC7231#4.1) */
260 if (!meth_sl.len)
261 goto fail;
262 for (i = 0; i < meth_sl.len; i++) {
263 if (!HTTP_IS_TOKEN(meth_sl.ptr[i]))
264 htx->flags |= HTX_FL_PARSING_ERROR;
265 }
266
Willy Tarreau2be362c2019-10-08 11:59:37 +0200267 /* make sure the final URI isn't empty. Note that 7540#8.1.2.3 states
268 * that :path must not be empty.
269 */
Willy Tarreau92919f72019-10-08 16:53:07 +0200270 if (!uri.len)
Willy Tarreau6deb4122018-11-27 15:34:18 +0100271 goto fail;
272
Willy Tarreau2be362c2019-10-08 11:59:37 +0200273 /* The final URI must not contain LWS nor CTL characters */
Willy Tarreau92919f72019-10-08 16:53:07 +0200274 for (i = 0; i < uri.len; i++) {
275 unsigned char c = uri.ptr[i];
Willy Tarreau9255e7e2019-03-05 10:47:37 +0100276 if (HTTP_IS_LWS(c) || HTTP_IS_CTL(c))
277 htx->flags |= HTX_FL_PARSING_ERROR;
278 }
279
Willy Tarreau6deb4122018-11-27 15:34:18 +0100280 /* Set HTX start-line flags */
281 flags |= HTX_SL_F_VER_11; // V2 in fact
282 flags |= HTX_SL_F_XFER_LEN; // xfer len always known with H2
283
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100284 sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth_sl, uri, ist("HTTP/2.0"));
Willy Tarreau6deb4122018-11-27 15:34:18 +0100285 if (!sl)
286 goto fail;
287
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100288 sl->info.req.meth = find_http_meth(meth_sl.ptr, meth_sl.len);
Christopher Faulet7d247f02020-12-02 14:26:36 +0100289 if (sl->info.req.meth == HTTP_METH_HEAD)
290 *msgf |= H2_MSGF_BODYLESS_RSP;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100291 return sl;
292 fail:
293 return NULL;
294}
295
296/* Takes an H2 request present in the headers list <list> terminated by a name
297 * being <NULL,0> and emits the equivalent HTX request according to the rules
298 * documented in RFC7540 #8.1.2. The output contents are emitted in <htx>, and
299 * non-zero is returned if some bytes were emitted. In case of error, a
300 * negative error code is returned.
301 *
302 * Upon success, <msgf> is filled with a few H2_MSGF_* flags indicating what
303 * was found while parsing. The caller must set it to zero in or H2_MSGF_BODY
304 * if a body is detected (!ES).
305 *
306 * The headers list <list> must be composed of :
307 * - n.name != NULL, n.len > 0 : literal header name
308 * - n.name == NULL, n.len > 0 : indexed pseudo header name number <n.len>
309 * among H2_PHDR_IDX_*
310 * - n.name ignored, n.len == 0 : end of list
311 * - in all cases except the end of list, v.name and v.len must designate a
312 * valid value.
313 *
314 * The Cookie header will be reassembled at the end, and for this, the <list>
315 * will be used to create a linked list, so its contents may be destroyed.
316 */
Willy Tarreau4790f7c2019-01-24 11:33:02 +0100317int h2_make_htx_request(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len)
Willy Tarreau6deb4122018-11-27 15:34:18 +0100318{
319 struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
320 uint32_t fields; /* bit mask of H2_PHDR_FND_* */
321 uint32_t idx;
322 int ck, lck; /* cookie index and last cookie index */
323 int phdr;
324 int ret;
325 int i;
326 struct htx_sl *sl = NULL;
327 unsigned int sl_flags = 0;
Willy Tarreau54f53ef2019-11-22 16:02:43 +0100328 const char *ctl;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100329
330 lck = ck = -1; // no cookie for now
331 fields = 0;
332 for (idx = 0; list[idx].n.len != 0; idx++) {
Tim Duesterhus77508502022-03-15 13:11:06 +0100333 if (!isttest(list[idx].n)) {
Willy Tarreau6deb4122018-11-27 15:34:18 +0100334 /* this is an indexed pseudo-header */
335 phdr = list[idx].n.len;
336 }
337 else {
338 /* this can be any type of header */
Willy Tarreau146f53a2019-11-24 10:34:39 +0100339 /* RFC7540#8.1.2: upper case not allowed in header field names.
340 * #10.3: header names must be valid (i.e. match a token).
341 * For pseudo-headers we check from 2nd char and for other ones
342 * from the first char, because HTTP_IS_TOKEN() also excludes
343 * the colon.
344 */
Willy Tarreau6deb4122018-11-27 15:34:18 +0100345 phdr = h2_str_to_phdr(list[idx].n);
Willy Tarreau146f53a2019-11-24 10:34:39 +0100346
347 for (i = !!phdr; i < list[idx].n.len; i++)
348 if ((uint8_t)(list[idx].n.ptr[i] - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(list[idx].n.ptr[i]))
349 goto fail;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100350 }
351
Willy Tarreau54f53ef2019-11-22 16:02:43 +0100352 /* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
353 * rejecting NUL, CR and LF characters.
354 */
355 ctl = ist_find_ctl(list[idx].v);
356 if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
357 goto fail;
358
Willy Tarreau6deb4122018-11-27 15:34:18 +0100359 if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) {
360 /* insert a pseudo header by its index (in phdr) and value (in value) */
361 if (fields & ((1 << phdr) | H2_PHDR_FND_NONE)) {
362 if (fields & H2_PHDR_FND_NONE) {
363 /* pseudo header field after regular headers */
364 goto fail;
365 }
366 else {
367 /* repeated pseudo header field */
368 goto fail;
369 }
370 }
371 fields |= 1 << phdr;
372 phdr_val[phdr] = list[idx].v;
373 continue;
374 }
375 else if (phdr != 0) {
376 /* invalid pseudo header -- should never happen here */
377 goto fail;
378 }
379
380 /* regular header field in (name,value) */
381 if (unlikely(!(fields & H2_PHDR_FND_NONE))) {
382 /* no more pseudo-headers, time to build the request line */
383 sl = h2_prepare_htx_reqline(fields, phdr_val, htx, msgf);
384 if (!sl)
385 goto fail;
386 fields |= H2_PHDR_FND_NONE;
Willy Tarreaub5d2b9e2021-08-11 15:39:13 +0200387
388 /* http2bis draft recommends to drop Host in favor of :authority when
389 * the latter is present. This is required to make sure there is no
390 * discrepancy between the authority and the host header, especially
391 * since routing rules usually involve Host. Here we already know if
392 * :authority was found so we can emit it right now and mark the host
393 * as filled so that it's skipped later.
394 */
395 if (fields & H2_PHDR_FND_AUTH) {
396 if (!htx_add_header(htx, ist("host"), phdr_val[H2_PHDR_IDX_AUTH]))
397 goto fail;
398 fields |= H2_PHDR_FND_HOST;
399 }
Willy Tarreau6deb4122018-11-27 15:34:18 +0100400 }
401
Willy Tarreaub5d2b9e2021-08-11 15:39:13 +0200402 if (isteq(list[idx].n, ist("host"))) {
403 if (fields & H2_PHDR_FND_HOST)
404 continue;
405
Willy Tarreau6deb4122018-11-27 15:34:18 +0100406 fields |= H2_PHDR_FND_HOST;
Willy Tarreaub5d2b9e2021-08-11 15:39:13 +0200407 }
Willy Tarreau6deb4122018-11-27 15:34:18 +0100408
Willy Tarreaubeefaee2018-12-19 13:08:08 +0100409 if (isteq(list[idx].n, ist("content-length"))) {
Amaury Denoyelle15f3cc42022-12-08 16:53:58 +0100410 ret = http_parse_cont_len_header(&list[idx].v, body_len,
411 *msgf & H2_MSGF_BODY_CL);
Willy Tarreaubeefaee2018-12-19 13:08:08 +0100412 if (ret < 0)
413 goto fail;
414
Amaury Denoyelle15f3cc42022-12-08 16:53:58 +0100415 *msgf |= H2_MSGF_BODY_CL;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100416 sl_flags |= HTX_SL_F_CLEN;
Willy Tarreaubeefaee2018-12-19 13:08:08 +0100417 if (ret == 0)
418 continue; // skip this duplicate
Willy Tarreau6deb4122018-11-27 15:34:18 +0100419 }
420
421 /* these ones are forbidden in requests (RFC7540#8.1.2.2) */
422 if (isteq(list[idx].n, ist("connection")) ||
423 isteq(list[idx].n, ist("proxy-connection")) ||
424 isteq(list[idx].n, ist("keep-alive")) ||
425 isteq(list[idx].n, ist("upgrade")) ||
426 isteq(list[idx].n, ist("transfer-encoding")))
427 goto fail;
428
429 if (isteq(list[idx].n, ist("te")) && !isteq(list[idx].v, ist("trailers")))
430 goto fail;
431
432 /* cookie requires special processing at the end */
433 if (isteq(list[idx].n, ist("cookie"))) {
Amaury Denoyelle2c5a7ee2022-08-17 16:33:53 +0200434 http_cookie_register(list, idx, &ck, &lck);
Willy Tarreau6deb4122018-11-27 15:34:18 +0100435 continue;
436 }
437
438 if (!htx_add_header(htx, list[idx].n, list[idx].v))
439 goto fail;
440 }
441
442 /* RFC7540#8.1.2.1 mandates to reject response pseudo-headers (:status) */
443 if (fields & H2_PHDR_FND_STAT)
444 goto fail;
445
446 /* Let's dump the request now if not yet emitted. */
447 if (!(fields & H2_PHDR_FND_NONE)) {
448 sl = h2_prepare_htx_reqline(fields, phdr_val, htx, msgf);
449 if (!sl)
450 goto fail;
451 }
452
Christopher Fauletd0db4232021-01-22 11:46:30 +0100453 if (*msgf & H2_MSGF_BODY_TUNNEL)
454 *msgf &= ~(H2_MSGF_BODY|H2_MSGF_BODY_CL);
455
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100456 if (!(*msgf & H2_MSGF_BODY) || ((*msgf & H2_MSGF_BODY_CL) && *body_len == 0) ||
457 (*msgf & H2_MSGF_BODY_TUNNEL)) {
458 /* Request without body or tunnel requested */
Christopher Faulet44af3cf2019-02-18 10:12:56 +0100459 sl_flags |= HTX_SL_F_BODYLESS;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100460 htx->flags |= HTX_FL_EOM;
461 }
Christopher Faulet44af3cf2019-02-18 10:12:56 +0100462
Amaury Denoyellec9a0afc2020-12-11 17:53:09 +0100463 if (*msgf & H2_MSGF_EXT_CONNECT) {
464 if (!htx_add_header(htx, ist("upgrade"), phdr_val[H2_PHDR_IDX_PROT]))
465 goto fail;
466 if (!htx_add_header(htx, ist("connection"), ist("upgrade")))
467 goto fail;
468 sl_flags |= HTX_SL_F_CONN_UPG;
469 }
470
Willy Tarreau6deb4122018-11-27 15:34:18 +0100471 /* update the start line with last detected header info */
472 sl->flags |= sl_flags;
473
Willy Tarreaub5d2b9e2021-08-11 15:39:13 +0200474 /* complete with missing Host if needed (we may validate this test if
475 * no regular header was found).
476 */
Willy Tarreau6deb4122018-11-27 15:34:18 +0100477 if ((fields & (H2_PHDR_FND_HOST|H2_PHDR_FND_AUTH)) == H2_PHDR_FND_AUTH) {
478 /* missing Host field, use :authority instead */
479 if (!htx_add_header(htx, ist("host"), phdr_val[H2_PHDR_IDX_AUTH]))
480 goto fail;
481 }
482
483 /* now we may have to build a cookie list. We'll dump the values of all
484 * visited headers.
485 */
486 if (ck >= 0) {
Amaury Denoyelle2c5a7ee2022-08-17 16:33:53 +0200487 if (http_cookie_merge(htx, list, ck))
Willy Tarreau6deb4122018-11-27 15:34:18 +0100488 goto fail;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100489 }
490
491 /* now send the end of headers marker */
Christopher Faulet5be651d2021-01-22 15:28:03 +0100492 if (!htx_add_endof(htx, HTX_BLK_EOH))
493 goto fail;
Willy Tarreau6deb4122018-11-27 15:34:18 +0100494
Amaury Denoyelle4ca0f362021-07-07 10:49:28 +0200495 /* proceed to scheme-based normalization on target-URI */
496 if (fields & H2_PHDR_FND_SCHM)
497 http_scheme_based_normalize(htx);
498
Willy Tarreau6deb4122018-11-27 15:34:18 +0100499 ret = 1;
500 return ret;
501
502 fail:
503 return -1;
504}
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200505
506/* Prepare the status line into <htx> from pseudo headers stored in <phdr[]>.
507 * <fields> indicates what was found so far. This should be called once at the
508 * detection of the first general header field or at the end of the message if
509 * no general header field was found yet. Returns the created start line on
510 * success, or NULL on failure. Upon success, <msgf> is updated with a few
511 * H2_MSGF_* flags indicating what was found while parsing.
512 */
513static struct htx_sl *h2_prepare_htx_stsline(uint32_t fields, struct ist *phdr, struct htx *htx, unsigned int *msgf)
514{
Willy Tarreaud8a44d02022-09-02 11:15:37 +0200515 unsigned int status, flags = HTX_SL_F_IS_RESP;
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200516 struct htx_sl *sl;
Amaury Denoyelle74162742020-12-11 17:53:05 +0100517 struct ist stat;
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200518
519 /* only :status is allowed as a pseudo header */
520 if (!(fields & H2_PHDR_FND_STAT))
521 goto fail;
522
523 if (phdr[H2_PHDR_IDX_STAT].len != 3)
524 goto fail;
525
Amaury Denoyelle74162742020-12-11 17:53:05 +0100526 /* if Extended CONNECT is used, convert status code from 200 to htx 101
527 * following rfc 8441 */
528 if (unlikely(*msgf & H2_MSGF_EXT_CONNECT) &&
529 isteq(phdr[H2_PHDR_IDX_STAT], ist("200"))) {
530 stat = ist("101");
531 status = 101;
532 }
533 else {
534 unsigned char h, t, u;
535
536 stat = phdr[H2_PHDR_IDX_STAT];
537
538 h = stat.ptr[0] - '0';
539 t = stat.ptr[1] - '0';
540 u = stat.ptr[2] - '0';
541 if (h > 9 || t > 9 || u > 9)
542 goto fail;
543 status = h * 100 + t * 10 + u;
544 }
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200545
Christopher Faulet89899422020-12-07 18:24:43 +0100546 /* 101 responses are not supported in H2, so return a error.
547 * On 1xx responses there is no ES on the HEADERS frame but there is no
548 * body. So remove the flag H2_MSGF_BODY and add H2_MSGF_RSP_1XX to
549 * notify the decoder another HEADERS frame is expected.
Ilya Shipitsinacf84592021-02-06 22:29:08 +0500550 * 204/304 response have no body by definition. So remove the flag
Christopher Faulet7d247f02020-12-02 14:26:36 +0100551 * H2_MSGF_BODY and set H2_MSGF_BODYLESS_RSP.
Amaury Denoyelle74162742020-12-11 17:53:05 +0100552 *
553 * Note however that there is a special condition for Extended CONNECT.
554 * In this case, we explicitly convert it to HTX 101 to mimic
555 * Get+Upgrade HTTP/1.1 mechanism
Christopher Faulet0b465482019-02-19 15:14:23 +0100556 */
Amaury Denoyelle74162742020-12-11 17:53:05 +0100557 if (status == 101) {
558 if (!(*msgf & H2_MSGF_EXT_CONNECT))
559 goto fail;
560 }
Christopher Faulet89899422020-12-07 18:24:43 +0100561 else if (status < 200) {
Christopher Faulet0b465482019-02-19 15:14:23 +0100562 *msgf |= H2_MSGF_RSP_1XX;
563 *msgf &= ~H2_MSGF_BODY;
564 }
Amaury Denoyelle74162742020-12-11 17:53:05 +0100565 else if (status == 204 || status == 304) {
Christopher Faulet7d247f02020-12-02 14:26:36 +0100566 *msgf &= ~H2_MSGF_BODY;
567 *msgf |= H2_MSGF_BODYLESS_RSP;
568 }
Christopher Faulet0b465482019-02-19 15:14:23 +0100569
Christopher Faulet89899422020-12-07 18:24:43 +0100570 /* Set HTX start-line flags */
571 flags |= HTX_SL_F_VER_11; // V2 in fact
572 flags |= HTX_SL_F_XFER_LEN; // xfer len always known with H2
573
Amaury Denoyelle74162742020-12-11 17:53:05 +0100574 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, ist("HTTP/2.0"), stat, ist(""));
Christopher Faulet89899422020-12-07 18:24:43 +0100575 if (!sl)
576 goto fail;
577 sl->info.res.status = status;
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200578 return sl;
579 fail:
580 return NULL;
581}
582
583/* Takes an H2 response present in the headers list <list> terminated by a name
584 * being <NULL,0> and emits the equivalent HTX response according to the rules
585 * documented in RFC7540 #8.1.2. The output contents are emitted in <htx>, and
586 * a positive value is returned if some bytes were emitted. In case of error, a
587 * negative error code is returned.
588 *
589 * Upon success, <msgf> is filled with a few H2_MSGF_* flags indicating what
590 * was found while parsing. The caller must set it to zero in or H2_MSGF_BODY
591 * if a body is detected (!ES).
592 *
593 * The headers list <list> must be composed of :
594 * - n.name != NULL, n.len > 0 : literal header name
595 * - n.name == NULL, n.len > 0 : indexed pseudo header name number <n.len>
596 * among H2_PHDR_IDX_*
597 * - n.name ignored, n.len == 0 : end of list
598 * - in all cases except the end of list, v.name and v.len must designate a
599 * valid value.
Amaury Denoyelle74162742020-12-11 17:53:05 +0100600 *
601 * <upgrade_protocol> is only used if the htx status code is 101 indicating a
602 * response to an upgrade or h2-equivalent request.
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200603 */
Amaury Denoyelle74162742020-12-11 17:53:05 +0100604int h2_make_htx_response(struct http_hdr *list, struct htx *htx, unsigned int *msgf, unsigned long long *body_len, char *upgrade_protocol)
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200605{
606 struct ist phdr_val[H2_PHDR_NUM_ENTRIES];
607 uint32_t fields; /* bit mask of H2_PHDR_FND_* */
608 uint32_t idx;
609 int phdr;
610 int ret;
611 int i;
612 struct htx_sl *sl = NULL;
613 unsigned int sl_flags = 0;
Willy Tarreau54f53ef2019-11-22 16:02:43 +0100614 const char *ctl;
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200615
616 fields = 0;
617 for (idx = 0; list[idx].n.len != 0; idx++) {
Tim Duesterhus77508502022-03-15 13:11:06 +0100618 if (!isttest(list[idx].n)) {
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200619 /* this is an indexed pseudo-header */
620 phdr = list[idx].n.len;
621 }
622 else {
623 /* this can be any type of header */
Willy Tarreau146f53a2019-11-24 10:34:39 +0100624 /* RFC7540#8.1.2: upper case not allowed in header field names.
625 * #10.3: header names must be valid (i.e. match a token).
626 * For pseudo-headers we check from 2nd char and for other ones
627 * from the first char, because HTTP_IS_TOKEN() also excludes
628 * the colon.
629 */
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200630 phdr = h2_str_to_phdr(list[idx].n);
Willy Tarreau146f53a2019-11-24 10:34:39 +0100631
632 for (i = !!phdr; i < list[idx].n.len; i++)
633 if ((uint8_t)(list[idx].n.ptr[i] - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(list[idx].n.ptr[i]))
634 goto fail;
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200635 }
636
Willy Tarreau54f53ef2019-11-22 16:02:43 +0100637 /* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
638 * rejecting NUL, CR and LF characters.
639 */
640 ctl = ist_find_ctl(list[idx].v);
641 if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
642 goto fail;
643
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200644 if (phdr > 0 && phdr < H2_PHDR_NUM_ENTRIES) {
645 /* insert a pseudo header by its index (in phdr) and value (in value) */
646 if (fields & ((1 << phdr) | H2_PHDR_FND_NONE)) {
647 if (fields & H2_PHDR_FND_NONE) {
648 /* pseudo header field after regular headers */
649 goto fail;
650 }
651 else {
652 /* repeated pseudo header field */
653 goto fail;
654 }
655 }
656 fields |= 1 << phdr;
657 phdr_val[phdr] = list[idx].v;
658 continue;
659 }
660 else if (phdr != 0) {
661 /* invalid pseudo header -- should never happen here */
662 goto fail;
663 }
664
665 /* regular header field in (name,value) */
666 if (!(fields & H2_PHDR_FND_NONE)) {
667 /* no more pseudo-headers, time to build the status line */
668 sl = h2_prepare_htx_stsline(fields, phdr_val, htx, msgf);
669 if (!sl)
670 goto fail;
671 fields |= H2_PHDR_FND_NONE;
672 }
673
Willy Tarreaubeefaee2018-12-19 13:08:08 +0100674 if (isteq(list[idx].n, ist("content-length"))) {
Amaury Denoyelle15f3cc42022-12-08 16:53:58 +0100675 ret = http_parse_cont_len_header(&list[idx].v, body_len,
676 *msgf & H2_MSGF_BODY_CL);
Willy Tarreaubeefaee2018-12-19 13:08:08 +0100677 if (ret < 0)
678 goto fail;
679
Amaury Denoyelle15f3cc42022-12-08 16:53:58 +0100680 *msgf |= H2_MSGF_BODY_CL;
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200681 sl_flags |= HTX_SL_F_CLEN;
Willy Tarreaubeefaee2018-12-19 13:08:08 +0100682 if (ret == 0)
683 continue; // skip this duplicate
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200684 }
685
686 /* these ones are forbidden in responses (RFC7540#8.1.2.2) */
687 if (isteq(list[idx].n, ist("connection")) ||
688 isteq(list[idx].n, ist("proxy-connection")) ||
689 isteq(list[idx].n, ist("keep-alive")) ||
690 isteq(list[idx].n, ist("upgrade")) ||
691 isteq(list[idx].n, ist("transfer-encoding")))
692 goto fail;
693
694 if (!htx_add_header(htx, list[idx].n, list[idx].v))
695 goto fail;
696 }
697
698 /* RFC7540#8.1.2.1 mandates to reject request pseudo-headers */
699 if (fields & (H2_PHDR_FND_AUTH|H2_PHDR_FND_METH|H2_PHDR_FND_PATH|H2_PHDR_FND_SCHM))
700 goto fail;
701
702 /* Let's dump the request now if not yet emitted. */
703 if (!(fields & H2_PHDR_FND_NONE)) {
704 sl = h2_prepare_htx_stsline(fields, phdr_val, htx, msgf);
705 if (!sl)
706 goto fail;
Amaury Denoyelle74162742020-12-11 17:53:05 +0100707 }
708
709 if (sl->info.res.status == 101 && upgrade_protocol) {
710 if (!htx_add_header(htx, ist("connection"), ist("upgrade")))
711 goto fail;
712 if (!htx_add_header(htx, ist("upgrade"), ist(upgrade_protocol)))
713 goto fail;
714 sl_flags |= HTX_SL_F_CONN_UPG;
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200715 }
716
Amaury Denoyelle74162742020-12-11 17:53:05 +0100717 if ((*msgf & H2_MSGF_BODY_TUNNEL) &&
718 ((sl->info.res.status >= 200 && sl->info.res.status < 300) || sl->info.res.status == 101))
Christopher Fauletd0db4232021-01-22 11:46:30 +0100719 *msgf &= ~(H2_MSGF_BODY|H2_MSGF_BODY_CL);
720 else
721 *msgf &= ~H2_MSGF_BODY_TUNNEL;
722
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100723 if (!(*msgf & H2_MSGF_BODY) || ((*msgf & H2_MSGF_BODY_CL) && *body_len == 0) ||
724 (*msgf & H2_MSGF_BODY_TUNNEL)) {
Ilya Shipitsinacf84592021-02-06 22:29:08 +0500725 /* Response without body or tunnel successfully established */
Christopher Faulet44af3cf2019-02-18 10:12:56 +0100726 sl_flags |= HTX_SL_F_BODYLESS;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100727 htx->flags |= HTX_FL_EOM;
728 }
Christopher Faulet44af3cf2019-02-18 10:12:56 +0100729
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200730 /* update the start line with last detected header info */
731 sl->flags |= sl_flags;
732
733 if ((*msgf & (H2_MSGF_BODY|H2_MSGF_BODY_TUNNEL|H2_MSGF_BODY_CL)) == H2_MSGF_BODY) {
734 /* FIXME: Do we need to signal anything when we have a body and
735 * no content-length, to have the equivalent of H1's chunked
736 * encoding?
737 */
738 }
739
740 /* now send the end of headers marker */
Christopher Faulet5be651d2021-01-22 15:28:03 +0100741 if (!htx_add_endof(htx, HTX_BLK_EOH))
742 goto fail;
Willy Tarreau1329b5b2018-10-08 14:49:20 +0200743
744 ret = 1;
745 return ret;
746
747 fail:
748 return -1;
749}
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100750
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200751/* Takes an H2 headers list <list> terminated by a name being <NULL,0> and emits
752 * the equivalent HTX trailers blocks. The output contents are emitted in <htx>,
753 * and a positive value is returned if some bytes were emitted. In case of
754 * error, a negative error code is returned. The caller must have verified that
755 * the message in the buffer is compatible with receipt of trailers.
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100756 *
757 * The headers list <list> must be composed of :
758 * - n.name != NULL, n.len > 0 : literal header name
759 * - n.name == NULL, n.len > 0 : indexed pseudo header name number <n.len>
760 * among H2_PHDR_IDX_* (illegal here)
761 * - n.name ignored, n.len == 0 : end of list
762 * - in all cases except the end of list, v.name and v.len must designate a
763 * valid value.
764 */
765int h2_make_htx_trailers(struct http_hdr *list, struct htx *htx)
766{
Willy Tarreau54f53ef2019-11-22 16:02:43 +0100767 const char *ctl;
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100768 uint32_t idx;
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100769 int i;
770
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100771 for (idx = 0; list[idx].n.len != 0; idx++) {
Tim Duesterhus77508502022-03-15 13:11:06 +0100772 if (!isttest(list[idx].n)) {
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100773 /* This is an indexed pseudo-header (RFC7540#8.1.2.1) */
774 goto fail;
775 }
776
Willy Tarreau146f53a2019-11-24 10:34:39 +0100777 /* RFC7540#8.1.2: upper case not allowed in header field names.
778 * #10.3: header names must be valid (i.e. match a token). This
779 * also catches pseudo-headers which are forbidden in trailers.
780 */
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100781 for (i = 0; i < list[idx].n.len; i++)
Willy Tarreau146f53a2019-11-24 10:34:39 +0100782 if ((uint8_t)(list[idx].n.ptr[i] - 'A') < 'Z' - 'A' || !HTTP_IS_TOKEN(list[idx].n.ptr[i]))
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100783 goto fail;
784
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100785 /* these ones are forbidden in trailers (RFC7540#8.1.2.2) */
786 if (isteq(list[idx].n, ist("host")) ||
787 isteq(list[idx].n, ist("content-length")) ||
788 isteq(list[idx].n, ist("connection")) ||
789 isteq(list[idx].n, ist("proxy-connection")) ||
790 isteq(list[idx].n, ist("keep-alive")) ||
791 isteq(list[idx].n, ist("upgrade")) ||
792 isteq(list[idx].n, ist("te")) ||
793 isteq(list[idx].n, ist("transfer-encoding")))
794 goto fail;
795
Willy Tarreau54f53ef2019-11-22 16:02:43 +0100796 /* RFC7540#10.3: intermediaries forwarding to HTTP/1 must take care of
797 * rejecting NUL, CR and LF characters.
798 */
799 ctl = ist_find_ctl(list[idx].v);
800 if (unlikely(ctl) && has_forbidden_char(list[idx].v, ctl))
801 goto fail;
802
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200803 if (!htx_add_trailer(htx, list[idx].n, list[idx].v))
804 goto fail;
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100805 }
806
Christopher Faulet2d7c5392019-06-03 10:41:26 +0200807 if (!htx_add_endof(htx, HTX_BLK_EOT))
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100808 goto fail;
809
Willy Tarreau1e1f27c2019-01-03 18:39:54 +0100810 return 1;
811
812 fail:
813 return -1;
814}