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