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/http_htx.h>
20 #include <haproxy/htx.h>
21 #include <haproxy/tools.h>
22 
23 /* Estimate the size of the HTX headers after the parsing, including the EOH. */
h1_eval_htx_hdrs_size(const struct http_hdr * hdrs)24 static size_t h1_eval_htx_hdrs_size(const struct http_hdr *hdrs)
25 {
26 	size_t sz = 0;
27 	int i;
28 
29 	for (i = 0; hdrs[i].n.len; i++)
30 		sz += sizeof(struct htx_blk) + hdrs[i].n.len + hdrs[i].v.len;
31 	sz += sizeof(struct htx_blk) + 1;
32 	return sz;
33 }
34 
35 /* 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)36 static size_t h1_eval_htx_size(const struct ist p1, const struct ist p2, const struct ist p3,
37 			       const struct http_hdr *hdrs)
38 {
39 	size_t sz;
40 
41 	/* size of the HTX start-line */
42 	sz = sizeof(struct htx_blk) + sizeof(struct htx_sl) + p1.len + p2.len + p3.len;
43 	sz += h1_eval_htx_hdrs_size(hdrs);
44 	return sz;
45 }
46 
47 /* Check the validity of the request version. If the version is valid, it
48  * returns 1. Otherwise, it returns 0.
49  */
h1_process_req_vsn(struct h1m * h1m,union h1_sl * sl)50 static int h1_process_req_vsn(struct h1m *h1m, union h1_sl *sl)
51 {
52 	/* RFC7230#2.6 has enforced the format of the HTTP version string to be
53 	 * exactly one digit "." one digit. This check may be disabled using
54 	 * option accept-invalid-http-request.
55 	 */
56 	if (h1m->err_pos == -2) { /* PR_O2_REQBUG_OK not set */
57 		if (sl->rq.v.len != 8)
58 			return 0;
59 
60 		if (*(sl->rq.v.ptr + 4) != '/' ||
61 		    !isdigit((unsigned char)*(sl->rq.v.ptr + 5)) ||
62 		    *(sl->rq.v.ptr + 6) != '.' ||
63 		    !isdigit((unsigned char)*(sl->rq.v.ptr + 7)))
64 			return 0;
65 	}
66 	else if (!sl->rq.v.len) {
67 		/* try to convert HTTP/0.9 requests to HTTP/1.0 */
68 
69 		/* RFC 1945 allows only GET for HTTP/0.9 requests */
70 		if (sl->rq.meth != HTTP_METH_GET)
71 			return 0;
72 
73 		/* HTTP/0.9 requests *must* have a request URI, per RFC 1945 */
74 		if (!sl->rq.u.len)
75 			return 0;
76 
77 		/* Add HTTP version */
78 		sl->rq.v = ist("HTTP/1.0");
79 		return 1;
80 	}
81 
82 	if ((sl->rq.v.len == 8) &&
83 	    ((*(sl->rq.v.ptr + 5) > '1') ||
84 	     ((*(sl->rq.v.ptr + 5) == '1') && (*(sl->rq.v.ptr + 7) >= '1'))))
85 		h1m->flags |= H1_MF_VER_11;
86 	return 1;
87 }
88 
89 /* Check the validity of the response version. If the version is valid, it
90  * returns 1. Otherwise, it returns 0.
91  */
h1_process_res_vsn(struct h1m * h1m,union h1_sl * sl)92 static int h1_process_res_vsn(struct h1m *h1m, union h1_sl *sl)
93 {
94 	/* RFC7230#2.6 has enforced the format of the HTTP version string to be
95 	 * exactly one digit "." one digit. This check may be disabled using
96 	 * option accept-invalid-http-request.
97 	 */
98 	if (h1m->err_pos == -2) { /* PR_O2_REQBUG_OK not set */
99 		if (sl->st.v.len != 8)
100 			return 0;
101 
102 		if (*(sl->st.v.ptr + 4) != '/' ||
103 		    !isdigit((unsigned char)*(sl->st.v.ptr + 5)) ||
104 		    *(sl->st.v.ptr + 6) != '.' ||
105 		    !isdigit((unsigned char)*(sl->st.v.ptr + 7)))
106 			return 0;
107 	}
108 
109 	if ((sl->st.v.len == 8) &&
110 	    ((*(sl->st.v.ptr + 5) > '1') ||
111 	     ((*(sl->st.v.ptr + 5) == '1') && (*(sl->st.v.ptr + 7) >= '1'))))
112 		h1m->flags |= H1_MF_VER_11;
113 
114 	return 1;
115 }
116 
117 /* Convert H1M flags to HTX start-line flags. */
h1m_htx_sl_flags(struct h1m * h1m)118 static unsigned int h1m_htx_sl_flags(struct h1m *h1m)
119 {
120 	unsigned int flags = HTX_SL_F_NONE;
121 
122 	if (h1m->flags & H1_MF_RESP)
123 		flags |= HTX_SL_F_IS_RESP;
124 	if (h1m->flags & H1_MF_VER_11)
125 		flags |= HTX_SL_F_VER_11;
126 	if (h1m->flags & H1_MF_XFER_ENC)
127 		flags |= HTX_SL_F_XFER_ENC;
128 	if (h1m->flags & H1_MF_XFER_LEN) {
129 		flags |= HTX_SL_F_XFER_LEN;
130 		if (h1m->flags & H1_MF_CHNK)
131 			flags |= HTX_SL_F_CHNK;
132 		else if (h1m->flags & H1_MF_CLEN) {
133 			flags |= HTX_SL_F_CLEN;
134 			if (h1m->body_len == 0)
135 				flags |= HTX_SL_F_BODYLESS;
136 		}
137 		else
138 			flags |= HTX_SL_F_BODYLESS;
139 	}
140 	if (h1m->flags & H1_MF_CONN_UPG)
141 		flags |= HTX_SL_F_CONN_UPG;
142 	return flags;
143 }
144 
145 /* Postprocess the parsed headers for a request and convert them into an htx
146  * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
147  * proceed. Parsing errors are reported by setting the htx flag
148  * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
149  */
h1_postparse_req_hdrs(struct h1m * h1m,union h1_sl * h1sl,struct htx * htx,struct http_hdr * hdrs,size_t max)150 static int h1_postparse_req_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
151 				 struct http_hdr *hdrs, size_t max)
152 {
153 	struct htx_sl *sl;
154 	struct ist meth, uri, vsn;
155 	unsigned int flags;
156 
157 	/* <h1sl> is always defined for a request */
158 	meth = h1sl->rq.m;
159 	uri  = h1sl->rq.u;
160 	vsn  = h1sl->rq.v;
161 
162 	/* Be sure the message, once converted into HTX, will not exceed the max
163 	 * size allowed.
164 	 */
165 	if (h1_eval_htx_size(meth, uri, vsn, hdrs) > max) {
166 		if (htx_is_empty(htx))
167 			goto error;
168 		goto output_full;
169 	}
170 
171 	/* By default, request have always a known length */
172 	h1m->flags |= H1_MF_XFER_LEN;
173 
174 	if (h1sl->rq.meth == HTTP_METH_CONNECT) {
175 		h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
176 		h1m->curr_len = h1m->body_len = 0;
177 	}
178 
179 
180 	flags = h1m_htx_sl_flags(h1m);
181 	if ((flags & (HTX_SL_F_CONN_UPG|HTX_SL_F_BODYLESS)) == HTX_SL_F_CONN_UPG) {
182 		int i;
183 
184 		for (i = 0; hdrs[i].n.len; i++) {
185 			if (isteqi(hdrs[i].n, ist("upgrade")))
186 				hdrs[i].v = IST_NULL;
187 		}
188 		h1m->flags &=~ H1_MF_CONN_UPG;
189 		flags &= ~HTX_SL_F_CONN_UPG;
190 	}
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 
196 	/* 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);
202 		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 		/* absolute-form target URI present, proceed to scheme-based
206 		 * normalization */
207 		http_scheme_based_normalize(htx);
208 	}
209 
210 	/* If body length cannot be determined, set htx->extra to
211 	 * ULLONG_MAX. This value is impossible in other cases.
212 	 */
213 	htx->extra = ((h1m->flags & H1_MF_XFER_LEN) ? h1m->curr_len : ULLONG_MAX);
214 
215   end:
216 	return 1;
217   output_full:
218 	h1m_init_req(h1m);
219 	h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
220 	return -2;
221   error:
222 	h1m->err_pos = h1m->next;
223 	h1m->err_state = h1m->state;
224 	htx->flags |= HTX_FL_PARSING_ERROR;
225 	return -1;
226 }
227 
228 /* Postprocess the parsed headers for a response and convert them into an htx
229  * message. It returns the number of bytes parsed if > 0, or 0 if it couldn't
230  * proceed. Parsing errors are reported by setting the htx flag
231  * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields.
232  */
h1_postparse_res_hdrs(struct h1m * h1m,union h1_sl * h1sl,struct htx * htx,struct http_hdr * hdrs,size_t max)233 static int h1_postparse_res_hdrs(struct h1m *h1m, union h1_sl *h1sl, struct htx *htx,
234 				 struct http_hdr *hdrs, size_t max)
235 {
236 	struct htx_sl *sl;
237 	struct ist vsn, status, reason;
238 	unsigned int flags;
239 	uint16_t code = 0;
240 
241 	if (h1sl) {
242 		/* For HTTP responses, the start-line was parsed */
243 		code   = h1sl->st.status;
244 		vsn    = h1sl->st.v;
245 		status = h1sl->st.c;
246 		reason = h1sl->st.r;
247 	}
248 	else {
249 		/* For FCGI responses, there is no start(-line but the "Status"
250 		 * header must be parsed, if found.
251 		 */
252 		int hdr;
253 
254 		vsn = ((h1m->flags & H1_MF_VER_11) ? ist("HTTP/1.1") : ist("HTTP/1.0"));
255 		for (hdr = 0; hdrs[hdr].n.len; hdr++) {
256 			if (isteqi(hdrs[hdr].n, ist("status"))) {
257 				code = http_parse_status_val(hdrs[hdr].v, &status, &reason);
258 			}
259 			else if (isteqi(hdrs[hdr].n, ist("location"))) {
260 				code = 302;
261 				status = ist("302");
262 				reason = ist("Moved Temporarily");
263 			}
264 		}
265 		if (!code) {
266 			code = 200;
267 			status = ist("200");
268 			reason = ist("OK");
269 		}
270 		/* FIXME: Check the codes 1xx ? */
271 	}
272 
273 	/* Be sure the message, once converted into HTX, will not exceed the max
274 	 * size allowed.
275 	 */
276 	if (h1_eval_htx_size(vsn, status, reason, hdrs) > max) {
277 		if (htx_is_empty(htx))
278 			goto error;
279 		goto output_full;
280 	}
281 
282 	if (((h1m->flags & H1_MF_METH_CONNECT) && code >= 200 && code < 300) || code == 101) {
283 		h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
284 		h1m->flags |= H1_MF_XFER_LEN;
285 		h1m->curr_len = h1m->body_len = 0;
286 	}
287 	else if ((h1m->flags & H1_MF_METH_HEAD) || (code >= 100 && code < 200) ||
288 		 (code == 204) || (code == 304)) {
289 		/* Responses known to have no body. */
290 		h1m->flags &= ~(H1_MF_CLEN|H1_MF_CHNK);
291 		h1m->flags |= H1_MF_XFER_LEN;
292 		h1m->curr_len = h1m->body_len = 0;
293 	}
294 	else if (h1m->flags & (H1_MF_CLEN|H1_MF_CHNK)) {
295 		/* Responses with a known body length. */
296 		h1m->flags |= H1_MF_XFER_LEN;
297 	}
298 
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 	/* If body length cannot be determined, set htx->extra to
306 	 * ULLONG_MAX. This value is impossible in other cases.
307 	 */
308 	htx->extra = ((h1m->flags & H1_MF_XFER_LEN) ? h1m->curr_len : ULLONG_MAX);
309 
310   end:
311 	return 1;
312   output_full:
313 	h1m_init_res(h1m);
314 	h1m->flags |= (H1_MF_NO_PHDR|H1_MF_CLEAN_CONN_HDR);
315 	return -2;
316   error:
317 	h1m->err_pos = h1m->next;
318 	h1m->err_state = h1m->state;
319 	htx->flags |= HTX_FL_PARSING_ERROR;
320 	return -1;
321 }
322 
323 /* Parse HTTP/1 headers. It returns the number of bytes parsed on success, 0 if
324  * headers are incomplete, -1 if an error occurred or -2 if it needs more space
325  * to proceed while the output buffer is not empty. Parsing errors are reported
326  * by setting the htx flag HTX_FL_PARSING_ERROR and filling h1m->err_pos and
327  * h1m->err_state fields. This functions is responsible to update the parser
328  * state <h1m> and the start-line <h1sl> if not NULL.  For the requests, <h1sl>
329  * must always be provided. For responses, <h1sl> may be NULL and <h1m> flags
330  * HTTP_METH_CONNECT of HTTP_METH_HEAD may be set.
331  */
h1_parse_msg_hdrs(struct h1m * h1m,union h1_sl * h1sl,struct htx * dsthtx,struct buffer * srcbuf,size_t ofs,size_t max)332 int 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 total = 0, 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 	total = ret;
361 
362 	/* messages headers fully parsed, do some checks to prepare the body
363 	 * parsing.
364 	 */
365 
366 	if (!(h1m->flags & H1_MF_RESP)) {
367 		if (!h1_process_req_vsn(h1m, h1sl)) {
368 			h1m->err_pos = h1sl->rq.v.ptr - b_head(srcbuf);
369 			h1m->err_state = h1m->state;
370 			goto vsn_error;
371 		}
372 		ret = h1_postparse_req_hdrs(h1m, h1sl, dsthtx, hdrs, max);
373 		if (ret < 0)
374 			return ret;
375 	}
376 	else {
377 		if (h1sl && !h1_process_res_vsn(h1m, h1sl)) {
378 			h1m->err_pos = h1sl->st.v.ptr - b_head(srcbuf);
379 			h1m->err_state = h1m->state;
380 			goto vsn_error;
381 		}
382 		ret = h1_postparse_res_hdrs(h1m, h1sl, dsthtx, hdrs, max);
383 		if (ret < 0)
384 			return ret;
385 	}
386 
387 	/* Switch messages without any payload to DONE state */
388 	if (((h1m->flags & H1_MF_CLEN) && h1m->body_len == 0) ||
389 	    ((h1m->flags & (H1_MF_XFER_LEN|H1_MF_CLEN|H1_MF_CHNK)) == H1_MF_XFER_LEN)) {
390 		h1m->state = H1_MSG_DONE;
391 		dsthtx->flags |= HTX_FL_EOM;
392 	}
393 
394   end:
395 	return total;
396   error:
397 	h1m->err_pos = h1m->next;
398 	h1m->err_state = h1m->state;
399   vsn_error:
400 	dsthtx->flags |= HTX_FL_PARSING_ERROR;
401 	return -1;
402 
403 }
404 
405 /* Copy data from <srbuf> into an DATA block in <dsthtx>. If possible, a
406  * zero-copy is performed. It returns the number of bytes copied.
407  */
h1_copy_msg_data(struct htx ** dsthtx,struct buffer * srcbuf,size_t ofs,size_t count,struct buffer * htxbuf)408 static int h1_copy_msg_data(struct htx **dsthtx, struct buffer *srcbuf, size_t ofs,
409 			    size_t count, struct buffer *htxbuf)
410 {
411 	struct htx *tmp_htx = *dsthtx;
412 
413 	/* very often with large files we'll face the following
414 	 * situation :
415 	 *   - htx is empty and points to <htxbuf>
416 	 *   - ret == srcbuf->data
417 	 *   - srcbuf->head == sizeof(struct htx)
418 	 *   => we can swap the buffers and place an htx header into
419 	 *      the target buffer instead
420 	 */
421 	if (unlikely(htx_is_empty(tmp_htx) && count == b_data(srcbuf) &&
422 		     !ofs && b_head_ofs(srcbuf) == sizeof(struct htx))) {
423 		void *raw_area = srcbuf->area;
424 		void *htx_area = htxbuf->area;
425 		struct htx_blk *blk;
426 
427 		srcbuf->area = htx_area;
428 		htxbuf->area = raw_area;
429 		tmp_htx = (struct htx *)htxbuf->area;
430 		tmp_htx->size = htxbuf->size - sizeof(*tmp_htx);
431 		htx_reset(tmp_htx);
432 		b_set_data(htxbuf, b_size(htxbuf));
433 
434 		blk = htx_add_blk(tmp_htx, HTX_BLK_DATA, count);
435 		blk->info += count;
436 
437 		*dsthtx = tmp_htx;
438 		/* nothing else to do, the old buffer now contains an
439 		 * empty pre-initialized HTX header
440 		 */
441 		return count;
442 	}
443 
444 	return htx_add_data(*dsthtx, ist2(b_peek(srcbuf, ofs), count));
445 }
446 
447 /* Parse HTTP/1 body. It returns the number of bytes parsed if > 0, or 0 if it
448  * couldn't proceed. Parsing errors are reported by setting the htx flags
449  * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
450  * functions is responsible to update the parser state <h1m>.
451  */
h1_parse_msg_data(struct h1m * h1m,struct htx ** dsthtx,struct buffer * srcbuf,size_t ofs,size_t max,struct buffer * htxbuf)452 int h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
453 		      struct buffer *srcbuf, size_t ofs, size_t max,
454 		      struct buffer *htxbuf)
455 {
456 	size_t total = 0;
457 	int32_t ret = 0;
458 
459 	if (h1m->flags & H1_MF_CLEN) {
460 		/* content-length: read only h2m->body_len */
461 		ret = htx_get_max_blksz(*dsthtx, max);
462 		if ((uint64_t)ret > h1m->curr_len)
463 			ret = h1m->curr_len;
464 		if (ret > b_contig_data(srcbuf, ofs))
465 			ret = b_contig_data(srcbuf, ofs);
466 		if (ret) {
467 			int32_t try = ret;
468 
469 			ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
470 			h1m->curr_len -= ret;
471 			max -= sizeof(struct htx_blk) + ret;
472 			ofs += ret;
473 			total += ret;
474 			if (ret < try)
475 				goto end;
476 		}
477 
478 		if (!h1m->curr_len) {
479 			h1m->state = H1_MSG_DONE;
480 			(*dsthtx)->flags |= HTX_FL_EOM;
481 		}
482 	}
483 	else if (h1m->flags & H1_MF_CHNK) {
484 		/* te:chunked : parse chunks */
485 	  new_chunk:
486 		if (h1m->state == H1_MSG_CHUNK_CRLF) {
487 			ret = h1_skip_chunk_crlf(srcbuf, ofs, b_data(srcbuf));
488 			if (ret <= 0)
489 				goto end;
490 			h1m->state = H1_MSG_CHUNK_SIZE;
491 			ofs += ret;
492 			total += ret;
493 		}
494 		if (h1m->state == H1_MSG_CHUNK_SIZE) {
495 			uint64_t chksz;
496 
497 			ret = h1_parse_chunk_size(srcbuf, ofs, b_data(srcbuf), &chksz);
498 			if (ret <= 0)
499 				goto end;
500 			h1m->state = ((!chksz) ? H1_MSG_TRAILERS : H1_MSG_DATA);
501 			h1m->curr_len  = chksz;
502 			h1m->body_len += chksz;
503 			ofs += ret;
504 			total += ret;
505 			if (!h1m->curr_len)
506 				goto end;
507 		}
508 		if (h1m->state == H1_MSG_DATA) {
509 			ret = htx_get_max_blksz(*dsthtx, max);
510 			if ((uint64_t)ret > h1m->curr_len)
511 				ret = h1m->curr_len;
512 			if (ret > b_contig_data(srcbuf, ofs))
513 				ret = b_contig_data(srcbuf, ofs);
514 			if (ret) {
515 				int32_t try = ret;
516 
517 				ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
518 				h1m->curr_len -= ret;
519 				max -= sizeof(struct htx_blk) + ret;
520 				ofs += ret;
521 				total += ret;
522 				if (ret < try)
523 					goto end;
524 			}
525 			if (!h1m->curr_len) {
526 				h1m->state = H1_MSG_CHUNK_CRLF;
527 				goto new_chunk;
528 			}
529 			goto end;
530 		}
531 	}
532 	else if (h1m->flags & H1_MF_XFER_LEN) {
533 		/* XFER_LEN is set but not CLEN nor CHNK, it means there is no
534 		 * body. Switch the message in DONE state
535 		 */
536 		h1m->state = H1_MSG_DONE;
537 		(*dsthtx)->flags |= HTX_FL_EOM;
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 	dsthtx->flags |= HTX_FL_EOM;
608 
609   end:
610 	return ret;
611   output_full:
612 	return -2;
613   error:
614 	h1m->err_state = h1m->state;
615 	h1m->err_pos = h1m->next;
616 	dsthtx->flags |= HTX_FL_PARSING_ERROR;
617 	return -1;
618 }
619 
620 /* Appends the H1 representation of the request line <sl> to the chunk <chk>. It
621  * returns 1 if data are successfully appended, otherwise it returns 0.
622  */
h1_format_htx_reqline(const struct htx_sl * sl,struct buffer * chk)623 int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk)
624 {
625 	struct ist uri;
626 	size_t sz = chk->data;
627 
628 	uri = h1_get_uri(sl);
629 	if (!chunk_memcat(chk, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)) ||
630 	    !chunk_memcat(chk, " ", 1) ||
631 	    !chunk_memcat(chk, uri.ptr, uri.len) ||
632 	    !chunk_memcat(chk, " ", 1))
633 		goto full;
634 
635 	if (sl->flags & HTX_SL_F_VER_11) {
636 		if (!chunk_memcat(chk, "HTTP/1.1", 8))
637 			goto full;
638 	}
639 	else {
640 		if (!chunk_memcat(chk, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)))
641 			goto full;
642 	}
643 
644 	if (!chunk_memcat(chk, "\r\n", 2))
645 		goto full;
646 
647 	return 1;
648 
649   full:
650 	chk->data = sz;
651 	return 0;
652 }
653 
654 /* Appends the H1 representation of the status line <sl> to the chunk <chk>. It
655  * returns 1 if data are successfully appended, otherwise it returns 0.
656  */
h1_format_htx_stline(const struct htx_sl * sl,struct buffer * chk)657 int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk)
658 {
659 	size_t sz = chk->data;
660 
661 	if (HTX_SL_LEN(sl) + 4 > b_room(chk))
662 		return 0;
663 
664 	if (sl->flags & HTX_SL_F_VER_11) {
665 		if (!chunk_memcat(chk, "HTTP/1.1", 8))
666 			goto full;
667 	}
668 	else {
669 		if (!chunk_memcat(chk, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl)))
670 			goto full;
671 	}
672 	if (!chunk_memcat(chk, " ", 1) ||
673 	    !chunk_memcat(chk, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl)) ||
674 	    !chunk_memcat(chk, " ", 1) ||
675 	    !chunk_memcat(chk, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl)) ||
676 	    !chunk_memcat(chk, "\r\n", 2))
677 		goto full;
678 
679 	return 1;
680 
681   full:
682 	chk->data = sz;
683 	return 0;
684 }
685 
686 /* Appends the H1 representation of the header <n> with the value <v> to the
687  * chunk <chk>. It returns 1 if data are successfully appended, otherwise it
688  * returns 0.
689  */
h1_format_htx_hdr(const struct ist n,const struct ist v,struct buffer * chk)690 int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk)
691 {
692 	size_t sz = chk->data;
693 
694 	if (n.len + v.len + 4 > b_room(chk))
695 		return 0;
696 
697 	if (!chunk_memcat(chk, n.ptr, n.len) ||
698 	    !chunk_memcat(chk, ": ", 2) ||
699 	    !chunk_memcat(chk, v.ptr, v.len) ||
700 	    !chunk_memcat(chk, "\r\n", 2))
701 		goto full;
702 
703 	return 1;
704 
705   full:
706 	chk->data = sz;
707 	return 0;
708 }
709 
710 /* Appends the H1 representation of the data <data> to the chunk <chk>. If
711  * <chunked> is non-zero, it emits HTTP/1 chunk-encoded data. It returns 1 if
712  * data are successfully appended, otherwise it returns 0.
713  */
h1_format_htx_data(const struct ist data,struct buffer * chk,int chunked)714 int h1_format_htx_data(const struct ist data, struct buffer *chk, int chunked)
715 {
716 	size_t sz = chk->data;
717 
718 	if (chunked) {
719 		uint32_t chksz;
720 		char     tmp[10];
721 		char    *beg, *end;
722 
723 		chksz = data.len;
724 
725 		beg = end = tmp+10;
726 		*--beg = '\n';
727 		*--beg = '\r';
728 		do {
729 			*--beg = hextab[chksz & 0xF];
730 		} while (chksz >>= 4);
731 
732 		if (!chunk_memcat(chk, beg, end - beg) ||
733 		    !chunk_memcat(chk, data.ptr, data.len) ||
734 		    !chunk_memcat(chk, "\r\n", 2))
735 			goto full;
736 	}
737 	else {
738 		if (!chunk_memcat(chk, data.ptr, data.len))
739 			return 0;
740 	}
741 
742 	return 1;
743 
744   full:
745 	chk->data = sz;
746 	return 0;
747 }
748 
749 /*
750  * Local variables:
751  *  c-indent-level: 8
752  *  c-basic-offset: 8
753  * End:
754  */
755