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