1 /*
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 <haproxy/api.h>
14 #include <haproxy/cfgparse.h>
15 #include <haproxy/global.h>
16 #include <haproxy/h1.h>
17 #include <haproxy/h1_htx.h>
18 #include <haproxy/http.h>
19 #include <haproxy/htx.h>
20 #include <haproxy/tools.h>
21 
22 /* Estimate the size of the HTX headers after the parsing, including the EOH. */
h1_eval_htx_hdrs_size(const struct http_hdr * hdrs)23 static 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. */
h1_eval_htx_size(const struct ist p1,const struct ist p2,const struct ist p3,const struct http_hdr * hdrs)35 static 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  * successful replies to CONNECT requests or on protocol switching.
49  */
h1_set_tunnel_mode(struct h1m * h1m)50 static 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  */
h1_process_req_vsn(struct h1m * h1m,union h1_sl * sl)59 static 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  */
h1_process_res_vsn(struct h1m * h1m,union h1_sl * sl)101 static 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. */
h1m_htx_sl_flags(struct h1m * h1m)127 static 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  */
h1_postparse_req_hdrs(struct h1m * h1m,union h1_sl * h1sl,struct htx * htx,struct http_hdr * hdrs,size_t max)157 static 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 		goto output_full;
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 
194 	/* 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);
200 		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 message 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   output_full:
214 	h1m_init_req(h1m);
215 	h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
216 	return -2;
217   error:
218 	h1m->err_pos = h1m->next;
219 	h1m->err_state = h1m->state;
220 	htx->flags |= HTX_FL_PARSING_ERROR;
221 	return -1;
222 }
223 
224 /* Postprocess the parsed headers for a response and convert them into an htx
225  * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
226  * proceed. Parsing errors are reported by setting the htx flag
227  * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
228  */
h1_postparse_res_hdrs(struct h1m * h1m,union h1_sl * h1sl,struct htx * htx,struct http_hdr * hdrs,size_t max)229 static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
230 				 struct http_hdr *hdrs, size_t max)
231 {
232 	struct htx_sl *sl;
233 	struct ist vsn, status, reason;
234 	unsigned int flags;
235 	size_t used;
236 	uint16_t code = 0;
237 
238 	if (h1sl) {
239 		/* For HTTP responses, the start-line was parsed */
240 		code   = h1sl->st.status;
241 		vsn    = h1sl->st.v;
242 		status = h1sl->st.c;
243 		reason = h1sl->st.r;
244 	}
245 	else {
246 		/* For FCGI responses, there is no start(-line but the "Status"
247 		 * header must be parsed, if found.
248 		 */
249 		int hdr;
250 
251 		vsn = ((h1m->flags & H1_MF_VER_11) ? ist("HTTP/1.1") : ist("HTTP/1.0"));
252 		for (hdr = 0; hdrs[hdr].n.len; hdr++) {
253 			if (isteqi(hdrs[hdr].n, ist("status"))) {
254 				code = http_parse_status_val(hdrs[hdr].v, &status, &reason);
255 			}
256 			else if (isteqi(hdrs[hdr].n, ist("location"))) {
257 				code = 302;
258 				status = ist("302");
259 				reason = ist("Moved Temporarily");
260 			}
261 		}
262 		if (!code) {
263 			code = 200;
264 			status = ist("200");
265 			reason = ist("OK");
266 		}
267 		/* FIXME: Check the codes 1xx ? */
268 	}
269 
270 	/* Be sure the message, once converted into HTX, will not exceed the max
271 	 * size allowed.
272 	 */
273 	if (h1_eval_htx_size(vsn, status, reason, hdrs) > max) {
274 		if (htx_is_empty(htx))
275 			goto error;
276 		goto output_full;
277 	}
278 
279 	if (((h1m->flags & H1_MF_METH_CONNECT) && code == 200) || code == 101) {
280 		/* Switch successful 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 message 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   output_full:
318 	h1m_init_res(h1m);
319 	h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
320 	return -2;
321   error:
322 	h1m->err_pos = h1m->next;
323 	h1m->err_state = h1m->state;
324 	htx->flags |= HTX_FL_PARSING_ERROR;
325 	return -1;
326 }
327 
328 /* Parse HTTP/1 headers. It returns the number of bytes parsed on success, 0 if
329  * headers are incomplete, -1 if an error occurred or -2 if it needs more space
330  * to proceed while the output buffer is not empty. Parsing errors are reported
331  * by setting the htx flag HTX_FL_PARSING_ERROR and filling h1m->err_pos and
332  * h1m->err_state fields. This functions is responsible to update the parser
333  * state <h1m> and the start-line <h1sl> if not NULL.  For the requests, <h1sl>
334  * must always be provided. For responses, <h1sl> may be NULL and <h1m> flags
335  * HTTP_METH_CONNECT of HTTP_METH_HEAD may be set.
336  */
h1_parse_msg_hdrs(struct h1m * h1m,union h1_sl * h1sl,struct htx * dsthtx,struct buffer * srcbuf,size_t ofs,size_t max)337 int h1_parse_msg_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *dsthtx,
338 		      struct buffer *srcbuf, size_t ofs, size_t max)
339 {
340 	struct http_hdr hdrs[global.tune.max_http_hdr];
341 	int total = 0, ret = 0;
342 
343 	if (!max || !b_data(srcbuf))
344 		goto end;
345 
346 	/* Realing input buffer if necessary */
347 	if (b_head(srcbuf) + b_data(srcbuf) > b_wrap(srcbuf))
348 		b_slow_realign(srcbuf, trash.area, 0);
349 
350 	if (!h1sl) {
351 		/* If there no start-line, be sure to only parse the headers */
352 		h1m->flags |= H1_MF_HDRS_ONLY;
353 	}
354 	ret = h1_headers_to_hdr_list(b_peek(srcbuf, ofs), b_tail(srcbuf),
355 				     hdrs, sizeof(hdrs)/sizeof(hdrs[0]), h1m, h1sl);
356 	if (ret <= 0) {
357 		/* Incomplete or invalid message. If the input buffer only
358 		 * contains headers and is full, which is detected by it being
359 		 * full and the offset to be zero, it's an error because
360 		 * headers are too large to be handled by the parser. */
361 		if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
362 			goto error;
363 		goto end;
364 	}
365 	total = ret;
366 
367 	/* messages headers fully parsed, do some checks to prepare the body
368 	 * parsing.
369 	 */
370 
371 	if (!(h1m->flags & H1_MF_RESP)) {
372 		if (!h1_process_req_vsn(h1m, h1sl)) {
373 			h1m->err_pos = h1sl->rq.v.ptr - b_head(srcbuf);
374 			h1m->err_state = h1m->state;
375 			goto vsn_error;
376 		}
377 		ret = h1_postparse_req_hdrs(h1m, h1sl, dsthtx, hdrs, max);
378 		if (ret < 0)
379 			return ret;
380 	}
381 	else {
382 		if (h1sl && !h1_process_res_vsn(h1m, h1sl)) {
383 			h1m->err_pos = h1sl->st.v.ptr - b_head(srcbuf);
384 			h1m->err_state = h1m->state;
385 			goto vsn_error;
386 		}
387 		ret = h1_postparse_res_hdrs(h1m, h1sl, dsthtx, hdrs, max);
388 		if (ret < 0)
389 			return ret;
390 	}
391 
392 	/* Switch messages without any payload to DONE state */
393 	if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
394 	    ((h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN))
395 		h1m->state = H1_MSG_DONE;
396 
397   end:
398 	return total;
399   error:
400 	h1m->err_pos = h1m->next;
401 	h1m->err_state = h1m->state;
402   vsn_error:
403 	dsthtx->flags |= HTX_FL_PARSING_ERROR;
404 	return -1;
405 
406 }
407 
408 /* Copy data from <srbuf> into an DATA block in <dsthtx>. If possible, a
409  * zero-copy is performed. It returns the number of bytes copied.
410  */
h1_copy_msg_data(struct htx ** dsthtx,struct buffer * srcbuf,size_t ofs,size_t count,struct buffer * htxbuf)411 static int h1_copy_msg_data(struct htx **dsthtx, struct buffer *srcbuf, size_t ofs,
412 			    size_t count, struct buffer *htxbuf)
413 {
414 	struct htx *tmp_htx = *dsthtx;
415 
416 	/* very often with large files we'll face the following
417 	 * situation :
418 	 *   - htx is empty and points to <htxbuf>
419 	 *   - ret == srcbuf->data
420 	 *   - srcbuf->head == sizeof(struct htx)
421 	 *   => we can swap the buffers and place an htx header into
422 	 *      the target buffer instead
423 	 */
424 	if (unlikely(htx_is_empty(tmp_htx) && count == b_data(srcbuf) &&
425 		     !ofs && b_head_ofs(srcbuf) == sizeof(struct htx))) {
426 		void *raw_area = srcbuf->area;
427 		void *htx_area = htxbuf->area;
428 		struct htx_blk *blk;
429 
430 		srcbuf->area = htx_area;
431 		htxbuf->area = raw_area;
432 		tmp_htx = (struct htx *)htxbuf->area;
433 		tmp_htx->size = htxbuf->size - sizeof(*tmp_htx);
434 		htx_reset(tmp_htx);
435 		b_set_data(htxbuf, b_size(htxbuf));
436 
437 		blk = htx_add_blk(tmp_htx, HTX_BLK_DATA, count);
438 		blk->info += count;
439 
440 		*dsthtx = tmp_htx;
441 		/* nothing else to do, the old buffer now contains an
442 		 * empty pre-initialized HTX header
443 		 */
444 		return count;
445 	}
446 
447 	return htx_add_data(*dsthtx, ist2(b_peek(srcbuf, ofs), count));
448 }
449 
450 /* Parse HTTP/1 body. It returns the number of bytes parsed if > 0, or 0 if it
451  * couldn't proceed. Parsing errors are reported by setting the htx flags
452  * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
453  * functions is responsible to update the parser state <h1m>.
454  */
h1_parse_msg_data(struct h1m * h1m,struct htx ** dsthtx,struct buffer * srcbuf,size_t ofs,size_t max,struct buffer * htxbuf)455 int h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
456 		      struct buffer *srcbuf, size_t ofs, size_t max,
457 		      struct buffer *htxbuf)
458 {
459 	size_t total = 0;
460 	int32_t ret = 0;
461 
462 	if (h1m->flags & H1_MF_CLEN) {
463 		/* content-length: read only h2m->body_len */
464 		ret = htx_get_max_blksz(*dsthtx, max);
465 		if ((uint64_t)ret > h1m->curr_len)
466 			ret = h1m->curr_len;
467 		if (ret > b_contig_data(srcbuf, ofs))
468 			ret = b_contig_data(srcbuf, ofs);
469 		if (ret) {
470 			int32_t try = ret;
471 
472 			ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
473 			h1m->curr_len -= ret;
474 			max -= sizeof(struct htx_blk) + ret;
475 			ofs += ret;
476 			total += ret;
477 			if (ret < try)
478 				goto end;
479 		}
480 
481 		if (!h1m->curr_len)
482 			h1m->state = H1_MSG_DONE;
483 	}
484 	else if (h1m->flags & H1_MF_CHNK) {
485 		/* te:chunked : parse chunks */
486 	  new_chunk:
487 		if (h1m->state == H1_MSG_CHUNK_CRLF) {
488 			ret = h1_skip_chunk_crlf(srcbuf, ofs, b_data(srcbuf));
489 			if (ret <= 0)
490 				goto end;
491 			h1m->state = H1_MSG_CHUNK_SIZE;
492 			ofs += ret;
493 			total += ret;
494 		}
495 		if (h1m->state == H1_MSG_CHUNK_SIZE) {
496 			uint64_t chksz;
497 
498 			ret = h1_parse_chunk_size(srcbuf, ofs, b_data(srcbuf), &chksz);
499 			if (ret <= 0)
500 				goto end;
501 			h1m->state = ((!chksz) ? H1_MSG_TRAILERS : H1_MSG_DATA);
502 			h1m->curr_len  = chksz;
503 			h1m->body_len += chksz;
504 			ofs += ret;
505 			total += ret;
506 			if (!h1m->curr_len)
507 				goto end;
508 		}
509 		if (h1m->state == H1_MSG_DATA) {
510 			ret = htx_get_max_blksz(*dsthtx, max);
511 			if ((uint64_t)ret > h1m->curr_len)
512 				ret = h1m->curr_len;
513 			if (ret > b_contig_data(srcbuf, ofs))
514 				ret = b_contig_data(srcbuf, ofs);
515 			if (ret) {
516 				int32_t try = ret;
517 
518 				ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
519 				h1m->curr_len -= ret;
520 				max -= sizeof(struct htx_blk) + ret;
521 				ofs += ret;
522 				total += ret;
523 				if (ret < try)
524 					goto end;
525 			}
526 			if (!h1m->curr_len) {
527 				h1m->state = H1_MSG_CHUNK_CRLF;
528 				goto new_chunk;
529 			}
530 			goto end;
531 		}
532 	}
533 	else if (h1m->flags & H1_MF_XFER_LEN) {
534 		/* XFER_LEN is set but not CLEN nor CHNK, it means there is no
535 		 * body. Switch the message in DONE state
536 		 */
537 		h1m->state = H1_MSG_DONE;
538 	}
539 	else {
540 		/* no content length, read till SHUTW */
541 		ret = htx_get_max_blksz(*dsthtx, max);
542 		if (ret > b_contig_data(srcbuf, ofs))
543 			ret = b_contig_data(srcbuf, ofs);
544 		if (ret)
545 			total += h1_copy_msg_data(dsthtx, srcbuf, ofs, ret, htxbuf);
546 	}
547 
548   end:
549 	if (ret < 0) {
550 		(*dsthtx)->flags |= HTX_FL_PARSING_ERROR;
551 		h1m->err_state = h1m->state;
552 		h1m->err_pos = ofs;
553 		total = 0;
554 	}
555 
556 	/* update htx->extra, only when the body length is known */
557 	if (h1m->flags & H1_MF_XFER_LEN)
558 		(*dsthtx)->extra = h1m->curr_len;
559 	return total;
560 }
561 
562 /* Parse HTTP/1 trailers. It returns the number of bytes parsed on success, 0 if
563  * trailers are incomplete, -1 if an error occurred or -2 if it needs more space
564  * to proceed while the output buffer is not empty. Parsing errors are reported
565  * by setting the htx flags HTX_FL_PARSING_ERROR and filling h1m->err_pos and
566  * h1m->err_state fields. This functions is responsible to update the parser
567  * state <h1m>.
568  */
h1_parse_msg_tlrs(struct h1m * h1m,struct htx * dsthtx,struct buffer * srcbuf,size_t ofs,size_t max)569 int h1_parse_msg_tlrs(struct h1m *h1m, struct htx *dsthtx,
570 		      struct buffer *srcbuf, size_t ofs, size_t max)
571 {
572 	struct http_hdr hdrs[global.tune.max_http_hdr];
573 	struct h1m tlr_h1m;
574 	int ret = 0;
575 
576 	if (!max || !b_data(srcbuf))
577 		goto end;
578 
579 	/* Realing input buffer if necessary */
580 	if (b_peek(srcbuf, ofs) > b_tail(srcbuf))
581 		b_slow_realign(srcbuf, trash.area, 0);
582 
583 	tlr_h1m.flags = (H1_MF_NO_PHDR|H1_MF_HDRS_ONLY);
584 	ret = h1_headers_to_hdr_list(b_peek(srcbuf, ofs), b_tail(srcbuf),
585 				     hdrs, sizeof(hdrs)/sizeof(hdrs[0]), &tlr_h1m, NULL);
586 	if (ret <= 0) {
587 		/* Incomplete or invalid trailers. If the input buffer only
588 		 * contains trailers and is full, which is detected by it being
589 		 * full and the offset to be zero, it's an error because
590 		 * trailers are too large to be handled by the parser. */
591 		if (ret < 0 || (!ret && !ofs && !buf_room_for_htx_data(srcbuf)))
592 			goto error;
593 		goto end;
594 	}
595 
596 	/* messages trailers fully parsed. */
597 	if (h1_eval_htx_hdrs_size(hdrs) > max) {
598 		if (htx_is_empty(dsthtx))
599 			goto error;
600 		goto output_full;
601 	}
602 
603 	if (!htx_add_all_trailers(dsthtx, hdrs))
604 		goto error;
605 
606 	h1m->state = H1_MSG_DONE;
607 
608   end:
609 	return ret;
610   output_full:
611 	return -2;
612   error:
613 	h1m->err_state = h1m->state;
614 	h1m->err_pos = h1m->next;
615 	dsthtx->flags |= HTX_FL_PARSING_ERROR;
616 	return -1;
617 }
618 
619 /* Finish HTTP/1 parsing by adding the HTX EOM block. It returns 1 on success or
620  * 0 if it couldn't proceed. There is no parsing at this stage, but a parsing
621  * error is reported if the message state is not H1_MSG_DONE. */
h1_parse_msg_eom(struct h1m * h1m,struct htx * dsthtx,size_t max)622 int h1_parse_msg_eom(struct h1m *h1m, struct htx *dsthtx, size_t max)
623 {
624 	if (h1m->state != H1_MSG_DONE) {
625 		h1m->err_state = h1m->state;
626 		h1m->err_pos = h1m->next;
627 		dsthtx->flags |= HTX_FL_PARSING_ERROR;
628 		return 0;
629 	}
630 
631 	dsthtx->flags |= HTX_FL_EOI; /* no more data are expected. Only EOM remains to add now */
632 	if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(dsthtx, HTX_BLK_EOM))
633 		return 0;
634 
635 	return 1;
636 }
637 
638 
639 /* Appends the H1 representation of the request line <sl> to the chunk <chk>. It
640  * returns 1 if data are successfully appended, otherwise it returns 0.
641  */
h1_format_htx_reqline(const struct htx_sl * sl,struct buffer * chk)642 int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk)
643 {
644 	struct ist uri;
645 	size_t sz = chk->data;
646 
647 	uri = h1_get_uri(sl);
648 	if (!chunk_memcat(chk, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)) ||
649 	    !chunk_memcat(chk, " ", 1) ||
650 	    !chunk_memcat(chk, uri.ptr, uri.len) ||
651 	    !chunk_memcat(chk, " ", 1))
652 		goto full;
653 
654 	if (sl->flags & HTX_SL_F_VER_11) {
655 		if (!chunk_memcat(chk, "HTTP/1.1", 8))
656 			goto full;
657 	}
658 	else {
659 		if (!chunk_memcat(chk, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)))
660 			goto full;
661 	}
662 
663 	if (!chunk_memcat(chk, "\r\n", 2))
664 		goto full;
665 
666 	return 1;
667 
668   full:
669 	chk->data = sz;
670 	return 0;
671 }
672 
673 /* Appends the H1 representation of the status line <sl> to the chunk <chk>. It
674  * returns 1 if data are successfully appended, otherwise it returns 0.
675  */
h1_format_htx_stline(const struct htx_sl * sl,struct buffer * chk)676 int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk)
677 {
678 	size_t sz = chk->data;
679 
680 	if (HTX_SL_LEN(sl) + 4 > b_room(chk))
681 		return 0;
682 
683 	if (sl->flags & HTX_SL_F_VER_11) {
684 		if (!chunk_memcat(chk, "HTTP/1.1", 8))
685 			goto full;
686 	}
687 	else {
688 		if (!chunk_memcat(chk, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl)))
689 			goto full;
690 	}
691 	if (!chunk_memcat(chk, " ", 1) ||
692 	    !chunk_memcat(chk, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl)) ||
693 	    !chunk_memcat(chk, " ", 1) ||
694 	    !chunk_memcat(chk, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl)) ||
695 	    !chunk_memcat(chk, "\r\n", 2))
696 		goto full;
697 
698 	return 1;
699 
700   full:
701 	chk->data = sz;
702 	return 0;
703 }
704 
705 /* Appends the H1 representation of the header <n> with the value <v> to the
706  * chunk <chk>. It returns 1 if data are successfully appended, otherwise it
707  * returns 0.
708  */
h1_format_htx_hdr(const struct ist n,const struct ist v,struct buffer * chk)709 int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk)
710 {
711 	size_t sz = chk->data;
712 
713 	if (n.len + v.len + 4 > b_room(chk))
714 		return 0;
715 
716 	if (!chunk_memcat(chk, n.ptr, n.len) ||
717 	    !chunk_memcat(chk, ": ", 2) ||
718 	    !chunk_memcat(chk, v.ptr, v.len) ||
719 	    !chunk_memcat(chk, "\r\n", 2))
720 		goto full;
721 
722 	return 1;
723 
724   full:
725 	chk->data = sz;
726 	return 0;
727 }
728 
729 /* Appends the H1 representation of the data <data> to the chunk <chk>. If
730  * <chunked> is non-zero, it emits HTTP/1 chunk-encoded data. It returns 1 if
731  * data are successfully appended, otherwise it returns 0.
732  */
h1_format_htx_data(const struct ist data,struct buffer * chk,int chunked)733 int h1_format_htx_data(const struct ist data, struct buffer *chk, int chunked)
734 {
735 	size_t sz = chk->data;
736 
737 	if (chunked) {
738 		uint32_t chksz;
739 		char     tmp[10];
740 		char    *beg, *end;
741 
742 		chksz = data.len;
743 
744 		beg = end = tmp+10;
745 		*--beg = '\n';
746 		*--beg = '\r';
747 		do {
748 			*--beg = hextab[chksz & 0xF];
749 		} while (chksz >>= 4);
750 
751 		if (!chunk_memcat(chk, beg, end - beg) ||
752 		    !chunk_memcat(chk, data.ptr, data.len) ||
753 		    !chunk_memcat(chk, "\r\n", 2))
754 			goto full;
755 	}
756 	else {
757 		if (!chunk_memcat(chk, data.ptr, data.len))
758 			return 0;
759 	}
760 
761 	return 1;
762 
763   full:
764 	chk->data = sz;
765 	return 0;
766 }
767 
768 /*
769  * Local variables:
770  *  c-indent-level: 8
771  *  c-basic-offset: 8
772  * End:
773  */
774