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 <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. */
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  * successfull 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 		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 
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 	/* 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  */
h1_postparse_res_hdrs(struct h1m * h1m,union h1_sl * h1sl,struct htx * htx,struct http_hdr * hdrs,size_t max)227 static 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  */
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 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 
384   end:
385 	return ret;
386   error:
387 	h1m->err_pos = h1m->next;
388 	h1m->err_state = h1m->state;
389   vsn_error:
390 	dsthtx->flags |= HTX_FL_PARSING_ERROR;
391 	return 0;
392 
393 }
394 
395 /* Copy data from <srbuf> into an DATA block in <dsthtx>. If possible, a
396  * zero-copy is performed. It returns the number of bytes copied.
397  */
h1_copy_msg_data(struct htx ** dsthtx,struct buffer * srcbuf,size_t ofs,size_t count,struct buffer * htxbuf)398 static int h1_copy_msg_data(struct htx **dsthtx, struct buffer *srcbuf, size_t ofs,
399 			    size_t count, struct buffer *htxbuf)
400 {
401 	struct htx *tmp_htx = *dsthtx;
402 
403 	/* very often with large files we'll face the following
404 	 * situation :
405 	 *   - htx is empty and points to <htxbuf>
406 	 *   - ret == srcbuf->data
407 	 *   - srcbuf->head == sizeof(struct htx)
408 	 *   => we can swap the buffers and place an htx header into
409 	 *      the target buffer instead
410 	 */
411 	if (unlikely(htx_is_empty(tmp_htx) && count == b_data(srcbuf) &&
412 		     !ofs && b_head_ofs(srcbuf) == sizeof(struct htx))) {
413 		void *raw_area = srcbuf->area;
414 		void *htx_area = htxbuf->area;
415 		struct htx_blk *blk;
416 
417 		srcbuf->area = htx_area;
418 		htxbuf->area = raw_area;
419 		tmp_htx = (struct htx *)htxbuf->area;
420 		tmp_htx->size = htxbuf->size - sizeof(*tmp_htx);
421 		htx_reset(tmp_htx);
422 		b_set_data(htxbuf, b_size(htxbuf));
423 
424 		blk = htx_add_blk(tmp_htx, HTX_BLK_DATA, count);
425 		blk->info += count;
426 
427 		*dsthtx = tmp_htx;
428 		/* nothing else to do, the old buffer now contains an
429 		 * empty pre-initialized HTX header
430 		 */
431 		return count;
432 	}
433 
434 	return htx_add_data(*dsthtx, ist2(b_peek(srcbuf, ofs), count));
435 }
436 
437 /* Parse HTTP/1 body. It returns the number of bytes parsed if > 0, or 0 if it
438  * couldn't proceed. Parsing errors are reported by setting the htx flags
439  * HTX_FL_PARSING_ERROR and filling h1m->err_pos and h1m->err_state fields. This
440  * functions is responsible to update the parser state <h1m>.
441  */
h1_parse_msg_data(struct h1m * h1m,struct htx ** dsthtx,struct buffer * srcbuf,size_t ofs,size_t max,struct buffer * htxbuf)442 int h1_parse_msg_data(struct h1m *h1m, struct htx **dsthtx,
443 		      struct buffer *srcbuf, size_t ofs, size_t max,
444 		      struct buffer *htxbuf)
445 {
446 	size_t total = 0;
447 	int32_t ret = 0;
448 
449 	if (h1m->flags & H1_MF_CLEN) {
450 		/* content-length: read only h2m->body_len */
451 		ret = htx_get_max_blksz(*dsthtx, max);
452 		if ((uint64_t)ret > h1m->curr_len)
453 			ret = h1m->curr_len;
454 		if (ret > b_contig_data(srcbuf, ofs))
455 			ret = b_contig_data(srcbuf, ofs);
456 		if (ret) {
457 			int32_t try = ret;
458 
459 			ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
460 			h1m->curr_len -= ret;
461 			max -= sizeof(struct htx_blk) + ret;
462 			ofs += ret;
463 			total += ret;
464 			if (ret < try)
465 				goto end;
466 		}
467 
468 		if (!h1m->curr_len) {
469 			if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(*dsthtx, HTX_BLK_EOM))
470 				goto end;
471 			h1m->state = H1_MSG_DONE;
472 		}
473 	}
474 	else if (h1m->flags & H1_MF_CHNK) {
475 		/* te:chunked : parse chunks */
476 	  new_chunk:
477 		if (h1m->state == H1_MSG_CHUNK_CRLF) {
478 			ret = h1_skip_chunk_crlf(srcbuf, ofs, b_data(srcbuf));
479 			if (ret <= 0)
480 				goto end;
481 			h1m->state = H1_MSG_CHUNK_SIZE;
482 			ofs += ret;
483 			total += ret;
484 		}
485 		if (h1m->state == H1_MSG_CHUNK_SIZE) {
486 			unsigned int chksz;
487 
488 			ret = h1_parse_chunk_size(srcbuf, ofs, b_data(srcbuf), &chksz);
489 			if (ret <= 0)
490 				goto end;
491 			h1m->state = ((!chksz) ? H1_MSG_TRAILERS : H1_MSG_DATA);
492 			h1m->curr_len  = chksz;
493 			h1m->body_len += chksz;
494 			ofs += ret;
495 			total += ret;
496 			if (!h1m->curr_len)
497 				goto end;
498 		}
499 		if (h1m->state == H1_MSG_DATA) {
500 			ret = htx_get_max_blksz(*dsthtx, max);
501 			if ((uint64_t)ret > h1m->curr_len)
502 				ret = h1m->curr_len;
503 			if (ret > b_contig_data(srcbuf, ofs))
504 				ret = b_contig_data(srcbuf, ofs);
505 			if (ret) {
506 				int32_t try = ret;
507 
508 				ret = h1_copy_msg_data(dsthtx, srcbuf, ofs, try, htxbuf);
509 				h1m->curr_len -= ret;
510 				max -= sizeof(struct htx_blk) + ret;
511 				ofs += ret;
512 				total += ret;
513 				if (ret < try)
514 					goto end;
515 			}
516 			if (!h1m->curr_len) {
517 				h1m->state = H1_MSG_CHUNK_CRLF;
518 				goto new_chunk;
519 			}
520 			goto end;
521 		}
522 	}
523 	else if (h1m->flags & H1_MF_XFER_LEN) {
524 		/* XFER_LEN is set but not CLEN nor CHNK, it means there is no
525 		 * body. Switch the message in DONE state
526 		 */
527 		if (max < sizeof(struct htx_blk) + 1 || !htx_add_endof(*dsthtx, HTX_BLK_EOM))
528 			goto end;
529 		h1m->state = H1_MSG_DONE;
530 	}
531 	else {
532 		/* no content length, read till SHUTW */
533 		ret = htx_get_max_blksz(*dsthtx, max);
534 		if (ret > b_contig_data(srcbuf, ofs))
535 			ret = b_contig_data(srcbuf, ofs);
536 		if (ret)
537 			total += h1_copy_msg_data(dsthtx, srcbuf, ofs, ret, htxbuf);
538 	}
539 
540   end:
541 	if (ret < 0) {
542 		(*dsthtx)->flags |= HTX_FL_PARSING_ERROR;
543 		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)
550 		(*dsthtx)->extra = h1m->curr_len;
551 	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  */
h1_parse_msg_tlrs(struct h1m * h1m,struct htx * dsthtx,struct buffer * srcbuf,size_t ofs,size_t max)559 int 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 
597   end:
598 	return ret;
599   error:
600 	h1m->err_state = h1m->state;
601 	h1m->err_pos = h1m->next;
602 	dsthtx->flags |= HTX_FL_PARSING_ERROR;
603 	return 0;
604 }
605 
606 
607 /* Appends the H1 representation of the request line <sl> to the chunk <chk>. It
608  * returns 1 if data are successfully appended, otherwise it returns 0.
609  */
h1_format_htx_reqline(const struct htx_sl * sl,struct buffer * chk)610 int h1_format_htx_reqline(const struct htx_sl *sl, struct buffer *chk)
611 {
612 	struct ist uri;
613 	size_t sz = chk->data;
614 
615 	uri = htx_sl_req_uri(sl);
616 	if (sl->flags & HTX_SL_F_NORMALIZED_URI) {
617 		uri = http_get_path(uri);
618 		if (unlikely(!uri.len)) {
619 			if (sl->info.req.meth == HTTP_METH_OPTIONS)
620 				uri = ist("*");
621 			else
622 				uri = ist("/");
623 		}
624 	}
625 
626 	if (!chunk_memcat(chk, HTX_SL_REQ_MPTR(sl), HTX_SL_REQ_MLEN(sl)) ||
627 	    !chunk_memcat(chk, " ", 1) ||
628 	    !chunk_memcat(chk, uri.ptr, uri.len) ||
629 	    !chunk_memcat(chk, " ", 1))
630 		goto full;
631 
632 	if (sl->flags & HTX_SL_F_VER_11) {
633 		if (!chunk_memcat(chk, "HTTP/1.1", 8))
634 			goto full;
635 	}
636 	else {
637 		if (!chunk_memcat(chk, HTX_SL_REQ_VPTR(sl), HTX_SL_REQ_VLEN(sl)))
638 			goto full;
639 	}
640 
641 	if (!chunk_memcat(chk, "\r\n", 2))
642 		goto full;
643 
644 	return 1;
645 
646   full:
647 	chk->data = sz;
648 	return 0;
649 }
650 
651 /* Appends the H1 representation of the status line <sl> to the chunk <chk>. It
652  * returns 1 if data are successfully appended, otherwise it returns 0.
653  */
h1_format_htx_stline(const struct htx_sl * sl,struct buffer * chk)654 int h1_format_htx_stline(const struct htx_sl *sl, struct buffer *chk)
655 {
656 	size_t sz = chk->data;
657 
658 	if (HTX_SL_LEN(sl) + 4 > b_room(chk))
659 		return 0;
660 
661 	if (sl->flags & HTX_SL_F_VER_11) {
662 		if (!chunk_memcat(chk, "HTTP/1.1", 8))
663 			goto full;
664 	}
665 	else {
666 		if (!chunk_memcat(chk, HTX_SL_RES_VPTR(sl), HTX_SL_RES_VLEN(sl)))
667 			goto full;
668 	}
669 	if (!chunk_memcat(chk, " ", 1) ||
670 	    !chunk_memcat(chk, HTX_SL_RES_CPTR(sl), HTX_SL_RES_CLEN(sl)) ||
671 	    !chunk_memcat(chk, " ", 1) ||
672 	    !chunk_memcat(chk, HTX_SL_RES_RPTR(sl), HTX_SL_RES_RLEN(sl)) ||
673 	    !chunk_memcat(chk, "\r\n", 2))
674 		goto full;
675 
676 	return 1;
677 
678   full:
679 	chk->data = sz;
680 	return 0;
681 }
682 
683 /* Appends the H1 representation of the header <n> witht the value <v> to the
684  * chunk <chk>. It returns 1 if data are successfully appended, otherwise it
685  * returns 0.
686  */
h1_format_htx_hdr(const struct ist n,const struct ist v,struct buffer * chk)687 int h1_format_htx_hdr(const struct ist n, const struct ist v, struct buffer *chk)
688 {
689 	size_t sz = chk->data;
690 
691 	if (n.len + v.len + 4 > b_room(chk))
692 		return 0;
693 
694 	if (!chunk_memcat(chk, n.ptr, n.len) ||
695 	    !chunk_memcat(chk, ": ", 2) ||
696 	    !chunk_memcat(chk, v.ptr, v.len) ||
697 	    !chunk_memcat(chk, "\r\n", 2))
698 		goto full;
699 
700 	return 1;
701 
702   full:
703 	chk->data = sz;
704 	return 0;
705 }
706 
707 /* Appends the H1 representation of the data <data> to the chunk <chk>. If
708  * <chunked> is non-zero, it emits HTTP/1 chunk-encoded data. It returns 1 if
709  * data are successfully appended, otherwise it returns 0.
710  */
h1_format_htx_data(const struct ist data,struct buffer * chk,int chunked)711 int h1_format_htx_data(const struct ist data, struct buffer *chk, int chunked)
712 {
713 	size_t sz = chk->data;
714 
715 	if (chunked) {
716 		uint32_t chksz;
717 		char     tmp[10];
718 		char    *beg, *end;
719 
720 		chksz = data.len;
721 
722 		beg = end = tmp+10;
723 		*--beg = '\n';
724 		*--beg = '\r';
725 		do {
726 			*--beg = hextab[chksz & 0xF];
727 		} while (chksz >>= 4);
728 
729 		if (!chunk_memcat(chk, beg, end - beg) ||
730 		    !chunk_memcat(chk, data.ptr, data.len) ||
731 		    !chunk_memcat(chk, "\r\n", 2))
732 			goto full;
733 	}
734 	else {
735 		if (!chunk_memcat(chk, data.ptr, data.len))
736 			return 0;
737 	}
738 
739 	return 1;
740 
741   full:
742 	chk->data = sz;
743 	return 0;
744 }
745 
746 /*
747  * Local variables:
748  *  c-indent-level: 8
749  *  c-basic-offset: 8
750  * End:
751  */
752