1 #include "request.h"
2 #include "keyvalue.h"
3 #include "log.h"
4 
5 #include <sys/stat.h>
6 
7 #include <limits.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <stdio.h>
11 #include <ctype.h>
12 
request_check_hostname(server * srv,connection * con,buffer * host)13 static int request_check_hostname(server *srv, connection *con, buffer *host) {
14 	enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
15 	size_t i;
16 	int label_len = 0;
17 	size_t host_len;
18 	char *colon;
19 	int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
20 	int level = 0;
21 
22 	UNUSED(srv);
23 	UNUSED(con);
24 
25 	/*
26 	 *       hostport      = host [ ":" port ]
27 	 *       host          = hostname | IPv4address | IPv6address
28 	 *       hostname      = *( domainlabel "." ) toplabel [ "." ]
29 	 *       domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
30 	 *       toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
31 	 *       IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
32 	 *       IPv6address   = "[" ... "]"
33 	 *       port          = *digit
34 	 */
35 
36 	/* no Host: */
37 	if (!host || host->used == 0) return 0;
38 
39 	host_len = host->used - 1;
40 
41 	/* IPv6 adress */
42 	if (host->ptr[0] == '[') {
43 		char *c = host->ptr + 1;
44 		int colon_cnt = 0;
45 
46 		/* check portnumber */
47 		for (; *c && *c != ']'; c++) {
48 			if (*c == ':') {
49 				if (++colon_cnt > 7) {
50 					return -1;
51 				}
52 			} else if (!light_isxdigit(*c) && '.' != *c) {
53 				return -1;
54 			}
55 		}
56 
57 		/* missing ] */
58 		if (!*c) {
59 			return -1;
60 		}
61 
62 		/* check port */
63 		if (*(c+1) == ':') {
64 			for (c += 2; *c; c++) {
65 				if (!light_isdigit(*c)) {
66 					return -1;
67 				}
68 			}
69 		}
70 		return 0;
71 	}
72 
73 	if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
74 		char *c = colon + 1;
75 
76 		/* check portnumber */
77 		for (; *c; c++) {
78 			if (!light_isdigit(*c)) return -1;
79 		}
80 
81 		/* remove the port from the host-len */
82 		host_len = colon - host->ptr;
83 	}
84 
85 	/* Host is empty */
86 	if (host_len == 0) return -1;
87 
88 	/* if the hostname ends in a "." strip it */
89 	if (host->ptr[host_len-1] == '.') {
90 		/* shift port info one left */
91 		if (NULL != colon) memmove(colon-1, colon, host->used - host_len);
92 		else host->ptr[host_len-1] = '\0';
93 		host_len -= 1;
94 		host->used -= 1;
95 	}
96 
97 	if (host_len == 0) return -1;
98 
99 	/* scan from the right and skip the \0 */
100 	for (i = host_len; i-- > 0; ) {
101 		const char c = host->ptr[i];
102 
103 		switch (stage) {
104 		case TOPLABEL:
105 			if (c == '.') {
106 				/* only switch stage, if this is not the last character */
107 				if (i != host_len - 1) {
108 					if (label_len == 0) {
109 						return -1;
110 					}
111 
112 					/* check the first character at right of the dot */
113 					if (is_ip == 0) {
114 						if (!light_isalnum(host->ptr[i+1])) {
115 							return -1;
116 						}
117 					} else if (!light_isdigit(host->ptr[i+1])) {
118 						is_ip = 0;
119 					} else if ('-' == host->ptr[i+1]) {
120 						return -1;
121 					} else {
122 						/* just digits */
123 						is_ip = 1;
124 					}
125 
126 					stage = DOMAINLABEL;
127 
128 					label_len = 0;
129 					level++;
130 				} else if (i == 0) {
131 					/* just a dot and nothing else is evil */
132 					return -1;
133 				}
134 			} else if (i == 0) {
135 				/* the first character of the hostname */
136 				if (!light_isalnum(c)) {
137 					return -1;
138 				}
139 				label_len++;
140 			} else {
141 				if (c != '-' && !light_isalnum(c)) {
142 					return -1;
143 				}
144 				if (is_ip == -1) {
145 					if (!light_isdigit(c)) is_ip = 0;
146 				}
147 				label_len++;
148 			}
149 
150 			break;
151 		case DOMAINLABEL:
152 			if (is_ip == 1) {
153 				if (c == '.') {
154 					if (label_len == 0) {
155 						return -1;
156 					}
157 
158 					label_len = 0;
159 					level++;
160 				} else if (!light_isdigit(c)) {
161 					return -1;
162 				} else {
163 					label_len++;
164 				}
165 			} else {
166 				if (c == '.') {
167 					if (label_len == 0) {
168 						return -1;
169 					}
170 
171 					/* c is either - or alphanum here */
172 					if ('-' == host->ptr[i+1]) {
173 						return -1;
174 					}
175 
176 					label_len = 0;
177 					level++;
178 				} else if (i == 0) {
179 					if (!light_isalnum(c)) {
180 						return -1;
181 					}
182 					label_len++;
183 				} else {
184 					if (c != '-' && !light_isalnum(c)) {
185 						return -1;
186 					}
187 					label_len++;
188 				}
189 			}
190 
191 			break;
192 		}
193 	}
194 
195 	/* a IP has to consist of 4 parts */
196 	if (is_ip == 1 && level != 3) {
197 		return -1;
198 	}
199 
200 	if (label_len == 0) {
201 		return -1;
202 	}
203 
204 	return 0;
205 }
206 
207 #if 0
208 #define DUMP_HEADER
209 #endif
210 
http_request_split_value(array * vals,buffer * b)211 static int http_request_split_value(array *vals, buffer *b) {
212 	size_t i;
213 	int state = 0;
214 
215 	const char *current;
216 	const char *token_start = NULL, *token_end = NULL;
217 	/*
218 	 * parse
219 	 *
220 	 * val1, val2, val3, val4
221 	 *
222 	 * into a array (more or less a explode() incl. striping of whitespaces
223 	 */
224 
225 	if (b->used == 0) return 0;
226 
227 	current = b->ptr;
228 	for (i =  0; i < b->used; ++i, ++current) {
229 		data_string *ds;
230 
231 		switch (state) {
232 		case 0: /* find start of a token */
233 			switch (*current) {
234 			case ' ':
235 			case '\t': /* skip white space */
236 			case ',': /* skip empty token */
237 				break;
238 			case '\0': /* end of string */
239 				return 0;
240 			default:
241 				/* found real data, switch to state 1 to find the end of the token */
242 				token_start = token_end = current;
243 				state = 1;
244 				break;
245 			}
246 			break;
247 		case 1: /* find end of token and last non white space character */
248 			switch (*current) {
249 			case ' ':
250 			case '\t':
251 				/* space - don't update token_end */
252 				break;
253 			case ',':
254 			case '\0': /* end of string also marks the end of a token */
255 				if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
256 					ds = data_string_init();
257 				}
258 
259 				buffer_copy_string_len(ds->value, token_start, token_end-token_start+1);
260 				array_insert_unique(vals, (data_unset *)ds);
261 
262 				state = 0;
263 				break;
264 			default:
265 				/* no white space, update token_end to include current character */
266 				token_end = current;
267 				break;
268 			}
269 			break;
270 		}
271 	}
272 
273 	return 0;
274 }
275 
request_uri_is_valid_char(unsigned char c)276 static int request_uri_is_valid_char(unsigned char c) {
277 	if (c <= 32) return 0;
278 	if (c == 127) return 0;
279 	if (c == 255) return 0;
280 
281 	return 1;
282 }
283 
http_request_parse(server * srv,connection * con)284 int http_request_parse(server *srv, connection *con) {
285 	char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
286 	int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
287 	char *value = NULL, *key = NULL;
288 	char *reqline_host = NULL;
289 	int reqline_hostlen = 0;
290 
291 	enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
292 
293 	int line = 0;
294 
295 	int request_line_stage = 0;
296 	size_t i, first;
297 
298 	int done = 0;
299 
300 	/*
301 	 * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
302 	 * Option : "^([-a-zA-Z]+): (.+)$"
303 	 * End    : "^$"
304 	 */
305 
306 	if (con->conf.log_request_header) {
307 		log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
308 				"fd:", con->fd,
309 				"request-len:", con->request.request->used,
310 				"\n", con->request.request);
311 	}
312 
313 	if (con->request_count > 1 &&
314 	    con->request.request->ptr[0] == '\r' &&
315 	    con->request.request->ptr[1] == '\n') {
316 		/* we are in keep-alive and might get \r\n after a previous POST request.*/
317 
318 		buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
319 	} else {
320 		/* fill the local request buffer */
321 		buffer_copy_string_buffer(con->parse_request, con->request.request);
322 	}
323 
324 	keep_alive_set = 0;
325 	con_length_set = 0;
326 
327 	/* parse the first line of the request
328 	 *
329 	 * should be:
330 	 *
331 	 * <method> <uri> <protocol>\r\n
332 	 * */
333 	for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
334 		char *cur = con->parse_request->ptr + i;
335 
336 		switch(*cur) {
337 		case '\r':
338 			if (con->parse_request->ptr[i+1] == '\n') {
339 				http_method_t r;
340 				char *nuri = NULL;
341 				size_t j;
342 
343 				/* \r\n -> \0\0 */
344 				con->parse_request->ptr[i] = '\0';
345 				con->parse_request->ptr[i+1] = '\0';
346 
347 				buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
348 
349 				if (request_line_stage != 2) {
350 					con->http_status = 400;
351 					con->response.keep_alive = 0;
352 					con->keep_alive = 0;
353 
354 					if (srv->srvconf.log_request_header_on_error) {
355 						log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
356 						log_error_write(srv, __FILE__, __LINE__, "Sb",
357 								"request-header:\n",
358 								con->request.request);
359 					}
360 					return 0;
361 				}
362 
363 				proto = con->parse_request->ptr + first;
364 
365 				*(uri - 1) = '\0';
366 				*(proto - 1) = '\0';
367 
368 				/* we got the first one :) */
369 				if (-1 == (r = get_http_method_key(method))) {
370 					con->http_status = 501;
371 					con->response.keep_alive = 0;
372 					con->keep_alive = 0;
373 
374 					if (srv->srvconf.log_request_header_on_error) {
375 						log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
376 						log_error_write(srv, __FILE__, __LINE__, "Sb",
377 								"request-header:\n",
378 								con->request.request);
379 					}
380 
381 					return 0;
382 				}
383 
384 				con->request.http_method = r;
385 
386 				/*
387 				 * RFC2616 says:
388 				 *
389 				 * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
390 				 *
391 				 * */
392 				if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
393 					char * major = proto + sizeof("HTTP/") - 1;
394 					char * minor = strchr(major, '.');
395 					char *err = NULL;
396 					int major_num = 0, minor_num = 0;
397 
398 					int invalid_version = 0;
399 
400 					if (NULL == minor || /* no dot */
401 					    minor == major || /* no major */
402 					    *(minor + 1) == '\0' /* no minor */) {
403 						invalid_version = 1;
404 					} else {
405 						*minor = '\0';
406 						major_num = strtol(major, &err, 10);
407 
408 						if (*err != '\0') invalid_version = 1;
409 
410 						*minor++ = '.';
411 						minor_num = strtol(minor, &err, 10);
412 
413 						if (*err != '\0') invalid_version = 1;
414 					}
415 
416 					if (invalid_version) {
417 						con->http_status = 400;
418 						con->keep_alive = 0;
419 
420 						if (srv->srvconf.log_request_header_on_error) {
421 							log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
422 							log_error_write(srv, __FILE__, __LINE__, "Sb",
423 									"request-header:\n",
424 									con->request.request);
425 						}
426 						return 0;
427 					}
428 
429 					if (major_num == 1 && minor_num == 1) {
430 						con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
431 					} else if (major_num == 1 && minor_num == 0) {
432 						con->request.http_version = HTTP_VERSION_1_0;
433 					} else {
434 						con->http_status = 505;
435 
436 						if (srv->srvconf.log_request_header_on_error) {
437 							log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
438 							log_error_write(srv, __FILE__, __LINE__, "Sb",
439 									"request-header:\n",
440 									con->request.request);
441 						}
442 						return 0;
443 					}
444 				} else {
445 					con->http_status = 400;
446 					con->keep_alive = 0;
447 
448 					if (srv->srvconf.log_request_header_on_error) {
449 						log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
450 						log_error_write(srv, __FILE__, __LINE__, "Sb",
451 								"request-header:\n",
452 								con->request.request);
453 					}
454 					return 0;
455 				}
456 
457 				if (0 == strncmp(uri, "http://", 7) &&
458 				    NULL != (nuri = strchr(uri + 7, '/'))) {
459 					reqline_host = uri + 7;
460 					reqline_hostlen = nuri - reqline_host;
461 
462 					buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
463 				} else if (0 == strncmp(uri, "https://", 8) &&
464 				    NULL != (nuri = strchr(uri + 8, '/'))) {
465 					reqline_host = uri + 8;
466 					reqline_hostlen = nuri - reqline_host;
467 
468 					buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
469 				} else {
470 					/* everything looks good so far */
471 					buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
472 				}
473 
474 				/* check uri for invalid characters */
475 				for (j = 0; j < con->request.uri->used - 1; j++) {
476 					if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
477 						unsigned char buf[2];
478 						con->http_status = 400;
479 						con->keep_alive = 0;
480 
481 						if (srv->srvconf.log_request_header_on_error) {
482 							buf[0] = con->request.uri->ptr[j];
483 							buf[1] = '\0';
484 
485 							if (con->request.uri->ptr[j] > 32 &&
486 							    con->request.uri->ptr[j] != 127) {
487 								/* the character is printable -> print it */
488 								log_error_write(srv, __FILE__, __LINE__, "ss",
489 										"invalid character in URI -> 400",
490 										buf);
491 							} else {
492 								/* a control-character, print ascii-code */
493 								log_error_write(srv, __FILE__, __LINE__, "sd",
494 										"invalid character in URI -> 400",
495 										con->request.uri->ptr[j]);
496 							}
497 
498 							log_error_write(srv, __FILE__, __LINE__, "Sb",
499 									"request-header:\n",
500 									con->request.request);
501 						}
502 
503 						return 0;
504 					}
505 				}
506 
507 				buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
508 
509 				con->http_status = 0;
510 
511 				i++;
512 				line++;
513 				first = i+1;
514 			}
515 			break;
516 		case ' ':
517 			switch(request_line_stage) {
518 			case 0:
519 				/* GET|POST|... */
520 				method = con->parse_request->ptr + first;
521 				first = i + 1;
522 				break;
523 			case 1:
524 				/* /foobar/... */
525 				uri = con->parse_request->ptr + first;
526 				first = i + 1;
527 				break;
528 			default:
529 				/* ERROR, one space to much */
530 				con->http_status = 400;
531 				con->response.keep_alive = 0;
532 				con->keep_alive = 0;
533 
534 				if (srv->srvconf.log_request_header_on_error) {
535 					log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
536 					log_error_write(srv, __FILE__, __LINE__, "Sb",
537 							"request-header:\n",
538 							con->request.request);
539 				}
540 				return 0;
541 			}
542 
543 			request_line_stage++;
544 			break;
545 		}
546 	}
547 
548 	in_folding = 0;
549 
550 	if (con->request.uri->used == 1) {
551 		con->http_status = 400;
552 		con->response.keep_alive = 0;
553 		con->keep_alive = 0;
554 
555 		if (srv->srvconf.log_request_header_on_error) {
556 			log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
557 			log_error_write(srv, __FILE__, __LINE__, "Sb",
558 							"request-header:\n",
559 							con->request.request);
560 		}
561 		return 0;
562 	}
563 
564 	if (reqline_host) {
565 		/* Insert as host header */
566 		data_string *ds;
567 
568 		if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
569 			ds = data_string_init();
570 		}
571 
572 		buffer_copy_string_len(ds->key, CONST_STR_LEN("Host"));
573 		buffer_copy_string_len(ds->value, reqline_host, reqline_hostlen);
574 		array_insert_unique(con->request.headers, (data_unset *)ds);
575 		con->request.http_host = ds->value;
576 	}
577 
578 	for (; i < con->parse_request->used && !done; i++) {
579 		char *cur = con->parse_request->ptr + i;
580 
581 		if (is_key) {
582 			size_t j;
583 			int got_colon = 0;
584 
585 			/**
586 			 * 1*<any CHAR except CTLs or separators>
587 			 * CTLs == 0-31 + 127
588 			 *
589 			 */
590 			switch(*cur) {
591 			case ':':
592 				is_key = 0;
593 
594 				value = cur + 1;
595 
596 				if (is_ws_after_key == 0) {
597 					key_len = i - first;
598 				}
599 				is_ws_after_key = 0;
600 
601 				break;
602 			case '(':
603 			case ')':
604 			case '<':
605 			case '>':
606 			case '@':
607 			case ',':
608 			case ';':
609 			case '\\':
610 			case '\"':
611 			case '/':
612 			case '[':
613 			case ']':
614 			case '?':
615 			case '=':
616 			case '{':
617 			case '}':
618 				con->http_status = 400;
619 				con->keep_alive = 0;
620 				con->response.keep_alive = 0;
621 
622 				log_error_write(srv, __FILE__, __LINE__, "sbsds",
623 						"invalid character in key", con->request.request, cur, *cur, "-> 400");
624 				return 0;
625 			case ' ':
626 			case '\t':
627 				if (i == first) {
628 					is_key = 0;
629 					in_folding = 1;
630 					value = cur;
631 
632 					break;
633 				}
634 
635 
636 				key_len = i - first;
637 
638 				/* skip every thing up to the : */
639 				for (j = 1; !got_colon; j++) {
640 					switch(con->parse_request->ptr[j + i]) {
641 					case ' ':
642 					case '\t':
643 						/* skip WS */
644 						continue;
645 					case ':':
646 						/* ok, done; handle the colon the usual way */
647 
648 						i += j - 1;
649 						got_colon = 1;
650 						is_ws_after_key = 1; /* we already know the key length */
651 
652 						break;
653 					default:
654 						/* error */
655 
656 						if (srv->srvconf.log_request_header_on_error) {
657 							log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
658 							log_error_write(srv, __FILE__, __LINE__, "Sb",
659 								"request-header:\n",
660 								con->request.request);
661 						}
662 
663 						con->http_status = 400;
664 						con->response.keep_alive = 0;
665 						con->keep_alive = 0;
666 
667 						return 0;
668 					}
669 				}
670 
671 				break;
672 			case '\r':
673 				if (con->parse_request->ptr[i+1] == '\n' && i == first) {
674 					/* End of Header */
675 					con->parse_request->ptr[i] = '\0';
676 					con->parse_request->ptr[i+1] = '\0';
677 
678 					i++;
679 
680 					done = 1;
681 
682 					break;
683 				} else {
684 					if (srv->srvconf.log_request_header_on_error) {
685 						log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
686 						log_error_write(srv, __FILE__, __LINE__, "Sb",
687 							"request-header:\n",
688 							con->request.request);
689 					}
690 
691 					con->http_status = 400;
692 					con->keep_alive = 0;
693 					con->response.keep_alive = 0;
694 					return 0;
695 				}
696 				/* fall thru */
697 			case 0: /* illegal characters (faster than a if () :) */
698 			case 1:
699 			case 2:
700 			case 3:
701 			case 4:
702 			case 5:
703 			case 6:
704 			case 7:
705 			case 8:
706 			case 10:
707 			case 11:
708 			case 12:
709 			case 14:
710 			case 15:
711 			case 16:
712 			case 17:
713 			case 18:
714 			case 19:
715 			case 20:
716 			case 21:
717 			case 22:
718 			case 23:
719 			case 24:
720 			case 25:
721 			case 26:
722 			case 27:
723 			case 28:
724 			case 29:
725 			case 30:
726 			case 31:
727 			case 127:
728 				con->http_status = 400;
729 				con->keep_alive = 0;
730 				con->response.keep_alive = 0;
731 
732 				if (srv->srvconf.log_request_header_on_error) {
733 					log_error_write(srv, __FILE__, __LINE__, "sbsds",
734 						"CTL character in key", con->request.request, cur, *cur, "-> 400");
735 
736 					log_error_write(srv, __FILE__, __LINE__, "Sb",
737 						"request-header:\n",
738 						con->request.request);
739 				}
740 
741 				return 0;
742 			default:
743 				/* ok */
744 				break;
745 			}
746 		} else {
747 			switch(*cur) {
748 			case '\r':
749 				if (con->parse_request->ptr[i+1] == '\n') {
750 					data_string *ds = NULL;
751 
752 					/* End of Headerline */
753 					con->parse_request->ptr[i] = '\0';
754 					con->parse_request->ptr[i+1] = '\0';
755 
756 					if (in_folding) {
757 						buffer *key_b;
758 						/**
759 						 * we use a evil hack to handle the line-folding
760 						 *
761 						 * As array_insert_unique() deletes 'ds' in the case of a duplicate
762 						 * ds points somewhere and we get a evil crash. As a solution we keep the old
763 						 * "key" and get the current value from the hash and append us
764 						 *
765 						 * */
766 
767 						if (!key || !key_len) {
768 							/* 400 */
769 
770 							if (srv->srvconf.log_request_header_on_error) {
771 								log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
772 
773 								log_error_write(srv, __FILE__, __LINE__, "Sb",
774 									"request-header:\n",
775 									con->request.request);
776 							}
777 
778 
779 							con->http_status = 400;
780 							con->keep_alive = 0;
781 							con->response.keep_alive = 0;
782 							return 0;
783 						}
784 
785 						key_b = buffer_init();
786 						buffer_copy_string_len(key_b, key, key_len);
787 
788 						if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key_b->ptr))) {
789 							buffer_append_string(ds->value, value);
790 						}
791 
792 						buffer_free(key_b);
793 					} else {
794 						int s_len;
795 						key = con->parse_request->ptr + first;
796 
797 						s_len = cur - value;
798 
799 						/* strip trailing white-spaces */
800 						for (; s_len > 0 &&
801 								(value[s_len - 1] == ' ' ||
802 								 value[s_len - 1] == '\t'); s_len--);
803 
804 						value[s_len] = '\0';
805 
806 						if (s_len > 0) {
807 							int cmp = 0;
808 							if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
809 								ds = data_string_init();
810 							}
811 							buffer_copy_string_len(ds->key, key, key_len);
812 							buffer_copy_string_len(ds->value, value, s_len);
813 
814 							/* retreive values
815 							 *
816 							 *
817 							 * the list of options is sorted to simplify the search
818 							 */
819 
820 							if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
821 								array *vals;
822 								size_t vi;
823 
824 								/* split on , */
825 
826 								vals = srv->split_vals;
827 
828 								array_reset(vals);
829 
830 								http_request_split_value(vals, ds->value);
831 
832 								for (vi = 0; vi < vals->used; vi++) {
833 									data_string *dsv = (data_string *)vals->data[vi];
834 
835 									if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
836 										keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
837 
838 										break;
839 									} else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
840 										keep_alive_set = HTTP_CONNECTION_CLOSE;
841 
842 										break;
843 									}
844 								}
845 
846 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
847 								char *err;
848 								unsigned long int r;
849 								size_t j;
850 
851 								if (con_length_set) {
852 									con->http_status = 400;
853 									con->keep_alive = 0;
854 
855 									if (srv->srvconf.log_request_header_on_error) {
856 										log_error_write(srv, __FILE__, __LINE__, "s",
857 												"duplicate Content-Length-header -> 400");
858 										log_error_write(srv, __FILE__, __LINE__, "Sb",
859 												"request-header:\n",
860 												con->request.request);
861 									}
862 									array_insert_unique(con->request.headers, (data_unset *)ds);
863 									return 0;
864 								}
865 
866 								if (ds->value->used == 0) SEGFAULT();
867 
868 								for (j = 0; j < ds->value->used - 1; j++) {
869 									char c = ds->value->ptr[j];
870 									if (!isdigit((unsigned char)c)) {
871 										log_error_write(srv, __FILE__, __LINE__, "sbs",
872 												"content-length broken:", ds->value, "-> 400");
873 
874 										con->http_status = 400;
875 										con->keep_alive = 0;
876 
877 										array_insert_unique(con->request.headers, (data_unset *)ds);
878 										return 0;
879 									}
880 								}
881 
882 								r = strtoul(ds->value->ptr, &err, 10);
883 
884 								if (*err == '\0') {
885 									con_length_set = 1;
886 									con->request.content_length = r;
887 								} else {
888 									log_error_write(srv, __FILE__, __LINE__, "sbs",
889 											"content-length broken:", ds->value, "-> 400");
890 
891 									con->http_status = 400;
892 									con->keep_alive = 0;
893 
894 									array_insert_unique(con->request.headers, (data_unset *)ds);
895 									return 0;
896 								}
897 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
898 								/* if dup, only the first one will survive */
899 								if (!con->request.http_content_type) {
900 									con->request.http_content_type = ds->value->ptr;
901 								} else {
902 									con->http_status = 400;
903 									con->keep_alive = 0;
904 
905 									if (srv->srvconf.log_request_header_on_error) {
906 										log_error_write(srv, __FILE__, __LINE__, "s",
907 												"duplicate Content-Type-header -> 400");
908 										log_error_write(srv, __FILE__, __LINE__, "Sb",
909 												"request-header:\n",
910 												con->request.request);
911 									}
912 									array_insert_unique(con->request.headers, (data_unset *)ds);
913 									return 0;
914 								}
915 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
916 								/* HTTP 2616 8.2.3
917 								 * Expect: 100-continue
918 								 *
919 								 *   -> (10.1.1)  100 (read content, process request, send final status-code)
920 								 *   -> (10.4.18) 417 (close)
921 								 *
922 								 * (not handled at all yet, we always send 417 here)
923 								 *
924 								 * What has to be added ?
925 								 * 1. handling of chunked request body
926 								 * 2. out-of-order sending from the HTTP/1.1 100 Continue
927 								 *    header
928 								 *
929 								 */
930 
931 								if (srv->srvconf.reject_expect_100_with_417 && 0 == buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
932 									con->http_status = 417;
933 									con->keep_alive = 0;
934 									array_insert_unique(con->request.headers, (data_unset *)ds);
935 									return 0;
936 								}
937 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
938 								if (reqline_host) {
939 									/* ignore all host: headers as we got the host in the request line */
940 									ds->free((data_unset*) ds);
941 									ds = NULL;
942 								} else if (!con->request.http_host) {
943 									con->request.http_host = ds->value;
944 								} else {
945 									con->http_status = 400;
946 									con->keep_alive = 0;
947 
948 									if (srv->srvconf.log_request_header_on_error) {
949 										log_error_write(srv, __FILE__, __LINE__, "s",
950 												"duplicate Host-header -> 400");
951 										log_error_write(srv, __FILE__, __LINE__, "Sb",
952 												"request-header:\n",
953 												con->request.request);
954 									}
955 									array_insert_unique(con->request.headers, (data_unset *)ds);
956 									return 0;
957 								}
958 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
959 								/* Proxies sometimes send dup headers
960 								 * if they are the same we ignore the second
961 								 * if not, we raise an error */
962 								if (!con->request.http_if_modified_since) {
963 									con->request.http_if_modified_since = ds->value->ptr;
964 								} else if (0 == strcasecmp(con->request.http_if_modified_since,
965 											ds->value->ptr)) {
966 									/* ignore it if they are the same */
967 
968 									ds->free((data_unset *)ds);
969 									ds = NULL;
970 								} else {
971 									con->http_status = 400;
972 									con->keep_alive = 0;
973 
974 									if (srv->srvconf.log_request_header_on_error) {
975 										log_error_write(srv, __FILE__, __LINE__, "s",
976 												"duplicate If-Modified-Since header -> 400");
977 										log_error_write(srv, __FILE__, __LINE__, "Sb",
978 												"request-header:\n",
979 												con->request.request);
980 									}
981 									array_insert_unique(con->request.headers, (data_unset *)ds);
982 									return 0;
983 								}
984 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
985 								/* if dup, only the first one will survive */
986 								if (!con->request.http_if_none_match) {
987 									con->request.http_if_none_match = ds->value->ptr;
988 								} else {
989 									ds->free((data_unset*) ds);
990 									ds = NULL;
991 								}
992 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
993 								if (!con->request.http_range) {
994 									/* bytes=.*-.* */
995 
996 									if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
997 									    NULL != strchr(ds->value->ptr+6, '-')) {
998 
999 										/* if dup, only the first one will survive */
1000 										con->request.http_range = ds->value->ptr + 6;
1001 									}
1002 								} else {
1003 									con->http_status = 400;
1004 									con->keep_alive = 0;
1005 
1006 									if (srv->srvconf.log_request_header_on_error) {
1007 										log_error_write(srv, __FILE__, __LINE__, "s",
1008 												"duplicate Range-header -> 400");
1009 										log_error_write(srv, __FILE__, __LINE__, "Sb",
1010 												"request-header:\n",
1011 												con->request.request);
1012 									}
1013 									array_insert_unique(con->request.headers, (data_unset *)ds);
1014 									return 0;
1015 								}
1016 							}
1017 
1018 							if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
1019 						} else {
1020 							/* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
1021 						}
1022 					}
1023 
1024 					i++;
1025 					first = i+1;
1026 					is_key = 1;
1027 					value = NULL;
1028 #if 0
1029 					/**
1030 					 * for Bug 1230 keep the key_len a live
1031 					 */
1032 					key_len = 0;
1033 #endif
1034 					in_folding = 0;
1035 				} else {
1036 					if (srv->srvconf.log_request_header_on_error) {
1037 						log_error_write(srv, __FILE__, __LINE__, "sbs",
1038 								"CR without LF", con->request.request, "-> 400");
1039 					}
1040 
1041 					con->http_status = 400;
1042 					con->keep_alive = 0;
1043 					con->response.keep_alive = 0;
1044 					return 0;
1045 				}
1046 				break;
1047 			case ' ':
1048 			case '\t':
1049 				/* strip leading WS */
1050 				if (value == cur) value = cur+1;
1051 			default:
1052 				if (*cur >= 0 && *cur < 32 && *cur != '\t') {
1053 					if (srv->srvconf.log_request_header_on_error) {
1054 						log_error_write(srv, __FILE__, __LINE__, "sds",
1055 								"invalid char in header", (int)*cur, "-> 400");
1056 					}
1057 
1058 					con->http_status = 400;
1059 					con->keep_alive = 0;
1060 
1061 					return 0;
1062 				}
1063 				break;
1064 			}
1065 		}
1066 	}
1067 
1068 	con->header_len = i;
1069 
1070 	/* do some post-processing */
1071 
1072 	if (con->request.http_version == HTTP_VERSION_1_1) {
1073 		if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
1074 			/* no Connection-Header sent */
1075 
1076 			/* HTTP/1.1 -> keep-alive default TRUE */
1077 			con->keep_alive = 1;
1078 		} else {
1079 			con->keep_alive = 0;
1080 		}
1081 
1082 		/* RFC 2616, 14.23 */
1083 		if (con->request.http_host == NULL ||
1084 		    buffer_is_empty(con->request.http_host)) {
1085 			con->http_status = 400;
1086 			con->response.keep_alive = 0;
1087 			con->keep_alive = 0;
1088 
1089 			if (srv->srvconf.log_request_header_on_error) {
1090 				log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
1091 				log_error_write(srv, __FILE__, __LINE__, "Sb",
1092 						"request-header:\n",
1093 						con->request.request);
1094 			}
1095 			return 0;
1096 		}
1097 	} else {
1098 		if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
1099 			/* no Connection-Header sent */
1100 
1101 			/* HTTP/1.0 -> keep-alive default FALSE  */
1102 			con->keep_alive = 1;
1103 		} else {
1104 			con->keep_alive = 0;
1105 		}
1106 	}
1107 
1108 	/* check hostname field if it is set */
1109 	if (NULL != con->request.http_host &&
1110 	    0 != request_check_hostname(srv, con, con->request.http_host)) {
1111 
1112 		if (srv->srvconf.log_request_header_on_error) {
1113 			log_error_write(srv, __FILE__, __LINE__, "s",
1114 					"Invalid Hostname -> 400");
1115 			log_error_write(srv, __FILE__, __LINE__, "Sb",
1116 					"request-header:\n",
1117 					con->request.request);
1118 		}
1119 
1120 		con->http_status = 400;
1121 		con->response.keep_alive = 0;
1122 		con->keep_alive = 0;
1123 
1124 		return 0;
1125 	}
1126 
1127 	switch(con->request.http_method) {
1128 	case HTTP_METHOD_GET:
1129 	case HTTP_METHOD_HEAD:
1130 		/* content-length is forbidden for those */
1131 		if (con_length_set && con->request.content_length != 0) {
1132 			/* content-length is missing */
1133 			log_error_write(srv, __FILE__, __LINE__, "s",
1134 					"GET/HEAD with content-length -> 400");
1135 
1136 			con->keep_alive = 0;
1137 			con->http_status = 400;
1138 			return 0;
1139 		}
1140 		break;
1141 	case HTTP_METHOD_POST:
1142 		/* content-length is required for them */
1143 		if (!con_length_set) {
1144 			/* content-length is missing */
1145 			log_error_write(srv, __FILE__, __LINE__, "s",
1146 					"POST-request, but content-length missing -> 411");
1147 
1148 			con->keep_alive = 0;
1149 			con->http_status = 411;
1150 			return 0;
1151 
1152 		}
1153 		break;
1154 	default:
1155 		/* the may have a content-length */
1156 		break;
1157 	}
1158 
1159 
1160 	/* check if we have read post data */
1161 	if (con_length_set) {
1162 		/* don't handle more the SSIZE_MAX bytes in content-length */
1163 		if (con->request.content_length > SSIZE_MAX) {
1164 			con->http_status = 413;
1165 			con->keep_alive = 0;
1166 
1167 			log_error_write(srv, __FILE__, __LINE__, "sos",
1168 					"request-size too long:", (off_t) con->request.content_length, "-> 413");
1169 			return 0;
1170 		}
1171 
1172 		/* divide by 1024 as srvconf.max_request_size is in kBytes */
1173 		if (srv->srvconf.max_request_size != 0 &&
1174 		    (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
1175 			/* the request body itself is larger then
1176 			 * our our max_request_size
1177 			 */
1178 
1179 			con->http_status = 413;
1180 			con->keep_alive = 0;
1181 
1182 			log_error_write(srv, __FILE__, __LINE__, "sos",
1183 					"request-size too long:", (off_t) con->request.content_length, "-> 413");
1184 			return 0;
1185 		}
1186 
1187 
1188 		/* we have content */
1189 		if (con->request.content_length != 0) {
1190 			return 1;
1191 		}
1192 	}
1193 
1194 	return 0;
1195 }
1196 
http_request_header_finished(server * srv,connection * con)1197 int http_request_header_finished(server *srv, connection *con) {
1198 	UNUSED(srv);
1199 
1200 	if (con->request.request->used < 5) return 0;
1201 
1202 	if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
1203 	if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
1204 
1205 	return 0;
1206 }
1207