blob: 1f687086c4260ad89610e628257e3a70b9d94ebb [file] [log] [blame]
Christopher Faulet4f0f88a2019-08-10 11:17:44 +02001/*
2 * Functions to manipulate H1 messages using the internal representation.
3 *
4 * Copyright (C) 2019 HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreau4c7e4b72020-05-27 12:58:42 +020013#include <haproxy/api.h>
Willy Tarreau6be78492020-06-05 00:00:29 +020014#include <haproxy/cfgparse.h>
Willy Tarreaudfd3de82020-06-04 23:46:14 +020015#include <haproxy/global.h>
Willy Tarreau5413a872020-06-02 19:33:08 +020016#include <haproxy/h1.h>
Willy Tarreauc6fe8842020-06-04 09:00:02 +020017#include <haproxy/h1_htx.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +020018#include <haproxy/http.h>
Amaury Denoyelle852d78c2021-07-07 10:49:27 +020019#include <haproxy/http_htx.h>
Willy Tarreau16f958c2020-06-03 08:44:35 +020020#include <haproxy/htx.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020021#include <haproxy/tools.h>
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020022
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020023/* Estimate the size of the HTX headers after the parsing, including the EOH. */
24static size_t h1_eval_htx_hdrs_size(const struct http_hdr *hdrs)
25{
26 size_t sz = 0;
27 int i;
28
29 for (i = 0; hdrs[i].n.len; i++)
30 sz += sizeof(struct htx_blk) + hdrs[i].n.len + hdrs[i].v.len;
31 sz += sizeof(struct htx_blk) + 1;
32 return sz;
33}
34
35/* Estimate the size of the HTX request after the parsing. */
36static size_t h1_eval_htx_size(const struct ist p1, const struct ist p2, const struct ist p3,
37 const struct http_hdr *hdrs)
38{
39 size_t sz;
40
41 /* size of the HTX start-line */
42 sz = sizeof(struct htx_blk) + sizeof(struct htx_sl) + p1.len + p2.len + p3.len;
43 sz += h1_eval_htx_hdrs_size(hdrs);
44 return sz;
45}
46
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020047/* Check the validity of the request version. If the version is valid, it
48 * returns 1. Otherwise, it returns 0.
49 */
50static int h1_process_req_vsn(struct h1m *h1m, union h1_sl *sl)
51{
52 /* RFC7230#2.6 has enforced the format of the HTTP version string to be
53 * exactly one digit "." one digit. This check may be disabled using
54 * option accept-invalid-http-request.
55 */
56 if (h1m->err_pos == -2) { /* PR_O2_REQBUG_OK not set */
57 if (sl->rq.v.len != 8)
58 return 0;
59
Tim Duesterhus8f4116e2020-03-10 00:55:40 +010060 if (!istnmatch(sl->rq.v, ist("HTTP/"), 5) ||
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020061 !isdigit((unsigned char)*(sl->rq.v.ptr + 5)) ||
62 *(sl->rq.v.ptr + 6) != '.' ||
63 !isdigit((unsigned char)*(sl->rq.v.ptr + 7)))
64 return 0;
65 }
66 else if (!sl->rq.v.len) {
67 /* try to convert HTTP/0.9 requests to HTTP/1.0 */
68
69 /* RFC 1945 allows only GET for HTTP/0.9 requests */
70 if (sl->rq.meth != HTTP_METH_GET)
71 return 0;
72
73 /* HTTP/0.9 requests *must* have a request URI, per RFC 1945 */
74 if (!sl->rq.u.len)
75 return 0;
76
77 /* Add HTTP version */
78 sl->rq.v = ist("HTTP/1.0");
79 return 1;
80 }
81
82 if ((sl->rq.v.len == 8) &&
83 ((*(sl->rq.v.ptr + 5) > '1') ||
84 ((*(sl->rq.v.ptr + 5) == '1') && (*(sl->rq.v.ptr + 7) >= '1'))))
85 h1m->flags |= H1_MF_VER_11;
86 return 1;
87}
88
89/* Check the validity of the response version. If the version is valid, it
90 * returns 1. Otherwise, it returns 0.
91 */
92static int h1_process_res_vsn(struct h1m *h1m, union h1_sl *sl)
93{
94 /* RFC7230#2.6 has enforced the format of the HTTP version string to be
95 * exactly one digit "." one digit. This check may be disabled using
96 * option accept-invalid-http-request.
97 */
98 if (h1m->err_pos == -2) { /* PR_O2_REQBUG_OK not set */
99 if (sl->st.v.len != 8)
100 return 0;
101
102 if (*(sl->st.v.ptr + 4) != '/' ||
103 !isdigit((unsigned char)*(sl->st.v.ptr + 5)) ||
104 *(sl->st.v.ptr + 6) != '.' ||
105 !isdigit((unsigned char)*(sl->st.v.ptr + 7)))
106 return 0;
107 }
108
109 if ((sl->st.v.len == 8) &&
110 ((*(sl->st.v.ptr + 5) > '1') ||
111 ((*(sl->st.v.ptr + 5) == '1') && (*(sl->st.v.ptr + 7) >= '1'))))
112 h1m->flags |= H1_MF_VER_11;
113
114 return 1;
115}
116
117/* Convert H1M flags to HTX start-line flags. */
118static unsigned int h1m_htx_sl_flags(struct h1m *h1m)
119{
120 unsigned int flags = HTX_SL_F_NONE;
121
122 if (h1m->flags & H1_MF_RESP)
123 flags |= HTX_SL_F_IS_RESP;
124 if (h1m->flags & H1_MF_VER_11)
125 flags |= HTX_SL_F_VER_11;
126 if (h1m->flags & H1_MF_XFER_ENC)
127 flags |= HTX_SL_F_XFER_ENC;
128 if (h1m->flags & H1_MF_XFER_LEN) {
129 flags |= HTX_SL_F_XFER_LEN;
130 if (h1m->flags & H1_MF_CHNK)
131 flags |= HTX_SL_F_CHNK;
132 else if (h1m->flags & H1_MF_CLEN) {
133 flags |= HTX_SL_F_CLEN;
134 if (h1m->body_len == 0)
135 flags |= HTX_SL_F_BODYLESS;
136 }
137 else
138 flags |= HTX_SL_F_BODYLESS;
139 }
Christopher Faulet576c3582021-01-08 15:53:01 +0100140 if (h1m->flags & H1_MF_CONN_UPG)
141 flags |= HTX_SL_F_CONN_UPG;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200142 return flags;
143}
144
145/* Postprocess the parsed headers for a request and convert them into an htx
146 * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
147 * proceed. Parsing errors are reported by setting the htx flag
148 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
149 */
150static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
151 struct http_hdr *hdrs, size_t max)
152{
153 struct htx_sl *sl;
154 struct ist meth, uri, vsn;
155 unsigned int flags;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200156
157 /* <h1sl> is always defined for a request */
158 meth = h1sl->rq.m;
159 uri = h1sl->rq.u;
160 vsn = h1sl->rq.v;
161
162 /* Be sure the message, once converted into HTX, will not exceed the max
163 * size allowed.
164 */
165 if (h1_eval_htx_size(meth, uri, vsn, hdrs) > max) {
166 if (htx_is_empty(htx))
167 goto error;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200168 goto output_full;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200169 }
170
171 /* By default, request have always a known length */
172 h1m->flags |= H1_MF_XFER_LEN;
173
174 if (h1sl->rq.meth == HTTP_METH_CONNECT) {
Christopher Faulet5be651d2021-01-22 15:28:03 +0100175 h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
176 h1m->curr_len = h1m->body_len = 0;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200177 }
178
Christopher Faulet52a5ec22021-09-09 09:52:51 +0200179
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200180 flags = h1m_htx_sl_flags(h1m);
Christopher Faulet52a5ec22021-09-09 09:52:51 +0200181 if ((flags & (HTX_SL_F_CONN_UPG|HTX_SL_F_BODYLESS)) == HTX_SL_F_CONN_UPG) {
182 int i;
183
184 for (i = 0; hdrs[i].n.len; i++) {
185 if (isteqi(hdrs[i].n, ist("upgrade")))
186 hdrs[i].v = IST_NULL;
187 }
188 h1m->flags &=~ H1_MF_CONN_UPG;
189 flags &= ~HTX_SL_F_CONN_UPG;
190 }
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200191 sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth, uri, vsn);
192 if (!sl || !htx_add_all_headers(htx, hdrs))
193 goto error;
194 sl->info.req.meth = h1sl->rq.meth;
195
Christopher Fauletfe451fb2019-10-08 15:01:34 +0200196 /* Check if the uri contains an authority. Also check if it contains an
197 * explicit scheme and if it is "http" or "https". */
198 if (h1sl->rq.meth == HTTP_METH_CONNECT)
199 sl->flags |= HTX_SL_F_HAS_AUTHORITY;
200 else if (uri.len && uri.ptr[0] != '/' && uri.ptr[0] != '*') {
201 sl->flags |= (HTX_SL_F_HAS_AUTHORITY|HTX_SL_F_HAS_SCHM);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200202 if (uri.len > 4 && (uri.ptr[0] | 0x20) == 'h')
203 sl->flags |= ((uri.ptr[4] == ':') ? HTX_SL_F_SCHM_HTTP : HTX_SL_F_SCHM_HTTPS);
Amaury Denoyelle852d78c2021-07-07 10:49:27 +0200204
205 /* absolute-form target URI present, proceed to scheme-based
206 * normalization */
207 http_scheme_based_normalize(htx);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200208 }
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200209
210 /* If body length cannot be determined, set htx->extra to
Christopher Faulet2e47e3a2023-01-13 11:40:24 +0100211 * HTX_UNKOWN_PAYLOAD_LENGTH. This value is impossible in other cases.
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200212 */
Christopher Faulet2e47e3a2023-01-13 11:40:24 +0100213 htx->extra = ((h1m->flags & H1_MF_XFER_LEN) ? h1m->curr_len : HTX_UNKOWN_PAYLOAD_LENGTH);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200214
215 end:
216 return 1;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200217 output_full:
218 h1m_init_req(h1m);
219 h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
220 return -2;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200221 error:
222 h1m->err_pos = h1m->next;
223 h1m->err_state = h1m->state;
224 htx->flags |= HTX_FL_PARSING_ERROR;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200225 return -1;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200226}
227
228/* Postprocess the parsed headers for a response and convert them into an htx
229 * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
230 * proceed. Parsing errors are reported by setting the htx flag
231 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
232 */
233static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
234 struct http_hdr *hdrs, size_t max)
235{
236 struct htx_sl *sl;
237 struct ist vsn, status, reason;
238 unsigned int flags;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200239 uint16_t code = 0;
240
241 if (h1sl) {
242 /* For HTTP responses, the start-line was parsed */
243 code = h1sl->st.status;
244 vsn = h1sl->st.v;
245 status = h1sl->st.c;
246 reason = h1sl->st.r;
247 }
248 else {
249 /* For FCGI responses, there is no start(-line but the "Status"
250 * header must be parsed, if found.
251 */
252 int hdr;
253
254 vsn = ((h1m->flags & H1_MF_VER_11) ? ist("HTTP/1.1") : ist("HTTP/1.0"));
255 for (hdr = 0; hdrs[hdr].n.len; hdr++) {
256 if (isteqi(hdrs[hdr].n, ist("status"))) {
257 code = http_parse_status_val(hdrs[hdr].v, &status, &reason);
258 }
259 else if (isteqi(hdrs[hdr].n, ist("location"))) {
260 code = 302;
261 status = ist("302");
Christopher Fauleta3ba46a2023-07-20 09:50:56 +0200262 reason = ist("Found");
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200263 }
264 }
265 if (!code) {
266 code = 200;
267 status = ist("200");
268 reason = ist("OK");
269 }
270 /* FIXME: Check the codes 1xx ? */
271 }
272
273 /* Be sure the message, once converted into HTX, will not exceed the max
274 * size allowed.
275 */
276 if (h1_eval_htx_size(vsn, status, reason, hdrs) > max) {
277 if (htx_is_empty(htx))
278 goto error;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200279 goto output_full;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200280 }
281
Christopher Faulet5f36bfe2023-01-10 18:51:55 +0100282 if ((h1m->flags & (H1_MF_CONN_UPG|H1_MF_UPG_WEBSOCKET)) && code != 101)
283 h1m->flags &= ~(H1_MF_CONN_UPG|H1_MF_UPG_WEBSOCKET);
284
Christopher Fauletc75668e2020-12-07 18:10:32 +0100285 if (((h1m->flags & H1_MF_METH_CONNECT) && code >= 200 && code < 300) || code == 101) {
Christopher Faulet5be651d2021-01-22 15:28:03 +0100286 h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
287 h1m->flags |= H1_MF_XFER_LEN;
288 h1m->curr_len = h1m->body_len = 0;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200289 }
290 else if ((h1m->flags & H1_MF_METH_HEAD) || (code >= 100 && code < 200) ||
291 (code == 204) || (code == 304)) {
292 /* Responses known to have no body. */
293 h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
294 h1m->flags |= H1_MF_XFER_LEN;
295 h1m->curr_len = h1m->body_len = 0;
296 }
297 else if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
298 /* Responses with a known body length. */
299 h1m->flags |= H1_MF_XFER_LEN;
300 }
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200301
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200302 flags = h1m_htx_sl_flags(h1m);
303 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, vsn, status, reason);
304 if (!sl || !htx_add_all_headers(htx, hdrs))
305 goto error;
306 sl->info.res.status = code;
307
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200308 /* If body length cannot be determined, set htx->extra to
Christopher Faulet2e47e3a2023-01-13 11:40:24 +0100309 * HTX_UNKOWN_PAYLOAD_LENGTH. This value is impossible in other cases.
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200310 */
Christopher Faulet2e47e3a2023-01-13 11:40:24 +0100311 htx->extra = ((h1m->flags & H1_MF_XFER_LEN) ? h1m->curr_len : HTX_UNKOWN_PAYLOAD_LENGTH);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200312
313 end:
314 return 1;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200315 output_full:
316 h1m_init_res(h1m);
317 h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
318 return -2;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200319 error:
320 h1m->err_pos = h1m->next;
321 h1m->err_state = h1m->state;
322 htx->flags |= HTX_FL_PARSING_ERROR;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200323 return -1;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200324}
325
Christopher Faulet46e058d2021-09-20 07:47:27 +0200326/* Parse HTTP/1 headers. It returns the number of bytes parsed on success, 0 if
327 * headers are incomplete, -1 if an error occurred or -2 if it needs more space
328 * to proceed while the output buffer is not empty. Parsing errors are reported
329 * by setting the htx flag HTX_FL_PARSING_ERROR and filling h1m->err_pos and
330 * h1m->err_state fields. This functions is responsible to update the parser
331 * state <h1m> and the start-line <h1sl> if not NULL. For the requests, <h1sl>
332 * must always be provided. For responses, <h1sl> may be NULL and <h1m> flags
333 * HTTP_METH_CONNECT of HTTP_METH_HEAD may be set.
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200334 */
Christopher Faulet46e058d2021-09-20 07:47:27 +0200335int h1_parse_msg_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *dsthtx,
336 struct buffer *srcbuf, size_t ofs, size_t max)
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200337{
338 struct http_hdr hdrs[global.tune.max_http_hdr];
Christopher Faulet46e058d2021-09-20 07:47:27 +0200339 int total = 0, ret = 0;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200340
341 if (!max || !b_data(srcbuf))
342 goto end;
343
344 /* Realing input buffer if necessary */
345 if (b_head(srcbuf) + b_data(srcbuf) > b_wrap(srcbuf))
Christopher Faulet00d7cde2021-02-04 11:01:51 +0100346 b_slow_realign_ofs(srcbuf, trash.area, 0);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200347
348 if (!h1sl) {
349 /* If there no start-line, be sure to only parse the headers */
350 h1m->flags |= H1_MF_HDRS_ONLY;
351 }
352 ret = h1_headers_to_hdr_list(b_peek(srcbuf, ofs), b_tail(srcbuf),
353 hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, h1sl);
354 if (ret <= 0) {
355 /* Incomplete or invalid message. If the input buffer only
356 * contains headers and is full, which is detected by it being
357 * full and the offset to be zero, it's an error because
358 * headers are too large to be handled by the parser. */
359 if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
360 goto error;
361 goto end;
362 }
Christopher Faulet46e058d2021-09-20 07:47:27 +0200363 total = ret;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200364
365 /* messages headers fully parsed, do some checks to prepare the body
366 * parsing.
367 */
368
369 if (!(h1m->flags & H1_MF_RESP)) {
370 if (!h1_process_req_vsn(h1m, h1sl)) {
371 h1m->err_pos = h1sl->rq.v.ptr - b_head(srcbuf);
372 h1m->err_state = h1m->state;
373 goto vsn_error;
374 }
Christopher Faulet46e058d2021-09-20 07:47:27 +0200375 ret = h1_postparse_req_hdrs(h1m, h1sl, dsthtx, hdrs, max);
376 if (ret < 0)
377 return ret;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200378 }
379 else {
380 if (h1sl && !h1_process_res_vsn(h1m, h1sl)) {
381 h1m->err_pos = h1sl->st.v.ptr - b_head(srcbuf);
382 h1m->err_state = h1m->state;
383 goto vsn_error;
384 }
Christopher Faulet46e058d2021-09-20 07:47:27 +0200385 ret = h1_postparse_res_hdrs(h1m, h1sl, dsthtx, hdrs, max);
386 if (ret < 0)
387 return ret;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200388 }
389
Christopher Faulet76014fd2019-12-10 11:47:22 +0100390 /* Switch messages without any payload to DONE state */
391 if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100392 ((h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN)) {
Christopher Faulet76014fd2019-12-10 11:47:22 +0100393 h1m->state = H1_MSG_DONE;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100394 dsthtx->flags |= HTX_FL_EOM;
395 }
Christopher Faulet76014fd2019-12-10 11:47:22 +0100396
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200397 end:
Christopher Faulet46e058d2021-09-20 07:47:27 +0200398 return total;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200399 error:
400 h1m->err_pos = h1m->next;
401 h1m->err_state = h1m->state;
402 vsn_error:
403 dsthtx->flags |= HTX_FL_PARSING_ERROR;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200404 return -1;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200405
406}
407
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200408/* Copy data from <srbuf> into an DATA block in <dsthtx>. If possible, a
409 * zero-copy is performed. It returns the number of bytes copied.
410 */
Christopher Fauletde471a42021-02-01 16:37:28 +0100411static size_t h1_copy_msg_data(struct htx **dsthtx, struct buffer *srcbuf, size_t ofs,
Christopher Fauletf7c20442021-02-02 19:40:07 +0100412 size_t count, size_t max, struct buffer *htxbuf)
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200413{
Christopher Fauletaf542632019-10-01 21:52:49 +0200414 struct htx *tmp_htx = *dsthtx;
Christopher Fauletf7c20442021-02-02 19:40:07 +0100415 size_t block1, block2, ret = 0;
416
417 /* Be prepared to create at least one HTX block by reserving its size
418 * and adjust <count> accordingly.
419 */
Christopher Fauletc9ec9bc2023-02-24 16:49:06 +0100420 if (max <= sizeof(struct htx_blk))
421 goto end;
Christopher Fauletf7c20442021-02-02 19:40:07 +0100422 max -= sizeof(struct htx_blk);
423 if (count > max)
424 count = max;
Christopher Fauletaf542632019-10-01 21:52:49 +0200425
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200426 /* very often with large files we'll face the following
427 * situation :
428 * - htx is empty and points to <htxbuf>
Christopher Fauletf7c20442021-02-02 19:40:07 +0100429 * - count == srcbuf->data
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200430 * - srcbuf->head == sizeof(struct htx)
431 * => we can swap the buffers and place an htx header into
432 * the target buffer instead
433 */
Christopher Fauletaf542632019-10-01 21:52:49 +0200434 if (unlikely(htx_is_empty(tmp_htx) && count == b_data(srcbuf) &&
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200435 !ofs && b_head_ofs(srcbuf) == sizeof(struct htx))) {
436 void *raw_area = srcbuf->area;
437 void *htx_area = htxbuf->area;
438 struct htx_blk *blk;
439
440 srcbuf->area = htx_area;
441 htxbuf->area = raw_area;
Christopher Fauletaf542632019-10-01 21:52:49 +0200442 tmp_htx = (struct htx *)htxbuf->area;
443 tmp_htx->size = htxbuf->size - sizeof(*tmp_htx);
444 htx_reset(tmp_htx);
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200445 b_set_data(htxbuf, b_size(htxbuf));
446
Christopher Fauletaf542632019-10-01 21:52:49 +0200447 blk = htx_add_blk(tmp_htx, HTX_BLK_DATA, count);
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200448 blk->info += count;
Christopher Fauletaf542632019-10-01 21:52:49 +0200449
450 *dsthtx = tmp_htx;
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200451 /* nothing else to do, the old buffer now contains an
452 * empty pre-initialized HTX header
453 */
454 return count;
455 }
456
Christopher Fauletf7c20442021-02-02 19:40:07 +0100457 /* * First block is the copy of contiguous data starting at offset <ofs>
458 * with <count> as max. <max> is updated accordingly
459 *
460 * * Second block is the remaining (count - block1) if <max> is large
461 * enough. Another HTX block is reserved.
462 */
463 block1 = b_contig_data(srcbuf, ofs);
464 block2 = 0;
465 if (block1 > count)
466 block1 = count;
467 max -= block1;
468
469 if (max > sizeof(struct htx_blk)) {
470 block2 = count - block1;
471 max -= sizeof(struct htx_blk);
472 if (block2 > max)
473 block2 = max;
474 }
475
476 ret = htx_add_data(tmp_htx, ist2(b_peek(srcbuf, ofs), block1));
477 if (ret == block1 && block2)
478 ret += htx_add_data(tmp_htx, ist2(b_orig(srcbuf), block2));
479 end:
480 return ret;
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200481}
482
Christopher Faulet7a835f32021-05-21 11:31:35 +0200483static const char hextable[] = {
484 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
485 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
486 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
487 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
488 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
489 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
490 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
491 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
492};
493
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200494/* Generic function to parse the current HTTP chunk. It may be used to parsed
Ilya Shipitsin213bb992021-06-12 15:55:27 +0500495 * any kind of chunks, including incomplete HTTP chunks or split chunks
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200496 * because the buffer wraps. This version tries to performed zero-copy on large
497 * chunks if possible.
Christopher Faulet140691b2021-02-03 11:51:24 +0100498 */
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200499static size_t h1_parse_chunk(struct h1m *h1m, struct htx **dsthtx,
500 struct buffer *srcbuf, size_t ofs, size_t *max,
501 struct buffer *htxbuf)
Christopher Faulet140691b2021-02-03 11:51:24 +0100502{
503 uint64_t chksz;
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200504 size_t sz, used, lmax, total = 0;
Christopher Faulet140691b2021-02-03 11:51:24 +0100505 int ret = 0;
506
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200507 lmax = *max;
Christopher Faulet140691b2021-02-03 11:51:24 +0100508 switch (h1m->state) {
509 case H1_MSG_DATA:
510 new_chunk:
511 used = htx_used_space(*dsthtx);
Christopher Fauletc9ec9bc2023-02-24 16:49:06 +0100512 if (b_data(srcbuf) == ofs || lmax <= sizeof(struct htx_blk))
Christopher Faulet140691b2021-02-03 11:51:24 +0100513 break;
514
515 sz = b_data(srcbuf) - ofs;
516 if (unlikely(sz > h1m->curr_len))
517 sz = h1m->curr_len;
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200518 sz = h1_copy_msg_data(dsthtx, srcbuf, ofs, sz, lmax, htxbuf);
519 lmax -= htx_used_space(*dsthtx) - used;
Christopher Faulet140691b2021-02-03 11:51:24 +0100520 ofs += sz;
521 total += sz;
522 h1m->curr_len -= sz;
523 if (h1m->curr_len)
524 break;
525
526 h1m->state = H1_MSG_CHUNK_CRLF;
Willy Tarreau779aa692022-11-14 07:32:50 +0100527 __fallthrough;
Christopher Faulet140691b2021-02-03 11:51:24 +0100528
529 case H1_MSG_CHUNK_CRLF:
530 ret = h1_skip_chunk_crlf(srcbuf, ofs, b_data(srcbuf));
531 if (ret <= 0)
532 break;
533 ofs += ret;
534 total += ret;
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200535
536 /* Don't parse next chunk to try to handle contiguous chunks if possible */
Christopher Faulet140691b2021-02-03 11:51:24 +0100537 h1m->state = H1_MSG_CHUNK_SIZE;
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200538 break;
Christopher Faulet140691b2021-02-03 11:51:24 +0100539
540 case H1_MSG_CHUNK_SIZE:
541 ret = h1_parse_chunk_size(srcbuf, ofs, b_data(srcbuf), &chksz);
542 if (ret <= 0)
543 break;
544 h1m->state = ((!chksz) ? H1_MSG_TRAILERS : H1_MSG_DATA);
545 h1m->curr_len = chksz;
546 h1m->body_len += chksz;
547 ofs += ret;
548 total += ret;
549
550 if (h1m->curr_len) {
551 h1m->state = H1_MSG_DATA;
552 goto new_chunk;
553 }
554 h1m->state = H1_MSG_TRAILERS;
555 break;
556
557 default:
558 /* unexpected */
559 ret = -1;
560 break;
561 }
562
563 if (ret < 0) {
564 (*dsthtx)->flags |= HTX_FL_PARSING_ERROR;
565 h1m->err_state = h1m->state;
566 h1m->err_pos = ofs;
567 total = 0;
568 }
569
570 /* Don't forget to update htx->extra */
571 (*dsthtx)->extra = h1m->curr_len;
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200572 *max = lmax;
573 return total;
574}
575
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200576/* Parses full contiguous HTTP chunks. This version is optimized for small
577 * chunks and does not performed zero-copy. It must be called in
Ilya Shipitsin213bb992021-06-12 15:55:27 +0500578 * H1_MSG_CHUNK_SIZE state. Be careful if you change something in this
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200579 * function. It is really sensitive, any change may have an impact on
580 * performance.
581 */
582static size_t h1_parse_full_contig_chunks(struct h1m *h1m, struct htx **dsthtx,
583 struct buffer *srcbuf, size_t ofs, size_t *max,
584 struct buffer *htxbuf)
585{
586 char *start, *end, *dptr;
587 ssize_t dpos, ridx, save;
588 size_t lmax, total = 0;
589 uint64_t chksz;
590 struct htx_ret htxret;
591
Christopher Fauletc9ec9bc2023-02-24 16:49:06 +0100592 lmax = *max;
593 if (lmax <= sizeof(struct htx_blk))
594 goto out;
595
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200596 /* source info :
597 * start : pointer at <ofs> position
598 * end : pointer marking the end of data to parse
599 * ridx : the reverse index (negative) marking the parser position (end[ridx])
600 */
601 ridx = -b_contig_data(srcbuf, ofs);
602 if (!ridx)
603 goto out;
604 start = b_peek(srcbuf, ofs);
605 end = start - ridx;
606
607 /* Reserve the maximum possible size for the data */
608 htxret = htx_reserve_max_data(*dsthtx);
609 if (!htxret.blk)
610 goto out;
611
612 /* destination info :
613 * dptr : pointer on the beginning of the data
614 * dpos : current position where to copy data
615 */
616 dptr = htx_get_blk_ptr(*dsthtx, htxret.blk);
617 dpos = htxret.ret;
618
619 /* Empty DATA block is not possible, thus if <dpos> is the beginning of
620 * the block, it means it is a new block. We can remove the block size
621 * from <max>. Then we must adjust it if it exceeds the free size in the
622 * block.
623 */
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200624 if (!dpos)
625 lmax -= sizeof(struct htx_blk);
626 if (lmax > htx_get_blksz(htxret.blk) - dpos)
627 lmax = htx_get_blksz(htxret.blk) - dpos;
628
629 while (1) {
630 /* The chunk size is in the following form, though we are only
631 * interested in the size and CRLF :
632 * 1*HEXDIGIT *WSP *[ ';' extensions ] CRLF
633 */
634 chksz = 0;
635 save = ridx; /* Save the parser position to rewind if necessary */
636 while (1) {
637 int c;
638
639 if (!ridx)
640 goto end_parsing;
641
642 /* Convert current character */
Christopher Faulet7a835f32021-05-21 11:31:35 +0200643 c = hextable[(unsigned char)end[ridx]];
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200644
645 /* not a hex digit anymore */
Christopher Fauletbf76df12021-06-11 13:39:06 +0200646 if (c & 0xF0)
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200647 break;
648
649 /* Update current chunk size */
650 chksz = (chksz << 4) + c;
651
Willy Tarreau8f0b4e92022-01-28 09:39:24 +0100652 if (unlikely(chksz & 0xF0000000000000ULL)) {
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200653 /* Don't get more than 13 hexa-digit (2^52 - 1)
654 * to never fed possibly bogus values from
655 * languages that use floats for their integers
656 */
657 goto parsing_error;
658 }
659 ++ridx;
660 }
661
662 if (unlikely(chksz > lmax))
663 goto end_parsing;
664
665 if (unlikely(ridx == save)) {
666 /* empty size not allowed */
667 goto parsing_error;
668 }
669
670 /* Skip spaces */
671 while (HTTP_IS_SPHT(end[ridx])) {
672 if (!++ridx)
673 goto end_parsing;
674 }
675
676 /* Up to there, we know that at least one byte is present. Check
677 * for the end of chunk size.
678 */
679 while (1) {
680 if (likely(end[ridx] == '\r')) {
681 /* Parse CRLF */
682 if (!++ridx)
683 goto end_parsing;
684 if (unlikely(end[ridx] != '\n')) {
685 /* CR must be followed by LF */
686 goto parsing_error;
687 }
688
689 /* done */
690 ++ridx;
691 break;
692 }
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200693 else if (likely(end[ridx] == ';')) {
694 /* chunk extension, ends at next CRLF */
695 if (!++ridx)
696 goto end_parsing;
697 while (!HTTP_IS_CRLF(end[ridx])) {
698 if (!++ridx)
699 goto end_parsing;
700 }
701 /* we have a CRLF now, loop above */
702 continue;
703 }
704 else {
Christopher Fauleta73e00a2024-01-26 16:30:53 +0100705 /* all other characters are unexpected, especially LF alone */
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200706 goto parsing_error;
707 }
708 }
709
710 /* Exit if it is the last chunk */
711 if (unlikely(!chksz)) {
712 h1m->state = H1_MSG_TRAILERS;
713 save = ridx;
714 goto end_parsing;
715 }
716
717 /* Now check if the whole chunk is here (including the CRLF at
Ilya Shipitsin213bb992021-06-12 15:55:27 +0500718 * the end), otherwise we switch in H1_MSG_DATA state.
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200719 */
720 if (chksz + 2 > -ridx) {
721 h1m->curr_len = chksz;
722 h1m->body_len += chksz;
723 h1m->state = H1_MSG_DATA;
724 (*dsthtx)->extra = h1m->curr_len;
725 save = ridx;
726 goto end_parsing;
727 }
728
729 memcpy(dptr + dpos, end + ridx, chksz);
730 h1m->body_len += chksz;
731 lmax -= chksz;
732 dpos += chksz;
733 ridx += chksz;
734
Christopher Faulet8df94eb2024-01-26 16:23:51 +0100735 /* Parse CRLF */
736 if (unlikely(end[ridx] != '\r')) {
737 h1m->state = H1_MSG_CHUNK_CRLF;
738 goto parsing_error;
739 }
740 ++ridx;
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200741 if (end[ridx] != '\n') {
742 h1m->state = H1_MSG_CHUNK_CRLF;
743 goto parsing_error;
744 }
745 ++ridx;
746 }
747
748 end_parsing:
749 ridx = save;
750
751 /* Adjust the HTX block size or remove the block if nothing was copied
752 * (Empty HTX data block are not supported).
753 */
754 if (!dpos)
755 htx_remove_blk(*dsthtx, htxret.blk);
756 else
757 htx_change_blk_value_len(*dsthtx, htxret.blk, dpos);
758 total = end + ridx - start;
759 *max = lmax;
760
761 out:
762 return total;
763
764 parsing_error:
765 (*dsthtx)->flags |= HTX_FL_PARSING_ERROR;
766 h1m->err_state = h1m->state;
767 h1m->err_pos = ofs + end + ridx - start;
768 return 0;
769}
770
771/* Parse HTTP chunks. This function relies on an optimized function to parse
772 * contiguous chunks if possible. Otherwise, when a chunk is incomplete or when
773 * the underlying buffer is wrapping, a generic function is used.
774 */
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200775static size_t h1_parse_msg_chunks(struct h1m *h1m, struct htx **dsthtx,
776 struct buffer *srcbuf, size_t ofs, size_t max,
777 struct buffer *htxbuf)
778{
779 size_t ret, total = 0;
780
781 while (ofs < b_data(srcbuf)) {
782 ret = 0;
783
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200784 /* First parse full contiguous chunks. It is only possible if we
785 * are waiting for the next chunk size.
786 */
787 if (h1m->state == H1_MSG_CHUNK_SIZE) {
788 ret = h1_parse_full_contig_chunks(h1m, dsthtx, srcbuf, ofs, &max, htxbuf);
789 /* exit on error */
790 if (!ret && (*dsthtx)->flags & HTX_FL_PARSING_ERROR) {
791 total = 0;
792 break;
793 }
794 /* or let a chance to parse remaining data */
795 total += ret;
796 ofs += ret;
797 ret = 0;
798 }
799
800 /* If some data remains, try to parse it using the generic
Ilya Shipitsin213bb992021-06-12 15:55:27 +0500801 * function handling incomplete chunks and split chunks
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200802 * because of a wrapping buffer.
803 */
804 if (h1m->state < H1_MSG_TRAILERS && ofs < b_data(srcbuf)) {
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200805 ret = h1_parse_chunk(h1m, dsthtx, srcbuf, ofs, &max, htxbuf);
806 total += ret;
807 ofs += ret;
808 }
809
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200810 /* nothing more was parsed or parsing was stopped on incomplete
811 * chunk, we can exit, handling parsing error if necessary.
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200812 */
Christopher Fauletbdcefe52021-05-21 11:05:12 +0200813 if (!ret || h1m->state != H1_MSG_CHUNK_SIZE) {
Christopher Faulet0d4c9242021-05-21 10:56:24 +0200814 if ((*dsthtx)->flags & HTX_FL_PARSING_ERROR)
815 total = 0;
816 break;
817 }
818 }
819
Christopher Faulet140691b2021-02-03 11:51:24 +0100820 return total;
821}
822
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200823/* Parse HTTP/1 body. It returns the number of bytes parsed if > 0, or 0 if it
824 * couldn't proceed. Parsing errors are reported by setting the htx flags
825 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
826 * functions is responsible to update the parser state <h1m>.
827 */
Christopher Fauletde471a42021-02-01 16:37:28 +0100828size_t h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
829 struct buffer *srcbuf, size_t ofs, size_t max,
830 struct buffer *htxbuf)
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200831{
Christopher Fauletde471a42021-02-01 16:37:28 +0100832 size_t sz, total = 0;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200833
Chris Staite3bef4e72023-09-04 08:52:26 +0000834 if (b_data(srcbuf) == ofs)
Christopher Faulet140691b2021-02-03 11:51:24 +0100835 return 0;
Christopher Fauletf7c20442021-02-02 19:40:07 +0100836
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200837 if (h1m->flags & H1_MF_CLEN) {
838 /* content-length: read only h2m->body_len */
Christopher Fauletf7c20442021-02-02 19:40:07 +0100839 sz = b_data(srcbuf) - ofs;
840 if (unlikely(sz > h1m->curr_len))
Christopher Fauletde471a42021-02-01 16:37:28 +0100841 sz = h1m->curr_len;
Christopher Fauletf7c20442021-02-02 19:40:07 +0100842 sz = h1_copy_msg_data(dsthtx, srcbuf, ofs, sz, max, htxbuf);
843 h1m->curr_len -= sz;
844 (*dsthtx)->extra = h1m->curr_len;
845 total += sz;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100846 if (!h1m->curr_len) {
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200847 h1m->state = H1_MSG_DONE;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100848 (*dsthtx)->flags |= HTX_FL_EOM;
849 }
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200850 }
851 else if (h1m->flags & H1_MF_CHNK) {
852 /* te:chunked : parse chunks */
Christopher Faulet140691b2021-02-03 11:51:24 +0100853 total += h1_parse_msg_chunks(h1m, dsthtx, srcbuf, ofs, max, htxbuf);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200854 }
855 else if (h1m->flags & H1_MF_XFER_LEN) {
856 /* XFER_LEN is set but not CLEN nor CHNK, it means there is no
857 * body. Switch the message in DONE state
858 */
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200859 h1m->state = H1_MSG_DONE;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100860 (*dsthtx)->flags |= HTX_FL_EOM;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200861 }
862 else {
863 /* no content length, read till SHUTW */
Christopher Fauletf7c20442021-02-02 19:40:07 +0100864 sz = b_data(srcbuf) - ofs;
865 sz = h1_copy_msg_data(dsthtx, srcbuf, ofs, sz, max, htxbuf);
866 total += sz;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200867 }
868
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200869 return total;
870}
871
Christopher Faulet46e058d2021-09-20 07:47:27 +0200872/* Parse HTTP/1 trailers. It returns the number of bytes parsed on success, 0 if
873 * trailers are incomplete, -1 if an error occurred or -2 if it needs more space
874 * to proceed while the output buffer is not empty. Parsing errors are reported
875 * by setting the htx flags HTX_FL_PARSING_ERROR and filling h1m->err_pos and
876 * h1m->err_state fields. This functions is responsible to update the parser
877 * state <h1m>.
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200878 */
Christopher Faulet46e058d2021-09-20 07:47:27 +0200879int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx,
880 struct buffer *srcbuf, size_t ofs, size_t max)
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200881{
882 struct http_hdr hdrs[global.tune.max_http_hdr];
883 struct h1m tlr_h1m;
884 int ret = 0;
885
Christopher Fauletae660be2022-04-13 17:48:54 +0200886 if (b_data(srcbuf) == ofs) {
887 /* Nothing to parse */
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200888 goto end;
Christopher Fauletae660be2022-04-13 17:48:54 +0200889 }
890 if (!max) {
891 /* No more room */
892 goto output_full;
893 }
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200894
895 /* Realing input buffer if necessary */
896 if (b_peek(srcbuf, ofs) > b_tail(srcbuf))
Christopher Faulet00d7cde2021-02-04 11:01:51 +0100897 b_slow_realign_ofs(srcbuf, trash.area, 0);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200898
899 tlr_h1m.flags = (H1_MF_NO_PHDR|H1_MF_HDRS_ONLY);
Willy Tarreau909ddf62024-01-31 15:04:11 +0100900 tlr_h1m.err_pos = h1m->err_pos;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200901 ret = h1_headers_to_hdr_list(b_peek(srcbuf, ofs), b_tail(srcbuf),
902 hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &tlr_h1m, NULL);
903 if (ret <= 0) {
904 /* Incomplete or invalid trailers. If the input buffer only
905 * contains trailers and is full, which is detected by it being
906 * full and the offset to be zero, it's an error because
907 * trailers are too large to be handled by the parser. */
908 if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
909 goto error;
910 goto end;
911 }
912
913 /* messages trailers fully parsed. */
914 if (h1_eval_htx_hdrs_size(hdrs) > max) {
915 if (htx_is_empty(dsthtx))
916 goto error;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200917 goto output_full;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200918 }
919
920 if (!htx_add_all_trailers(dsthtx, hdrs))
921 goto error;
922
Christopher Faulet76014fd2019-12-10 11:47:22 +0100923 h1m->state = H1_MSG_DONE;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100924 dsthtx->flags |= HTX_FL_EOM;
Christopher Faulet76014fd2019-12-10 11:47:22 +0100925
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200926 end:
927 return ret;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200928 output_full:
929 return -2;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200930 error:
931 h1m->err_state = h1m->state;
932 h1m->err_pos = h1m->next;
933 dsthtx->flags |= HTX_FL_PARSING_ERROR;
Christopher Faulet46e058d2021-09-20 07:47:27 +0200934 return -1;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200935}
936
Christopher Faulet53a899b2019-10-08 16:38:42 +0200937/* Appends the H1 representation of the request line <sl> to the chunk <chk>. It
938 * returns 1 if data are successfully appended, otherwise it returns 0.
939 */
940int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk)
941{
942 struct ist uri;
943 size_t sz = chk->data;
944
Christopher Fauletfb38c912021-04-26 09:38:55 +0200945 uri = h1_get_uri(sl);
Christopher Faulet53a899b2019-10-08 16:38:42 +0200946 if (!chunk_memcat(chk, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)) ||
947 !chunk_memcat(chk, " ", 1) ||
948 !chunk_memcat(chk, uri.ptr, uri.len) ||
949 !chunk_memcat(chk, " ", 1))
950 goto full;
951
952 if (sl->flags & HTX_SL_F_VER_11) {
953 if (!chunk_memcat(chk, "HTTP/1.1", 8))
954 goto full;
955 }
956 else {
957 if (!chunk_memcat(chk, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)))
958 goto full;
959 }
960
961 if (!chunk_memcat(chk, "\r\n", 2))
962 goto full;
963
964 return 1;
965
966 full:
967 chk->data = sz;
968 return 0;
969}
970
971/* Appends the H1 representation of the status line <sl> to the chunk <chk>. It
972 * returns 1 if data are successfully appended, otherwise it returns 0.
973 */
974int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk)
975{
976 size_t sz = chk->data;
977
978 if (HTX_SL_LEN(sl) + 4 > b_room(chk))
979 return 0;
980
981 if (sl->flags & HTX_SL_F_VER_11) {
982 if (!chunk_memcat(chk, "HTTP/1.1", 8))
983 goto full;
984 }
985 else {
986 if (!chunk_memcat(chk, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl)))
987 goto full;
988 }
989 if (!chunk_memcat(chk, " ", 1) ||
990 !chunk_memcat(chk, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl)) ||
991 !chunk_memcat(chk, " ", 1) ||
992 !chunk_memcat(chk, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl)) ||
993 !chunk_memcat(chk, "\r\n", 2))
994 goto full;
995
996 return 1;
997
998 full:
999 chk->data = sz;
1000 return 0;
1001}
1002
Ilya Shipitsin47d17182020-06-21 21:42:57 +05001003/* Appends the H1 representation of the header <n> with the value <v> to the
Christopher Faulet53a899b2019-10-08 16:38:42 +02001004 * chunk <chk>. It returns 1 if data are successfully appended, otherwise it
1005 * returns 0.
1006 */
1007int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk)
1008{
1009 size_t sz = chk->data;
1010
1011 if (n.len + v.len + 4 > b_room(chk))
1012 return 0;
1013
1014 if (!chunk_memcat(chk, n.ptr, n.len) ||
1015 !chunk_memcat(chk, ": ", 2) ||
1016 !chunk_memcat(chk, v.ptr, v.len) ||
1017 !chunk_memcat(chk, "\r\n", 2))
1018 goto full;
1019
1020 return 1;
1021
1022 full:
1023 chk->data = sz;
1024 return 0;
1025}
1026
1027/* Appends the H1 representation of the data <data> to the chunk <chk>. If
1028 * <chunked> is non-zero, it emits HTTP/1 chunk-encoded data. It returns 1 if
1029 * data are successfully appended, otherwise it returns 0.
1030 */
1031int h1_format_htx_data(const struct ist data, struct buffer *chk, int chunked)
1032{
1033 size_t sz = chk->data;
1034
1035 if (chunked) {
1036 uint32_t chksz;
1037 char tmp[10];
1038 char *beg, *end;
1039
1040 chksz = data.len;
1041
1042 beg = end = tmp+10;
1043 *--beg = '\n';
1044 *--beg = '\r';
1045 do {
1046 *--beg = hextab[chksz & 0xF];
1047 } while (chksz >>= 4);
1048
1049 if (!chunk_memcat(chk, beg, end - beg) ||
1050 !chunk_memcat(chk, data.ptr, data.len) ||
1051 !chunk_memcat(chk, "\r\n", 2))
1052 goto full;
1053 }
1054 else {
1055 if (!chunk_memcat(chk, data.ptr, data.len))
1056 return 0;
1057 }
1058
1059 return 1;
1060
1061 full:
1062 chk->data = sz;
1063 return 0;
1064}
1065
Christopher Faulet4f0f88a2019-08-10 11:17:44 +02001066/*
1067 * Local variables:
1068 * c-indent-level: 8
1069 * c-basic-offset: 8
1070 * End:
1071 */