blob: b27ddca81b7d28574a3294048949fd317fd93749 [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>
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020014#include <common/cfgparse.h>
Willy Tarreau5413a872020-06-02 19:33:08 +020015#include <haproxy/h1.h>
Willy Tarreauc6fe8842020-06-04 09:00:02 +020016#include <haproxy/h1_htx.h>
Willy Tarreaucd72d8c2020-06-02 19:11:26 +020017#include <haproxy/http.h>
Willy Tarreau16f958c2020-06-03 08:44:35 +020018#include <haproxy/htx.h>
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020019
Christopher Faulet4f0f88a2019-08-10 11:17:44 +020020/* Estimate the size of the HTX headers after the parsing, including the EOH. */
21static size_t h1_eval_htx_hdrs_size(const struct http_hdr *hdrs)
22{
23 size_t sz = 0;
24 int i;
25
26 for (i = 0; hdrs[i].n.len; i++)
27 sz += sizeof(struct htx_blk) + hdrs[i].n.len + hdrs[i].v.len;
28 sz += sizeof(struct htx_blk) + 1;
29 return sz;
30}
31
32/* Estimate the size of the HTX request after the parsing. */
33static size_t h1_eval_htx_size(const struct ist p1, const struct ist p2, const struct ist p3,
34 const struct http_hdr *hdrs)
35{
36 size_t sz;
37
38 /* size of the HTX start-line */
39 sz = sizeof(struct htx_blk) + sizeof(struct htx_sl) + p1.len + p2.len + p3.len;
40 sz += h1_eval_htx_hdrs_size(hdrs);
41 return sz;
42}
43
44/* Switch the message to tunnel mode. On the request, it must only be called for
45 * a CONNECT method. On the response, this function must only be called on
46 * successfull replies to CONNECT requests or on protocol switching.
47 */
48static void h1_set_tunnel_mode(struct h1m *h1m)
49{
50 h1m->flags &= ~(H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK);
51 h1m->state = H1_MSG_TUNNEL;
52}
53
54/* Check the validity of the request version. If the version is valid, it
55 * returns 1. Otherwise, it returns 0.
56 */
57static int h1_process_req_vsn(struct h1m *h1m, union h1_sl *sl)
58{
59 /* RFC7230#2.6 has enforced the format of the HTTP version string to be
60 * exactly one digit "." one digit. This check may be disabled using
61 * option accept-invalid-http-request.
62 */
63 if (h1m->err_pos == -2) { /* PR_O2_REQBUG_OK not set */
64 if (sl->rq.v.len != 8)
65 return 0;
66
67 if (*(sl->rq.v.ptr + 4) != '/' ||
68 !isdigit((unsigned char)*(sl->rq.v.ptr + 5)) ||
69 *(sl->rq.v.ptr + 6) != '.' ||
70 !isdigit((unsigned char)*(sl->rq.v.ptr + 7)))
71 return 0;
72 }
73 else if (!sl->rq.v.len) {
74 /* try to convert HTTP/0.9 requests to HTTP/1.0 */
75
76 /* RFC 1945 allows only GET for HTTP/0.9 requests */
77 if (sl->rq.meth != HTTP_METH_GET)
78 return 0;
79
80 /* HTTP/0.9 requests *must* have a request URI, per RFC 1945 */
81 if (!sl->rq.u.len)
82 return 0;
83
84 /* Add HTTP version */
85 sl->rq.v = ist("HTTP/1.0");
86 return 1;
87 }
88
89 if ((sl->rq.v.len == 8) &&
90 ((*(sl->rq.v.ptr + 5) > '1') ||
91 ((*(sl->rq.v.ptr + 5) == '1') && (*(sl->rq.v.ptr + 7) >= '1'))))
92 h1m->flags |= H1_MF_VER_11;
93 return 1;
94}
95
96/* Check the validity of the response version. If the version is valid, it
97 * returns 1. Otherwise, it returns 0.
98 */
99static int h1_process_res_vsn(struct h1m *h1m, union h1_sl *sl)
100{
101 /* RFC7230#2.6 has enforced the format of the HTTP version string to be
102 * exactly one digit "." one digit. This check may be disabled using
103 * option accept-invalid-http-request.
104 */
105 if (h1m->err_pos == -2) { /* PR_O2_REQBUG_OK not set */
106 if (sl->st.v.len != 8)
107 return 0;
108
109 if (*(sl->st.v.ptr + 4) != '/' ||
110 !isdigit((unsigned char)*(sl->st.v.ptr + 5)) ||
111 *(sl->st.v.ptr + 6) != '.' ||
112 !isdigit((unsigned char)*(sl->st.v.ptr + 7)))
113 return 0;
114 }
115
116 if ((sl->st.v.len == 8) &&
117 ((*(sl->st.v.ptr + 5) > '1') ||
118 ((*(sl->st.v.ptr + 5) == '1') && (*(sl->st.v.ptr + 7) >= '1'))))
119 h1m->flags |= H1_MF_VER_11;
120
121 return 1;
122}
123
124/* Convert H1M flags to HTX start-line flags. */
125static unsigned int h1m_htx_sl_flags(struct h1m *h1m)
126{
127 unsigned int flags = HTX_SL_F_NONE;
128
129 if (h1m->flags & H1_MF_RESP)
130 flags |= HTX_SL_F_IS_RESP;
131 if (h1m->flags & H1_MF_VER_11)
132 flags |= HTX_SL_F_VER_11;
133 if (h1m->flags & H1_MF_XFER_ENC)
134 flags |= HTX_SL_F_XFER_ENC;
135 if (h1m->flags & H1_MF_XFER_LEN) {
136 flags |= HTX_SL_F_XFER_LEN;
137 if (h1m->flags & H1_MF_CHNK)
138 flags |= HTX_SL_F_CHNK;
139 else if (h1m->flags & H1_MF_CLEN) {
140 flags |= HTX_SL_F_CLEN;
141 if (h1m->body_len == 0)
142 flags |= HTX_SL_F_BODYLESS;
143 }
144 else
145 flags |= HTX_SL_F_BODYLESS;
146 }
147 return flags;
148}
149
150/* Postprocess the parsed headers for a request and convert them into an htx
151 * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
152 * proceed. Parsing errors are reported by setting the htx flag
153 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
154 */
155static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
156 struct http_hdr *hdrs, size_t max)
157{
158 struct htx_sl *sl;
159 struct ist meth, uri, vsn;
160 unsigned int flags;
161 size_t used;
162
163 /* <h1sl> is always defined for a request */
164 meth = h1sl->rq.m;
165 uri = h1sl->rq.u;
166 vsn = h1sl->rq.v;
167
168 /* Be sure the message, once converted into HTX, will not exceed the max
169 * size allowed.
170 */
171 if (h1_eval_htx_size(meth, uri, vsn, hdrs) > max) {
172 if (htx_is_empty(htx))
173 goto error;
174 h1m_init_res(h1m);
175 h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
176 return 0;
177 }
178
179 /* By default, request have always a known length */
180 h1m->flags |= H1_MF_XFER_LEN;
181
182 if (h1sl->rq.meth == HTTP_METH_CONNECT) {
183 /* Switch CONNECT requests to tunnel mode */
184 h1_set_tunnel_mode(h1m);
185 }
186
187 used = htx_used_space(htx);
188 flags = h1m_htx_sl_flags(h1m);
189 sl = htx_add_stline(htx, HTX_BLK_REQ_SL, flags, meth, uri, vsn);
190 if (!sl || !htx_add_all_headers(htx, hdrs))
191 goto error;
192 sl->info.req.meth = h1sl->rq.meth;
193
Christopher Fauletfe451fb2019-10-08 15:01:34 +0200194 /* Check if the uri contains an authority. Also check if it contains an
195 * explicit scheme and if it is "http" or "https". */
196 if (h1sl->rq.meth == HTTP_METH_CONNECT)
197 sl->flags |= HTX_SL_F_HAS_AUTHORITY;
198 else if (uri.len && uri.ptr[0] != '/' && uri.ptr[0] != '*') {
199 sl->flags |= (HTX_SL_F_HAS_AUTHORITY|HTX_SL_F_HAS_SCHM);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200200 if (uri.len > 4 && (uri.ptr[0] | 0x20) == 'h')
201 sl->flags |= ((uri.ptr[4] == ':') ? HTX_SL_F_SCHM_HTTP : HTX_SL_F_SCHM_HTTPS);
202 }
203 /* Set bytes used in the HTX mesage for the headers now */
204 sl->hdrs_bytes = htx_used_space(htx) - used;
205
206 /* If body length cannot be determined, set htx->extra to
207 * ULLONG_MAX. This value is impossible in other cases.
208 */
209 htx->extra = ((h1m->flags & H1_MF_XFER_LEN) ? h1m->curr_len : ULLONG_MAX);
210
211 end:
212 return 1;
213 error:
214 h1m->err_pos = h1m->next;
215 h1m->err_state = h1m->state;
216 htx->flags |= HTX_FL_PARSING_ERROR;
217 return 0;
218}
219
220/* Postprocess the parsed headers for a response and convert them into an htx
221 * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
222 * proceed. Parsing errors are reported by setting the htx flag
223 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
224 */
225static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
226 struct http_hdr *hdrs, size_t max)
227{
228 struct htx_sl *sl;
229 struct ist vsn, status, reason;
230 unsigned int flags;
231 size_t used;
232 uint16_t code = 0;
233
234 if (h1sl) {
235 /* For HTTP responses, the start-line was parsed */
236 code = h1sl->st.status;
237 vsn = h1sl->st.v;
238 status = h1sl->st.c;
239 reason = h1sl->st.r;
240 }
241 else {
242 /* For FCGI responses, there is no start(-line but the "Status"
243 * header must be parsed, if found.
244 */
245 int hdr;
246
247 vsn = ((h1m->flags & H1_MF_VER_11) ? ist("HTTP/1.1") : ist("HTTP/1.0"));
248 for (hdr = 0; hdrs[hdr].n.len; hdr++) {
249 if (isteqi(hdrs[hdr].n, ist("status"))) {
250 code = http_parse_status_val(hdrs[hdr].v, &status, &reason);
251 }
252 else if (isteqi(hdrs[hdr].n, ist("location"))) {
253 code = 302;
254 status = ist("302");
255 reason = ist("Moved Temporarily");
256 }
257 }
258 if (!code) {
259 code = 200;
260 status = ist("200");
261 reason = ist("OK");
262 }
263 /* FIXME: Check the codes 1xx ? */
264 }
265
266 /* Be sure the message, once converted into HTX, will not exceed the max
267 * size allowed.
268 */
269 if (h1_eval_htx_size(vsn, status, reason, hdrs) > max) {
270 if (htx_is_empty(htx))
271 goto error;
272 h1m_init_res(h1m);
273 h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
274 return 0;
275 }
276
277 if (((h1m->flags & H1_MF_METH_CONNECT) && code == 200) || code == 101) {
278 /* Switch successfull replies to CONNECT requests and
279 * protocol switching to tunnel mode. */
280 h1_set_tunnel_mode(h1m);
281 }
282 else if ((h1m->flags & H1_MF_METH_HEAD) || (code >= 100 && code < 200) ||
283 (code == 204) || (code == 304)) {
284 /* Responses known to have no body. */
285 h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
286 h1m->flags |= H1_MF_XFER_LEN;
287 h1m->curr_len = h1m->body_len = 0;
288 }
289 else if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
290 /* Responses with a known body length. */
291 h1m->flags |= H1_MF_XFER_LEN;
292 }
293 else {
294 /* Responses with an unknown body length */
295 h1m->state = H1_MSG_TUNNEL;
296 }
297
298 used = htx_used_space(htx);
299 flags = h1m_htx_sl_flags(h1m);
300 sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags, vsn, status, reason);
301 if (!sl || !htx_add_all_headers(htx, hdrs))
302 goto error;
303 sl->info.res.status = code;
304
305 /* Set bytes used in the HTX mesage for the headers now */
306 sl->hdrs_bytes = htx_used_space(htx) - used;
307
308 /* If body length cannot be determined, set htx->extra to
309 * ULLONG_MAX. This value is impossible in other cases.
310 */
311 htx->extra = ((h1m->flags & H1_MF_XFER_LEN) ? h1m->curr_len : ULLONG_MAX);
312
313 end:
314 return 1;
315 error:
316 h1m->err_pos = h1m->next;
317 h1m->err_state = h1m->state;
318 htx->flags |= HTX_FL_PARSING_ERROR;
319 return 0;
320}
321
322/* Parse HTTP/1 headers. It returns the number of bytes parsed if > 0, or 0 if
323 * it couldn't proceed. Parsing errors are reported by setting the htx flag
324 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
325 * functions is responsible to update the parser state <h1m> and the start-line
326 * <h1sl> if not NULL.
327 * For the requests, <h1sl> must always be provided. For responses, <h1sl> may
328 * be NULL and <h1m> flags HTTP_METH_CONNECT of HTTP_METH_HEAD may be set.
329 */
330int h1_parse_msg_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *dsthtx,
331 struct buffer *srcbuf, size_t ofs, size_t max)
332{
333 struct http_hdr hdrs[global.tune.max_http_hdr];
334 int ret = 0;
335
336 if (!max || !b_data(srcbuf))
337 goto end;
338
339 /* Realing input buffer if necessary */
340 if (b_head(srcbuf) + b_data(srcbuf) > b_wrap(srcbuf))
341 b_slow_realign(srcbuf, trash.area, 0);
342
343 if (!h1sl) {
344 /* If there no start-line, be sure to only parse the headers */
345 h1m->flags |= H1_MF_HDRS_ONLY;
346 }
347 ret = h1_headers_to_hdr_list(b_peek(srcbuf, ofs), b_tail(srcbuf),
348 hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, h1sl);
349 if (ret <= 0) {
350 /* Incomplete or invalid message. If the input buffer only
351 * contains headers and is full, which is detected by it being
352 * full and the offset to be zero, it's an error because
353 * headers are too large to be handled by the parser. */
354 if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
355 goto error;
356 goto end;
357 }
358
359 /* messages headers fully parsed, do some checks to prepare the body
360 * parsing.
361 */
362
363 if (!(h1m->flags & H1_MF_RESP)) {
364 if (!h1_process_req_vsn(h1m, h1sl)) {
365 h1m->err_pos = h1sl->rq.v.ptr - b_head(srcbuf);
366 h1m->err_state = h1m->state;
367 goto vsn_error;
368 }
369 if (!h1_postparse_req_hdrs(h1m, h1sl, dsthtx, hdrs, max))
370 ret = 0;
371 }
372 else {
373 if (h1sl && !h1_process_res_vsn(h1m, h1sl)) {
374 h1m->err_pos = h1sl->st.v.ptr - b_head(srcbuf);
375 h1m->err_state = h1m->state;
376 goto vsn_error;
377 }
378 if (!h1_postparse_res_hdrs(h1m, h1sl, dsthtx, hdrs, max))
379 ret = 0;
380 }
381
Christopher Faulet76014fd2019-12-10 11:47:22 +0100382 /* Switch messages without any payload to DONE state */
383 if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
384 ((h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN))
385 h1m->state = H1_MSG_DONE;
386
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200387 end:
388 return ret;
389 error:
390 h1m->err_pos = h1m->next;
391 h1m->err_state = h1m->state;
392 vsn_error:
393 dsthtx->flags |= HTX_FL_PARSING_ERROR;
394 return 0;
395
396}
397
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200398/* Copy data from <srbuf> into an DATA block in <dsthtx>. If possible, a
399 * zero-copy is performed. It returns the number of bytes copied.
400 */
Christopher Fauletaf542632019-10-01 21:52:49 +0200401static int h1_copy_msg_data(struct htx **dsthtx, struct buffer *srcbuf, size_t ofs,
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200402 size_t count, struct buffer *htxbuf)
403{
Christopher Fauletaf542632019-10-01 21:52:49 +0200404 struct htx *tmp_htx = *dsthtx;
405
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200406 /* very often with large files we'll face the following
407 * situation :
408 * - htx is empty and points to <htxbuf>
409 * - ret == srcbuf->data
410 * - srcbuf->head == sizeof(struct htx)
411 * => we can swap the buffers and place an htx header into
412 * the target buffer instead
413 */
Christopher Fauletaf542632019-10-01 21:52:49 +0200414 if (unlikely(htx_is_empty(tmp_htx) && count == b_data(srcbuf) &&
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200415 !ofs && b_head_ofs(srcbuf) == sizeof(struct htx))) {
416 void *raw_area = srcbuf->area;
417 void *htx_area = htxbuf->area;
418 struct htx_blk *blk;
419
420 srcbuf->area = htx_area;
421 htxbuf->area = raw_area;
Christopher Fauletaf542632019-10-01 21:52:49 +0200422 tmp_htx = (struct htx *)htxbuf->area;
423 tmp_htx->size = htxbuf->size - sizeof(*tmp_htx);
424 htx_reset(tmp_htx);
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200425 b_set_data(htxbuf, b_size(htxbuf));
426
Christopher Fauletaf542632019-10-01 21:52:49 +0200427 blk = htx_add_blk(tmp_htx, HTX_BLK_DATA, count);
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200428 blk->info += count;
Christopher Fauletaf542632019-10-01 21:52:49 +0200429
430 *dsthtx = tmp_htx;
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200431 /* nothing else to do, the old buffer now contains an
432 * empty pre-initialized HTX header
433 */
434 return count;
435 }
436
Christopher Fauletaf542632019-10-01 21:52:49 +0200437 return htx_add_data(*dsthtx, ist2(b_peek(srcbuf, ofs), count));
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200438}
439
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200440/* Parse HTTP/1 body. It returns the number of bytes parsed if > 0, or 0 if it
441 * couldn't proceed. Parsing errors are reported by setting the htx flags
442 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
443 * functions is responsible to update the parser state <h1m>.
444 */
Christopher Fauletaf542632019-10-01 21:52:49 +0200445int h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200446 struct buffer *srcbuf, size_t ofs, size_t max,
447 struct buffer *htxbuf)
448{
449 size_t total = 0;
450 int32_t ret = 0;
451
452 if (h1m->flags & H1_MF_CLEN) {
453 /* content-length: read only h2m->body_len */
Christopher Fauletaf542632019-10-01 21:52:49 +0200454 ret = htx_get_max_blksz(*dsthtx, max);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200455 if ((uint64_t)ret > h1m->curr_len)
456 ret = h1m->curr_len;
457 if (ret > b_contig_data(srcbuf, ofs))
458 ret = b_contig_data(srcbuf, ofs);
459 if (ret) {
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200460 int32_t try = ret;
461
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200462 ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200463 h1m->curr_len -= ret;
464 max -= sizeof(struct htx_blk) + ret;
465 ofs += ret;
466 total += ret;
467 if (ret < try)
468 goto end;
469 }
470
Christopher Faulet76014fd2019-12-10 11:47:22 +0100471 if (!h1m->curr_len)
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200472 h1m->state = H1_MSG_DONE;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200473 }
474 else if (h1m->flags & H1_MF_CHNK) {
475 /* te:chunked : parse chunks */
476 new_chunk:
477 if (h1m->state == H1_MSG_CHUNK_CRLF) {
478 ret = h1_skip_chunk_crlf(srcbuf, ofs, b_data(srcbuf));
479 if (ret <= 0)
480 goto end;
481 h1m->state = H1_MSG_CHUNK_SIZE;
482 ofs += ret;
483 total += ret;
484 }
485 if (h1m->state == H1_MSG_CHUNK_SIZE) {
486 unsigned int chksz;
487
488 ret = h1_parse_chunk_size(srcbuf, ofs, b_data(srcbuf), &chksz);
489 if (ret <= 0)
490 goto end;
491 h1m->state = ((!chksz) ? H1_MSG_TRAILERS : H1_MSG_DATA);
492 h1m->curr_len = chksz;
493 h1m->body_len += chksz;
494 ofs += ret;
495 total += ret;
496 if (!h1m->curr_len)
497 goto end;
498 }
499 if (h1m->state == H1_MSG_DATA) {
Christopher Fauletaf542632019-10-01 21:52:49 +0200500 ret = htx_get_max_blksz(*dsthtx, max);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200501 if ((uint64_t)ret > h1m->curr_len)
502 ret = h1m->curr_len;
503 if (ret > b_contig_data(srcbuf, ofs))
504 ret = b_contig_data(srcbuf, ofs);
505 if (ret) {
506 int32_t try = ret;
507
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200508 ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200509 h1m->curr_len -= ret;
510 max -= sizeof(struct htx_blk) + ret;
511 ofs += ret;
512 total += ret;
513 if (ret < try)
514 goto end;
515 }
516 if (!h1m->curr_len) {
517 h1m->state = H1_MSG_CHUNK_CRLF;
518 goto new_chunk;
519 }
520 goto end;
521 }
522 }
523 else if (h1m->flags & H1_MF_XFER_LEN) {
524 /* XFER_LEN is set but not CLEN nor CHNK, it means there is no
525 * body. Switch the message in DONE state
526 */
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200527 h1m->state = H1_MSG_DONE;
528 }
529 else {
530 /* no content length, read till SHUTW */
Christopher Fauletaf542632019-10-01 21:52:49 +0200531 ret = htx_get_max_blksz(*dsthtx, max);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200532 if (ret > b_contig_data(srcbuf, ofs))
533 ret = b_contig_data(srcbuf, ofs);
534 if (ret)
Christopher Fauletcc3124c2019-08-12 22:42:21 +0200535 total += h1_copy_msg_data(dsthtx, srcbuf, ofs, ret, htxbuf);
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200536 }
537
538 end:
539 if (ret < 0) {
Christopher Fauletaf542632019-10-01 21:52:49 +0200540 (*dsthtx)->flags |= HTX_FL_PARSING_ERROR;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200541 h1m->err_state = h1m->state;
542 h1m->err_pos = ofs;
543 total = 0;
544 }
545
546 /* update htx->extra, only when the body length is known */
547 if (h1m->flags & H1_MF_XFER_LEN)
Christopher Fauletaf542632019-10-01 21:52:49 +0200548 (*dsthtx)->extra = h1m->curr_len;
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200549 return total;
550}
551
552/* Parse HTTP/1 trailers. It returns the number of bytes parsed if > 0, or 0 if
553 * it couldn't proceed. Parsing errors are reported by setting the htx flags
554 * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
555 * functions is responsible to update the parser state <h1m>.
556 */
557int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx,
558 struct buffer *srcbuf, size_t ofs, size_t max)
559{
560 struct http_hdr hdrs[global.tune.max_http_hdr];
561 struct h1m tlr_h1m;
562 int ret = 0;
563
564 if (!max || !b_data(srcbuf))
565 goto end;
566
567 /* Realing input buffer if necessary */
568 if (b_peek(srcbuf, ofs) > b_tail(srcbuf))
569 b_slow_realign(srcbuf, trash.area, 0);
570
571 tlr_h1m.flags = (H1_MF_NO_PHDR|H1_MF_HDRS_ONLY);
572 ret = h1_headers_to_hdr_list(b_peek(srcbuf, ofs), b_tail(srcbuf),
573 hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &tlr_h1m, NULL);
574 if (ret <= 0) {
575 /* Incomplete or invalid trailers. If the input buffer only
576 * contains trailers and is full, which is detected by it being
577 * full and the offset to be zero, it's an error because
578 * trailers are too large to be handled by the parser. */
579 if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
580 goto error;
581 goto end;
582 }
583
584 /* messages trailers fully parsed. */
585 if (h1_eval_htx_hdrs_size(hdrs) > max) {
586 if (htx_is_empty(dsthtx))
587 goto error;
588 ret = 0;
589 goto end;
590 }
591
592 if (!htx_add_all_trailers(dsthtx, hdrs))
593 goto error;
594
Christopher Faulet76014fd2019-12-10 11:47:22 +0100595 h1m->state = H1_MSG_DONE;
596
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200597 end:
598 return ret;
599 error:
600 h1m->err_state = h1m->state;
601 h1m->err_pos = h1m->next;
602 dsthtx->flags |= HTX_FL_PARSING_ERROR;
603 return 0;
604}
605
Christopher Faulet76014fd2019-12-10 11:47:22 +0100606/* Finish HTTP/1 parsing by adding the HTX EOM block. It returns 1 on success or
607 * 0 if it couldn't proceed. There is no parsing at this stage, but a parsing
608 * error is reported if the message state is not H1_MSG_DONE. */
609int h1_parse_msg_eom(struct h1m *h1m, struct htx *dsthtx, size_t max)
610{
611 if (h1m->state != H1_MSG_DONE) {
612 h1m->err_state = h1m->state;
613 h1m->err_pos = h1m->next;
614 dsthtx->flags |= HTX_FL_PARSING_ERROR;
615 return 0;
616 }
617 if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(dsthtx, HTX_BLK_EOM))
618 return 0;
619
620 return 1;
621}
622
Christopher Faulet53a899b2019-10-08 16:38:42 +0200623
624/* Appends the H1 representation of the request line <sl> to the chunk <chk>. It
625 * returns 1 if data are successfully appended, otherwise it returns 0.
626 */
627int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk)
628{
629 struct ist uri;
630 size_t sz = chk->data;
631
632 uri = htx_sl_req_uri(sl);
633 if (sl->flags & HTX_SL_F_NORMALIZED_URI) {
634 uri = http_get_path(uri);
635 if (unlikely(!uri.len)) {
636 if (sl->info.req.meth == HTTP_METH_OPTIONS)
637 uri = ist("*");
638 else
639 uri = ist("/");
640 }
641 }
642
643 if (!chunk_memcat(chk, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)) ||
644 !chunk_memcat(chk, " ", 1) ||
645 !chunk_memcat(chk, uri.ptr, uri.len) ||
646 !chunk_memcat(chk, " ", 1))
647 goto full;
648
649 if (sl->flags & HTX_SL_F_VER_11) {
650 if (!chunk_memcat(chk, "HTTP/1.1", 8))
651 goto full;
652 }
653 else {
654 if (!chunk_memcat(chk, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)))
655 goto full;
656 }
657
658 if (!chunk_memcat(chk, "\r\n", 2))
659 goto full;
660
661 return 1;
662
663 full:
664 chk->data = sz;
665 return 0;
666}
667
668/* Appends the H1 representation of the status line <sl> to the chunk <chk>. It
669 * returns 1 if data are successfully appended, otherwise it returns 0.
670 */
671int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk)
672{
673 size_t sz = chk->data;
674
675 if (HTX_SL_LEN(sl) + 4 > b_room(chk))
676 return 0;
677
678 if (sl->flags & HTX_SL_F_VER_11) {
679 if (!chunk_memcat(chk, "HTTP/1.1", 8))
680 goto full;
681 }
682 else {
683 if (!chunk_memcat(chk, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl)))
684 goto full;
685 }
686 if (!chunk_memcat(chk, " ", 1) ||
687 !chunk_memcat(chk, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl)) ||
688 !chunk_memcat(chk, " ", 1) ||
689 !chunk_memcat(chk, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl)) ||
690 !chunk_memcat(chk, "\r\n", 2))
691 goto full;
692
693 return 1;
694
695 full:
696 chk->data = sz;
697 return 0;
698}
699
700/* Appends the H1 representation of the header <n> witht the value <v> to the
701 * chunk <chk>. It returns 1 if data are successfully appended, otherwise it
702 * returns 0.
703 */
704int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk)
705{
706 size_t sz = chk->data;
707
708 if (n.len + v.len + 4 > b_room(chk))
709 return 0;
710
711 if (!chunk_memcat(chk, n.ptr, n.len) ||
712 !chunk_memcat(chk, ": ", 2) ||
713 !chunk_memcat(chk, v.ptr, v.len) ||
714 !chunk_memcat(chk, "\r\n", 2))
715 goto full;
716
717 return 1;
718
719 full:
720 chk->data = sz;
721 return 0;
722}
723
724/* Appends the H1 representation of the data <data> to the chunk <chk>. If
725 * <chunked> is non-zero, it emits HTTP/1 chunk-encoded data. It returns 1 if
726 * data are successfully appended, otherwise it returns 0.
727 */
728int h1_format_htx_data(const struct ist data, struct buffer *chk, int chunked)
729{
730 size_t sz = chk->data;
731
732 if (chunked) {
733 uint32_t chksz;
734 char tmp[10];
735 char *beg, *end;
736
737 chksz = data.len;
738
739 beg = end = tmp+10;
740 *--beg = '\n';
741 *--beg = '\r';
742 do {
743 *--beg = hextab[chksz & 0xF];
744 } while (chksz >>= 4);
745
746 if (!chunk_memcat(chk, beg, end - beg) ||
747 !chunk_memcat(chk, data.ptr, data.len) ||
748 !chunk_memcat(chk, "\r\n", 2))
749 goto full;
750 }
751 else {
752 if (!chunk_memcat(chk, data.ptr, data.len))
753 return 0;
754 }
755
756 return 1;
757
758 full:
759 chk->data = sz;
760 return 0;
761}
762
Christopher Faulet4f0f88a2019-08-10 11:17:44 +0200763/*
764 * Local variables:
765 * c-indent-level: 8
766 * c-basic-offset: 8
767 * End:
768 */