blob: 1a1c897323e125bc09a1001f2d54dc6569b0d322 [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>
Willy Tarreau16f958c2020-06-03 08:44:35 +020019#include <haproxy/htx.h>
Willy Tarreau36979d92020-06-05 17:27:29 +020020#include <haproxy/tools.h>
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020021
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020022/* Estimate the size of the HTX headers after the parsing, including the EOH. */
23static size_t h1_eval_htx_hdrs_size(const struct http_hdr *hdrs)
24{
25 size_t sz = 0;
26 int i;
27
28 for (i = 0; hdrs[i].n.len; i++)
29 sz += sizeof(struct htx_blk) + hdrs[i].n.len + hdrs[i].v.len;
30 sz += sizeof(struct htx_blk) + 1;
31 return sz;
32}
33
34/* Estimate the size of the HTX request after the parsing. */
35static size_t h1_eval_htx_size(const struct ist p1, const struct ist p2, const struct ist p3,
36 const struct http_hdr *hdrs)
37{
38 size_t sz;
39
40 /* size of the HTX start-line */
41 sz = sizeof(struct htx_blk) + sizeof(struct htx_sl) + p1.len + p2.len + p3.len;
42 sz += h1_eval_htx_hdrs_size(hdrs);
43 return sz;
44}
45
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020046/* Check the validity of the request version. If the version is valid, it
47 * returns 1. Otherwise, it returns 0.
48 */
49static int h1_process_req_vsn(struct h1m *h1m, union h1_sl *sl)
50{
51 /* RFC7230#2.6 has enforced the format of the HTTP version string to be
52 * exactly one digit "." one digit. This check may be disabled using
53 * option accept-invalid-http-request.
54 */
55 if (h1m->err_pos == -2) { /* PR_O2_REQBUG_OK not set */
56 if (sl->rq.v.len != 8)
57 return 0;
58
59 if (*(sl->rq.v.ptr + 4) != '/' ||
60 !isdigit((unsigned char)*(sl->rq.v.ptr + 5)) ||
61 *(sl->rq.v.ptr + 6) != '.' ||
62 !isdigit((unsigned char)*(sl->rq.v.ptr + 7)))
63 return 0;
64 }
65 else if (!sl->rq.v.len) {
66 /* try to convert HTTP/0.9 requests to HTTP/1.0 */
67
68 /* RFC 1945 allows only GET for HTTP/0.9 requests */
69 if (sl->rq.meth != HTTP_METH_GET)
70 return 0;
71
72 /* HTTP/0.9 requests *must* have a request URI, per RFC 1945 */
73 if (!sl->rq.u.len)
74 return 0;
75
76 /* Add HTTP version */
77 sl->rq.v = ist("HTTP/1.0");
78 return 1;
79 }
80
81 if ((sl->rq.v.len == 8) &&
82 ((*(sl->rq.v.ptr + 5) > '1') ||
83 ((*(sl->rq.v.ptr + 5) == '1') && (*(sl->rq.v.ptr + 7) >= '1'))))
84 h1m->flags |= H1_MF_VER_11;
85 return 1;
86}
87
88/* Check the validity of the response version. If the version is valid, it
89 * returns 1. Otherwise, it returns 0.
90 */
91static int h1_process_res_vsn(struct h1m *h1m, union h1_sl *sl)
92{
93 /* RFC7230#2.6 has enforced the format of the HTTP version string to be
94 * exactly one digit "." one digit. This check may be disabled using
95 * option accept-invalid-http-request.
96 */
97 if (h1m->err_pos == -2) { /* PR_O2_REQBUG_OK not set */
98 if (sl->st.v.len != 8)
99 return 0;
100
101 if (*(sl->st.v.ptr + 4) != '/' ||
102 !isdigit((unsigned char)*(sl->st.v.ptr + 5)) ||
103 *(sl->st.v.ptr + 6) != '.' ||
104 !isdigit((unsigned char)*(sl->st.v.ptr + 7)))
105 return 0;
106 }
107
108 if ((sl->st.v.len == 8) &&
109 ((*(sl->st.v.ptr + 5) > '1') ||
110 ((*(sl->st.v.ptr + 5) == '1') && (*(sl->st.v.ptr + 7) >= '1'))))
111 h1m->flags |= H1_MF_VER_11;
112
113 return 1;
114}
115
116/* Convert H1M flags to HTX start-line flags. */
117static unsigned int h1m_htx_sl_flags(struct h1m *h1m)
118{
119 unsigned int flags = HTX_SL_F_NONE;
120
121 if (h1m->flags & H1_MF_RESP)
122 flags |= HTX_SL_F_IS_RESP;
123 if (h1m->flags & H1_MF_VER_11)
124 flags |= HTX_SL_F_VER_11;
125 if (h1m->flags & H1_MF_XFER_ENC)
126 flags |= HTX_SL_F_XFER_ENC;
127 if (h1m->flags & H1_MF_XFER_LEN) {
128 flags |= HTX_SL_F_XFER_LEN;
129 if (h1m->flags & H1_MF_CHNK)
130 flags |= HTX_SL_F_CHNK;
131 else if (h1m->flags & H1_MF_CLEN) {
132 flags |= HTX_SL_F_CLEN;
133 if (h1m->body_len == 0)
134 flags |= HTX_SL_F_BODYLESS;
135 }
136 else
137 flags |= HTX_SL_F_BODYLESS;
138 }
Christopher Faulet576c3582021-01-08 15:53:01 +0100139 if (h1m->flags & H1_MF_CONN_UPG)
140 flags |= HTX_SL_F_CONN_UPG;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200141 return flags;
142}
143
144/* Postprocess the parsed headers for a request and convert them into an htx
145 * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
146 * proceed. Parsing errors are reported by setting the htx flag
147 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
148 */
149static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
150 struct http_hdr *hdrs, size_t max)
151{
152 struct htx_sl *sl;
153 struct ist meth, uri, vsn;
154 unsigned int flags;
155 size_t used;
156
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;
168 h1m_init_res(h1m);
169 h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
170 return 0;
171 }
172
173 /* By default, request have always a known length */
174 h1m->flags |= H1_MF_XFER_LEN;
175
176 if (h1sl->rq.meth == HTTP_METH_CONNECT) {
Christopher Faulet5be651d2021-01-22 15:28:03 +0100177 h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
178 h1m->curr_len = h1m->body_len = 0;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200179 }
180
181 used = htx_used_space(htx);
182 flags = h1m_htx_sl_flags(h1m);
183 sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth, uri, vsn);
184 if (!sl || !htx_add_all_headers(htx, hdrs))
185 goto error;
186 sl->info.req.meth = h1sl->rq.meth;
187
Christopher Fauletfe451fb2019-10-08 15:01:34 +0200188 /* Check if the uri contains an authority. Also check if it contains an
189 * explicit scheme and if it is "http" or "https". */
190 if (h1sl->rq.meth == HTTP_METH_CONNECT)
191 sl->flags |= HTX_SL_F_HAS_AUTHORITY;
192 else if (uri.len && uri.ptr[0] != '/' && uri.ptr[0] != '*') {
193 sl->flags |= (HTX_SL_F_HAS_AUTHORITY|HTX_SL_F_HAS_SCHM);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200194 if (uri.len > 4 && (uri.ptr[0] | 0x20) == 'h')
195 sl->flags |= ((uri.ptr[4] == ':') ? HTX_SL_F_SCHM_HTTP : HTX_SL_F_SCHM_HTTPS);
196 }
Ilya Shipitsin47d17182020-06-21 21:42:57 +0500197 /* Set bytes used in the HTX message for the headers now */
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200198 sl->hdrs_bytes = htx_used_space(htx) - used;
199
200 /* If body length cannot be determined, set htx->extra to
201 * ULLONG_MAX. This value is impossible in other cases.
202 */
203 htx->extra = ((h1m->flags & H1_MF_XFER_LEN) ? h1m->curr_len : ULLONG_MAX);
204
205 end:
206 return 1;
207 error:
208 h1m->err_pos = h1m->next;
209 h1m->err_state = h1m->state;
210 htx->flags |= HTX_FL_PARSING_ERROR;
211 return 0;
212}
213
214/* Postprocess the parsed headers for a response and convert them into an htx
215 * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
216 * proceed. Parsing errors are reported by setting the htx flag
217 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
218 */
219static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
220 struct http_hdr *hdrs, size_t max)
221{
222 struct htx_sl *sl;
223 struct ist vsn, status, reason;
224 unsigned int flags;
225 size_t used;
226 uint16_t code = 0;
227
228 if (h1sl) {
229 /* For HTTP responses, the start-line was parsed */
230 code = h1sl->st.status;
231 vsn = h1sl->st.v;
232 status = h1sl->st.c;
233 reason = h1sl->st.r;
234 }
235 else {
236 /* For FCGI responses, there is no start(-line but the "Status"
237 * header must be parsed, if found.
238 */
239 int hdr;
240
241 vsn = ((h1m->flags & H1_MF_VER_11) ? ist("HTTP/1.1") : ist("HTTP/1.0"));
242 for (hdr = 0; hdrs[hdr].n.len; hdr++) {
243 if (isteqi(hdrs[hdr].n, ist("status"))) {
244 code = http_parse_status_val(hdrs[hdr].v, &status, &reason);
245 }
246 else if (isteqi(hdrs[hdr].n, ist("location"))) {
247 code = 302;
248 status = ist("302");
249 reason = ist("Moved Temporarily");
250 }
251 }
252 if (!code) {
253 code = 200;
254 status = ist("200");
255 reason = ist("OK");
256 }
257 /* FIXME: Check the codes 1xx ? */
258 }
259
260 /* Be sure the message, once converted into HTX, will not exceed the max
261 * size allowed.
262 */
263 if (h1_eval_htx_size(vsn, status, reason, hdrs) > max) {
264 if (htx_is_empty(htx))
265 goto error;
266 h1m_init_res(h1m);
267 h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
268 return 0;
269 }
270
Christopher Fauletc75668e2020-12-07 18:10:32 +0100271 if (((h1m->flags & H1_MF_METH_CONNECT) && code >= 200 && code < 300) || code == 101) {
Christopher Faulet5be651d2021-01-22 15:28:03 +0100272 h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
273 h1m->flags |= H1_MF_XFER_LEN;
274 h1m->curr_len = h1m->body_len = 0;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200275 }
276 else if ((h1m->flags & H1_MF_METH_HEAD) || (code >= 100 && code < 200) ||
277 (code == 204) || (code == 304)) {
278 /* Responses known to have no body. */
279 h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
280 h1m->flags |= H1_MF_XFER_LEN;
281 h1m->curr_len = h1m->body_len = 0;
282 }
283 else if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
284 /* Responses with a known body length. */
285 h1m->flags |= H1_MF_XFER_LEN;
286 }
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200287
288 used = htx_used_space(htx);
289 flags = h1m_htx_sl_flags(h1m);
290 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, vsn, status, reason);
291 if (!sl || !htx_add_all_headers(htx, hdrs))
292 goto error;
293 sl->info.res.status = code;
294
Ilya Shipitsin47d17182020-06-21 21:42:57 +0500295 /* Set bytes used in the HTX message for the headers now */
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200296 sl->hdrs_bytes = htx_used_space(htx) - used;
297
298 /* If body length cannot be determined, set htx->extra to
299 * ULLONG_MAX. This value is impossible in other cases.
300 */
301 htx->extra = ((h1m->flags & H1_MF_XFER_LEN) ? h1m->curr_len : ULLONG_MAX);
302
303 end:
304 return 1;
305 error:
306 h1m->err_pos = h1m->next;
307 h1m->err_state = h1m->state;
308 htx->flags |= HTX_FL_PARSING_ERROR;
309 return 0;
310}
311
312/* Parse HTTP/1 headers. It returns the number of bytes parsed if > 0, or 0 if
313 * it couldn't proceed. Parsing errors are reported by setting the htx flag
314 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
315 * functions is responsible to update the parser state <h1m> and the start-line
316 * <h1sl> if not NULL.
317 * For the requests, <h1sl> must always be provided. For responses, <h1sl> may
318 * be NULL and <h1m> flags HTTP_METH_CONNECT of HTTP_METH_HEAD may be set.
319 */
320int h1_parse_msg_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *dsthtx,
321 struct buffer *srcbuf, size_t ofs, size_t max)
322{
323 struct http_hdr hdrs[global.tune.max_http_hdr];
324 int ret = 0;
325
326 if (!max || !b_data(srcbuf))
327 goto end;
328
329 /* Realing input buffer if necessary */
330 if (b_head(srcbuf) + b_data(srcbuf) > b_wrap(srcbuf))
331 b_slow_realign(srcbuf, trash.area, 0);
332
333 if (!h1sl) {
334 /* If there no start-line, be sure to only parse the headers */
335 h1m->flags |= H1_MF_HDRS_ONLY;
336 }
337 ret = h1_headers_to_hdr_list(b_peek(srcbuf, ofs), b_tail(srcbuf),
338 hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, h1sl);
339 if (ret <= 0) {
340 /* Incomplete or invalid message. If the input buffer only
341 * contains headers and is full, which is detected by it being
342 * full and the offset to be zero, it's an error because
343 * headers are too large to be handled by the parser. */
344 if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
345 goto error;
346 goto end;
347 }
348
349 /* messages headers fully parsed, do some checks to prepare the body
350 * parsing.
351 */
352
353 if (!(h1m->flags & H1_MF_RESP)) {
354 if (!h1_process_req_vsn(h1m, h1sl)) {
355 h1m->err_pos = h1sl->rq.v.ptr - b_head(srcbuf);
356 h1m->err_state = h1m->state;
357 goto vsn_error;
358 }
359 if (!h1_postparse_req_hdrs(h1m, h1sl, dsthtx, hdrs, max))
360 ret = 0;
361 }
362 else {
363 if (h1sl && !h1_process_res_vsn(h1m, h1sl)) {
364 h1m->err_pos = h1sl->st.v.ptr - b_head(srcbuf);
365 h1m->err_state = h1m->state;
366 goto vsn_error;
367 }
368 if (!h1_postparse_res_hdrs(h1m, h1sl, dsthtx, hdrs, max))
369 ret = 0;
370 }
371
Christopher Faulet76014fd2019-12-10 11:47:22 +0100372 /* Switch messages without any payload to DONE state */
373 if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100374 ((h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN)) {
Christopher Faulet76014fd2019-12-10 11:47:22 +0100375 h1m->state = H1_MSG_DONE;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100376 dsthtx->flags |= HTX_FL_EOM;
377 }
Christopher Faulet76014fd2019-12-10 11:47:22 +0100378
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200379 end:
380 return ret;
381 error:
382 h1m->err_pos = h1m->next;
383 h1m->err_state = h1m->state;
384 vsn_error:
385 dsthtx->flags |= HTX_FL_PARSING_ERROR;
386 return 0;
387
388}
389
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200390/* Copy data from <srbuf> into an DATA block in <dsthtx>. If possible, a
391 * zero-copy is performed. It returns the number of bytes copied.
392 */
Christopher Fauletaf542632019-10-01 21:52:49 +0200393static int h1_copy_msg_data(struct htx **dsthtx, struct buffer *srcbuf, size_t ofs,
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200394 size_t count, struct buffer *htxbuf)
395{
Christopher Fauletaf542632019-10-01 21:52:49 +0200396 struct htx *tmp_htx = *dsthtx;
397
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200398 /* very often with large files we'll face the following
399 * situation :
400 * - htx is empty and points to <htxbuf>
401 * - ret == srcbuf->data
402 * - srcbuf->head == sizeof(struct htx)
403 * => we can swap the buffers and place an htx header into
404 * the target buffer instead
405 */
Christopher Fauletaf542632019-10-01 21:52:49 +0200406 if (unlikely(htx_is_empty(tmp_htx) && count == b_data(srcbuf) &&
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200407 !ofs && b_head_ofs(srcbuf) == sizeof(struct htx))) {
408 void *raw_area = srcbuf->area;
409 void *htx_area = htxbuf->area;
410 struct htx_blk *blk;
411
412 srcbuf->area = htx_area;
413 htxbuf->area = raw_area;
Christopher Fauletaf542632019-10-01 21:52:49 +0200414 tmp_htx = (struct htx *)htxbuf->area;
415 tmp_htx->size = htxbuf->size - sizeof(*tmp_htx);
416 htx_reset(tmp_htx);
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200417 b_set_data(htxbuf, b_size(htxbuf));
418
Christopher Fauletaf542632019-10-01 21:52:49 +0200419 blk = htx_add_blk(tmp_htx, HTX_BLK_DATA, count);
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200420 blk->info += count;
Christopher Fauletaf542632019-10-01 21:52:49 +0200421
422 *dsthtx = tmp_htx;
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200423 /* nothing else to do, the old buffer now contains an
424 * empty pre-initialized HTX header
425 */
426 return count;
427 }
428
Christopher Fauletaf542632019-10-01 21:52:49 +0200429 return htx_add_data(*dsthtx, ist2(b_peek(srcbuf, ofs), count));
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200430}
431
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200432/* Parse HTTP/1 body. It returns the number of bytes parsed if > 0, or 0 if it
433 * couldn't proceed. Parsing errors are reported by setting the htx flags
434 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
435 * functions is responsible to update the parser state <h1m>.
436 */
Christopher Fauletaf542632019-10-01 21:52:49 +0200437int h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200438 struct buffer *srcbuf, size_t ofs, size_t max,
439 struct buffer *htxbuf)
440{
441 size_t total = 0;
442 int32_t ret = 0;
443
444 if (h1m->flags & H1_MF_CLEN) {
445 /* content-length: read only h2m->body_len */
Christopher Fauletaf542632019-10-01 21:52:49 +0200446 ret = htx_get_max_blksz(*dsthtx, max);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200447 if ((uint64_t)ret > h1m->curr_len)
448 ret = h1m->curr_len;
449 if (ret > b_contig_data(srcbuf, ofs))
450 ret = b_contig_data(srcbuf, ofs);
451 if (ret) {
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200452 int32_t try = ret;
453
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200454 ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200455 h1m->curr_len -= ret;
456 max -= sizeof(struct htx_blk) + ret;
457 ofs += ret;
458 total += ret;
459 if (ret < try)
460 goto end;
461 }
462
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100463 if (!h1m->curr_len) {
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200464 h1m->state = H1_MSG_DONE;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100465 (*dsthtx)->flags |= HTX_FL_EOM;
466 }
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200467 }
468 else if (h1m->flags & H1_MF_CHNK) {
469 /* te:chunked : parse chunks */
470 new_chunk:
471 if (h1m->state == H1_MSG_CHUNK_CRLF) {
472 ret = h1_skip_chunk_crlf(srcbuf, ofs, b_data(srcbuf));
473 if (ret <= 0)
474 goto end;
475 h1m->state = H1_MSG_CHUNK_SIZE;
476 ofs += ret;
477 total += ret;
478 }
479 if (h1m->state == H1_MSG_CHUNK_SIZE) {
Christopher Faulet405f0542021-01-27 15:17:13 +0100480 uint64_t chksz;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200481
482 ret = h1_parse_chunk_size(srcbuf, ofs, b_data(srcbuf), &chksz);
483 if (ret <= 0)
484 goto end;
485 h1m->state = ((!chksz) ? H1_MSG_TRAILERS : H1_MSG_DATA);
486 h1m->curr_len = chksz;
487 h1m->body_len += chksz;
488 ofs += ret;
489 total += ret;
490 if (!h1m->curr_len)
491 goto end;
492 }
493 if (h1m->state == H1_MSG_DATA) {
Christopher Fauletaf542632019-10-01 21:52:49 +0200494 ret = htx_get_max_blksz(*dsthtx, max);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200495 if ((uint64_t)ret > h1m->curr_len)
496 ret = h1m->curr_len;
497 if (ret > b_contig_data(srcbuf, ofs))
498 ret = b_contig_data(srcbuf, ofs);
499 if (ret) {
500 int32_t try = ret;
501
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200502 ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200503 h1m->curr_len -= ret;
504 max -= sizeof(struct htx_blk) + ret;
505 ofs += ret;
506 total += ret;
507 if (ret < try)
508 goto end;
509 }
510 if (!h1m->curr_len) {
511 h1m->state = H1_MSG_CHUNK_CRLF;
512 goto new_chunk;
513 }
514 goto end;
515 }
516 }
517 else if (h1m->flags & H1_MF_XFER_LEN) {
518 /* XFER_LEN is set but not CLEN nor CHNK, it means there is no
519 * body. Switch the message in DONE state
520 */
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200521 h1m->state = H1_MSG_DONE;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100522 (*dsthtx)->flags |= HTX_FL_EOM;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200523 }
524 else {
525 /* no content length, read till SHUTW */
Christopher Fauletaf542632019-10-01 21:52:49 +0200526 ret = htx_get_max_blksz(*dsthtx, max);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200527 if (ret > b_contig_data(srcbuf, ofs))
528 ret = b_contig_data(srcbuf, ofs);
529 if (ret)
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200530 total += h1_copy_msg_data(dsthtx, srcbuf, ofs, ret, htxbuf);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200531 }
532
533 end:
534 if (ret < 0) {
Christopher Fauletaf542632019-10-01 21:52:49 +0200535 (*dsthtx)->flags |= HTX_FL_PARSING_ERROR;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200536 h1m->err_state = h1m->state;
537 h1m->err_pos = ofs;
538 total = 0;
539 }
540
541 /* update htx->extra, only when the body length is known */
542 if (h1m->flags & H1_MF_XFER_LEN)
Christopher Fauletaf542632019-10-01 21:52:49 +0200543 (*dsthtx)->extra = h1m->curr_len;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200544 return total;
545}
546
547/* Parse HTTP/1 trailers. It returns the number of bytes parsed if > 0, or 0 if
548 * it couldn't proceed. Parsing errors are reported by setting the htx flags
549 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
550 * functions is responsible to update the parser state <h1m>.
551 */
552int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx,
553 struct buffer *srcbuf, size_t ofs, size_t max)
554{
555 struct http_hdr hdrs[global.tune.max_http_hdr];
556 struct h1m tlr_h1m;
557 int ret = 0;
558
559 if (!max || !b_data(srcbuf))
560 goto end;
561
562 /* Realing input buffer if necessary */
563 if (b_peek(srcbuf, ofs) > b_tail(srcbuf))
564 b_slow_realign(srcbuf, trash.area, 0);
565
566 tlr_h1m.flags = (H1_MF_NO_PHDR|H1_MF_HDRS_ONLY);
567 ret = h1_headers_to_hdr_list(b_peek(srcbuf, ofs), b_tail(srcbuf),
568 hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &tlr_h1m, NULL);
569 if (ret <= 0) {
570 /* Incomplete or invalid trailers. If the input buffer only
571 * contains trailers and is full, which is detected by it being
572 * full and the offset to be zero, it's an error because
573 * trailers are too large to be handled by the parser. */
574 if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
575 goto error;
576 goto end;
577 }
578
579 /* messages trailers fully parsed. */
580 if (h1_eval_htx_hdrs_size(hdrs) > max) {
581 if (htx_is_empty(dsthtx))
582 goto error;
583 ret = 0;
584 goto end;
585 }
586
587 if (!htx_add_all_trailers(dsthtx, hdrs))
588 goto error;
589
Christopher Faulet76014fd2019-12-10 11:47:22 +0100590 h1m->state = H1_MSG_DONE;
Christopher Fauletd1ac2b92020-12-02 19:12:22 +0100591 dsthtx->flags |= HTX_FL_EOM;
Christopher Faulet76014fd2019-12-10 11:47:22 +0100592
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200593 end:
594 return ret;
595 error:
596 h1m->err_state = h1m->state;
597 h1m->err_pos = h1m->next;
598 dsthtx->flags |= HTX_FL_PARSING_ERROR;
599 return 0;
600}
601
Christopher Faulet53a899b2019-10-08 16:38:42 +0200602/* Appends the H1 representation of the request line <sl> to the chunk <chk>. It
603 * returns 1 if data are successfully appended, otherwise it returns 0.
604 */
605int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk)
606{
607 struct ist uri;
608 size_t sz = chk->data;
609
610 uri = htx_sl_req_uri(sl);
611 if (sl->flags & HTX_SL_F_NORMALIZED_URI) {
612 uri = http_get_path(uri);
613 if (unlikely(!uri.len)) {
614 if (sl->info.req.meth == HTTP_METH_OPTIONS)
615 uri = ist("*");
616 else
617 uri = ist("/");
618 }
619 }
620
621 if (!chunk_memcat(chk, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)) ||
622 !chunk_memcat(chk, " ", 1) ||
623 !chunk_memcat(chk, uri.ptr, uri.len) ||
624 !chunk_memcat(chk, " ", 1))
625 goto full;
626
627 if (sl->flags & HTX_SL_F_VER_11) {
628 if (!chunk_memcat(chk, "HTTP/1.1", 8))
629 goto full;
630 }
631 else {
632 if (!chunk_memcat(chk, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)))
633 goto full;
634 }
635
636 if (!chunk_memcat(chk, "\r\n", 2))
637 goto full;
638
639 return 1;
640
641 full:
642 chk->data = sz;
643 return 0;
644}
645
646/* Appends the H1 representation of the status line <sl> to the chunk <chk>. It
647 * returns 1 if data are successfully appended, otherwise it returns 0.
648 */
649int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk)
650{
651 size_t sz = chk->data;
652
653 if (HTX_SL_LEN(sl) + 4 > b_room(chk))
654 return 0;
655
656 if (sl->flags & HTX_SL_F_VER_11) {
657 if (!chunk_memcat(chk, "HTTP/1.1", 8))
658 goto full;
659 }
660 else {
661 if (!chunk_memcat(chk, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl)))
662 goto full;
663 }
664 if (!chunk_memcat(chk, " ", 1) ||
665 !chunk_memcat(chk, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl)) ||
666 !chunk_memcat(chk, " ", 1) ||
667 !chunk_memcat(chk, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl)) ||
668 !chunk_memcat(chk, "\r\n", 2))
669 goto full;
670
671 return 1;
672
673 full:
674 chk->data = sz;
675 return 0;
676}
677
Ilya Shipitsin47d17182020-06-21 21:42:57 +0500678/* Appends the H1 representation of the header <n> with the value <v> to the
Christopher Faulet53a899b2019-10-08 16:38:42 +0200679 * chunk <chk>. It returns 1 if data are successfully appended, otherwise it
680 * returns 0.
681 */
682int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk)
683{
684 size_t sz = chk->data;
685
686 if (n.len + v.len + 4 > b_room(chk))
687 return 0;
688
689 if (!chunk_memcat(chk, n.ptr, n.len) ||
690 !chunk_memcat(chk, ": ", 2) ||
691 !chunk_memcat(chk, v.ptr, v.len) ||
692 !chunk_memcat(chk, "\r\n", 2))
693 goto full;
694
695 return 1;
696
697 full:
698 chk->data = sz;
699 return 0;
700}
701
702/* Appends the H1 representation of the data <data> to the chunk <chk>. If
703 * <chunked> is non-zero, it emits HTTP/1 chunk-encoded data. It returns 1 if
704 * data are successfully appended, otherwise it returns 0.
705 */
706int h1_format_htx_data(const struct ist data, struct buffer *chk, int chunked)
707{
708 size_t sz = chk->data;
709
710 if (chunked) {
711 uint32_t chksz;
712 char tmp[10];
713 char *beg, *end;
714
715 chksz = data.len;
716
717 beg = end = tmp+10;
718 *--beg = '\n';
719 *--beg = '\r';
720 do {
721 *--beg = hextab[chksz & 0xF];
722 } while (chksz >>= 4);
723
724 if (!chunk_memcat(chk, beg, end - beg) ||
725 !chunk_memcat(chk, data.ptr, data.len) ||
726 !chunk_memcat(chk, "\r\n", 2))
727 goto full;
728 }
729 else {
730 if (!chunk_memcat(chk, data.ptr, data.len))
731 return 0;
732 }
733
734 return 1;
735
736 full:
737 chk->data = sz;
738 return 0;
739}
740
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200741/*
742 * Local variables:
743 * c-indent-level: 8
744 * c-basic-offset: 8
745 * End:
746 */