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