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