File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / request.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

    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: 		buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, buffer_string_length(con->request.request) - 2);
  448: 	} else {
  449: 		/* fill the local request buffer */
  450: 		buffer_copy_buffer(con->parse_request, con->request.request);
  451: 	}
  452: 
  453: 	keep_alive_set = 0;
  454: 	con_length_set = 0;
  455: 
  456: 	/* parse the first line of the request
  457: 	 *
  458: 	 * should be:
  459: 	 *
  460: 	 * <method> <uri> <protocol>\r\n
  461: 	 * */
  462: 	ilen = buffer_string_length(con->parse_request);
  463: 	for (i = 0, first = 0; i < ilen && line == 0; i++) {
  464: 		switch(con->parse_request->ptr[i]) {
  465: 		case '\r':
  466: 			if (con->parse_request->ptr[i+1] == '\n') {
  467: 				http_method_t r;
  468: 				char *nuri = NULL;
  469: 				size_t j, jlen;
  470: 
  471: 				/* \r\n -> \0\0 */
  472: 				con->parse_request->ptr[i] = '\0';
  473: 				con->parse_request->ptr[i+1] = '\0';
  474: 
  475: 				buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
  476: 
  477: 				if (request_line_stage != 2) {
  478: 					con->http_status = 400;
  479: 					con->response.keep_alive = 0;
  480: 					con->keep_alive = 0;
  481: 
  482: 					if (srv->srvconf.log_request_header_on_error) {
  483: 						log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
  484: 						log_error_write(srv, __FILE__, __LINE__, "Sb",
  485: 								"request-header:\n",
  486: 								con->request.request);
  487: 					}
  488: 					return 0;
  489: 				}
  490: 
  491: 				proto = con->parse_request->ptr + first;
  492: 
  493: 				*(uri - 1) = '\0';
  494: 				*(proto - 1) = '\0';
  495: 
  496: 				/* we got the first one :) */
  497: 				if (HTTP_METHOD_UNSET == (r = get_http_method_key(method))) {
  498: 					con->http_status = 501;
  499: 					con->response.keep_alive = 0;
  500: 					con->keep_alive = 0;
  501: 
  502: 					if (srv->srvconf.log_request_header_on_error) {
  503: 						log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
  504: 						log_error_write(srv, __FILE__, __LINE__, "Sb",
  505: 								"request-header:\n",
  506: 								con->request.request);
  507: 					}
  508: 
  509: 					return 0;
  510: 				}
  511: 
  512: 				con->request.http_method = r;
  513: 
  514: 				/*
  515: 				 * RFC2616 says:
  516: 				 *
  517: 				 * HTTP-Version   = "HTTP" "/" 1*DIGIT "." 1*DIGIT
  518: 				 *
  519: 				 * */
  520: 				if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
  521: 					char * major = proto + sizeof("HTTP/") - 1;
  522: 					char * minor = strchr(major, '.');
  523: 					char *err = NULL;
  524: 					int major_num = 0, minor_num = 0;
  525: 
  526: 					int invalid_version = 0;
  527: 
  528: 					if (NULL == minor || /* no dot */
  529: 					    minor == major || /* no major */
  530: 					    *(minor + 1) == '\0' /* no minor */) {
  531: 						invalid_version = 1;
  532: 					} else {
  533: 						*minor = '\0';
  534: 						major_num = strtol(major, &err, 10);
  535: 
  536: 						if (*err != '\0') invalid_version = 1;
  537: 
  538: 						*minor++ = '.';
  539: 						minor_num = strtol(minor, &err, 10);
  540: 
  541: 						if (*err != '\0') invalid_version = 1;
  542: 					}
  543: 
  544: 					if (invalid_version) {
  545: 						con->http_status = 400;
  546: 						con->keep_alive = 0;
  547: 
  548: 						if (srv->srvconf.log_request_header_on_error) {
  549: 							log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
  550: 							log_error_write(srv, __FILE__, __LINE__, "Sb",
  551: 									"request-header:\n",
  552: 									con->request.request);
  553: 						}
  554: 						return 0;
  555: 					}
  556: 
  557: 					if (major_num == 1 && minor_num == 1) {
  558: 						con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
  559: 					} else if (major_num == 1 && minor_num == 0) {
  560: 						con->request.http_version = HTTP_VERSION_1_0;
  561: 					} else {
  562: 						con->http_status = 505;
  563: 
  564: 						if (srv->srvconf.log_request_header_on_error) {
  565: 							log_error_write(srv, __FILE__, __LINE__, "s", "unknown HTTP version -> 505");
  566: 							log_error_write(srv, __FILE__, __LINE__, "Sb",
  567: 									"request-header:\n",
  568: 									con->request.request);
  569: 						}
  570: 						return 0;
  571: 					}
  572: 				} else {
  573: 					con->http_status = 400;
  574: 					con->keep_alive = 0;
  575: 
  576: 					if (srv->srvconf.log_request_header_on_error) {
  577: 						log_error_write(srv, __FILE__, __LINE__, "s", "unknown protocol -> 400");
  578: 						log_error_write(srv, __FILE__, __LINE__, "Sb",
  579: 								"request-header:\n",
  580: 								con->request.request);
  581: 					}
  582: 					return 0;
  583: 				}
  584: 
  585: 				if (0 == strncmp(uri, "http://", 7) &&
  586: 				    NULL != (nuri = strchr(uri + 7, '/'))) {
  587: 					reqline_host = uri + 7;
  588: 					reqline_hostlen = nuri - reqline_host;
  589: 
  590: 					buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
  591: 				} else if (0 == strncmp(uri, "https://", 8) &&
  592: 				    NULL != (nuri = strchr(uri + 8, '/'))) {
  593: 					reqline_host = uri + 8;
  594: 					reqline_hostlen = nuri - reqline_host;
  595: 
  596: 					buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
  597: 				} else {
  598: 					/* everything looks good so far */
  599: 					buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
  600: 				}
  601: 
  602: 				/* check uri for invalid characters */
  603: 				jlen = buffer_string_length(con->request.uri);
  604: 				if (http_header_strict) {
  605: 					for (j = 0; j < jlen && request_uri_is_valid_char(con->request.uri->ptr[j]); j++) ;
  606: 				} else {
  607: 					char *z = memchr(con->request.uri->ptr, '\0', jlen);
  608: 					j = (NULL == z) ? jlen : (size_t)(z - con->request.uri->ptr);
  609: 				}
  610: 				if (j < jlen) {
  611: 						con->http_status = 400;
  612: 						con->keep_alive = 0;
  613: 
  614: 						if (srv->srvconf.log_request_header_on_error) {
  615: 							unsigned char buf[2];
  616: 							buf[0] = con->request.uri->ptr[j];
  617: 							buf[1] = '\0';
  618: 
  619: 							if (con->request.uri->ptr[j] > 32 &&
  620: 							    con->request.uri->ptr[j] != 127) {
  621: 								/* the character is printable -> print it */
  622: 								log_error_write(srv, __FILE__, __LINE__, "ss",
  623: 										"invalid character in URI -> 400",
  624: 										buf);
  625: 							} else {
  626: 								/* a control-character, print ascii-code */
  627: 								log_error_write(srv, __FILE__, __LINE__, "sd",
  628: 										"invalid character in URI -> 400",
  629: 										con->request.uri->ptr[j]);
  630: 							}
  631: 
  632: 							log_error_write(srv, __FILE__, __LINE__, "Sb",
  633: 									"request-header:\n",
  634: 									con->request.request);
  635: 						}
  636: 
  637: 						return 0;
  638: 				}
  639: 
  640: 				buffer_copy_buffer(con->request.orig_uri, con->request.uri);
  641: 
  642: 				con->http_status = 0;
  643: 
  644: 				i++;
  645: 				line++;
  646: 				first = i+1;
  647: 			}
  648: 			break;
  649: 		case ' ':
  650: 			switch(request_line_stage) {
  651: 			case 0:
  652: 				/* GET|POST|... */
  653: 				method = con->parse_request->ptr + first;
  654: 				first = i + 1;
  655: 				break;
  656: 			case 1:
  657: 				/* /foobar/... */
  658: 				uri = con->parse_request->ptr + first;
  659: 				first = i + 1;
  660: 				break;
  661: 			default:
  662: 				/* ERROR, one space to much */
  663: 				con->http_status = 400;
  664: 				con->response.keep_alive = 0;
  665: 				con->keep_alive = 0;
  666: 
  667: 				if (srv->srvconf.log_request_header_on_error) {
  668: 					log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
  669: 					log_error_write(srv, __FILE__, __LINE__, "Sb",
  670: 							"request-header:\n",
  671: 							con->request.request);
  672: 				}
  673: 				return 0;
  674: 			}
  675: 
  676: 			request_line_stage++;
  677: 			break;
  678: 		}
  679: 	}
  680: 
  681: 	in_folding = 0;
  682: 
  683: 	if (buffer_string_is_empty(con->request.uri)) {
  684: 		con->http_status = 400;
  685: 		con->response.keep_alive = 0;
  686: 		con->keep_alive = 0;
  687: 
  688: 		if (srv->srvconf.log_request_header_on_error) {
  689: 			log_error_write(srv, __FILE__, __LINE__, "s", "no uri specified -> 400");
  690: 			log_error_write(srv, __FILE__, __LINE__, "Sb",
  691: 							"request-header:\n",
  692: 							con->request.request);
  693: 		}
  694: 		return 0;
  695: 	}
  696: 
  697: 	if (reqline_host) {
  698: 		/* Insert as host header */
  699: 		data_string *ds;
  700: 
  701: 		if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
  702: 			ds = data_string_init();
  703: 		}
  704: 
  705: 		buffer_copy_string_len(ds->key, CONST_STR_LEN("Host"));
  706: 		buffer_copy_string_len(ds->value, reqline_host, reqline_hostlen);
  707: 		array_insert_unique(con->request.headers, (data_unset *)ds);
  708: 		con->request.http_host = ds->value;
  709: 	}
  710: 
  711: 	for (; i <= ilen && !done; i++) {
  712: 		char *cur = con->parse_request->ptr + i;
  713: 
  714: 		if (is_key) {
  715: 			size_t j;
  716: 			int got_colon = 0;
  717: 
  718: 			/**
  719: 			 * 1*<any CHAR except CTLs or separators>
  720: 			 * CTLs == 0-31 + 127, CHAR = 7-bit ascii (0..127)
  721: 			 *
  722: 			 */
  723: 			switch(*cur) {
  724: 			case ':':
  725: 				is_key = 0;
  726: 
  727: 				value = cur + 1;
  728: 
  729: 				if (is_ws_after_key == 0) {
  730: 					key_len = i - first;
  731: 				}
  732: 				is_ws_after_key = 0;
  733: 
  734: 				break;
  735: 			case '(':
  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: 				con->http_status = 400;
  752: 				con->keep_alive = 0;
  753: 				con->response.keep_alive = 0;
  754: 
  755: 				if (srv->srvconf.log_request_header_on_error) {
  756: 					log_error_write(srv, __FILE__, __LINE__, "sbsds",
  757: 						"invalid character in key", con->request.request, cur, *cur, "-> 400");
  758: 
  759: 					log_error_write(srv, __FILE__, __LINE__, "Sb",
  760: 						"request-header:\n",
  761: 						con->request.request);
  762: 				}
  763: 				return 0;
  764: 			case ' ':
  765: 			case '\t':
  766: 				if (i == first) {
  767: 					is_key = 0;
  768: 					in_folding = 1;
  769: 					value = cur;
  770: 
  771: 					break;
  772: 				}
  773: 
  774: 
  775: 				key_len = i - first;
  776: 
  777: 				/* skip every thing up to the : */
  778: 				for (j = 1; !got_colon; j++) {
  779: 					switch(con->parse_request->ptr[j + i]) {
  780: 					case ' ':
  781: 					case '\t':
  782: 						/* skip WS */
  783: 						continue;
  784: 					case ':':
  785: 						/* ok, done; handle the colon the usual way */
  786: 
  787: 						i += j - 1;
  788: 						got_colon = 1;
  789: 						is_ws_after_key = 1; /* we already know the key length */
  790: 
  791: 						break;
  792: 					default:
  793: 						/* error */
  794: 
  795: 						if (srv->srvconf.log_request_header_on_error) {
  796: 							log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
  797: 							log_error_write(srv, __FILE__, __LINE__, "Sb",
  798: 								"request-header:\n",
  799: 								con->request.request);
  800: 						}
  801: 
  802: 						con->http_status = 400;
  803: 						con->response.keep_alive = 0;
  804: 						con->keep_alive = 0;
  805: 
  806: 						return 0;
  807: 					}
  808: 				}
  809: 
  810: 				break;
  811: 			case '\r':
  812: 				if (con->parse_request->ptr[i+1] == '\n' && i == first) {
  813: 					/* End of Header */
  814: 					con->parse_request->ptr[i] = '\0';
  815: 					con->parse_request->ptr[i+1] = '\0';
  816: 
  817: 					i++;
  818: 
  819: 					done = 1;
  820: 				} else {
  821: 					if (srv->srvconf.log_request_header_on_error) {
  822: 						log_error_write(srv, __FILE__, __LINE__, "s", "CR without LF -> 400");
  823: 						log_error_write(srv, __FILE__, __LINE__, "Sb",
  824: 							"request-header:\n",
  825: 							con->request.request);
  826: 					}
  827: 
  828: 					con->http_status = 400;
  829: 					con->keep_alive = 0;
  830: 					con->response.keep_alive = 0;
  831: 					return 0;
  832: 				}
  833: 				break;
  834: 			default:
  835: 				if (http_header_strict ? (*cur < 32 || ((unsigned char)*cur) >= 127) : *cur == '\0') {
  836: 					con->http_status = 400;
  837: 					con->keep_alive = 0;
  838: 					con->response.keep_alive = 0;
  839: 
  840: 					if (srv->srvconf.log_request_header_on_error) {
  841: 						log_error_write(srv, __FILE__, __LINE__, "sbsds",
  842: 							"invalid character in key", con->request.request, cur, *cur, "-> 400");
  843: 
  844: 						log_error_write(srv, __FILE__, __LINE__, "Sb",
  845: 							"request-header:\n",
  846: 							con->request.request);
  847: 					}
  848: 
  849: 					return 0;
  850: 				}
  851: 				/* ok */
  852: 				break;
  853: 			}
  854: 		} else {
  855: 			switch(*cur) {
  856: 			case '\r':
  857: 				if (con->parse_request->ptr[i+1] == '\n') {
  858: 					data_string *ds = NULL;
  859: 
  860: 					/* End of Headerline */
  861: 					con->parse_request->ptr[i] = '\0';
  862: 					con->parse_request->ptr[i+1] = '\0';
  863: 
  864: 					if (in_folding) {
  865: 						buffer *key_b;
  866: 						/**
  867: 						 * we use a evil hack to handle the line-folding
  868: 						 * 
  869: 						 * As array_insert_unique() deletes 'ds' in the case of a duplicate
  870: 						 * ds points somewhere and we get a evil crash. As a solution we keep the old
  871: 						 * "key" and get the current value from the hash and append us
  872: 						 *
  873: 						 * */
  874: 
  875: 						if (!key || !key_len) {
  876: 							/* 400 */
  877: 
  878: 							if (srv->srvconf.log_request_header_on_error) {
  879: 								log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
  880: 
  881: 								log_error_write(srv, __FILE__, __LINE__, "Sb",
  882: 									"request-header:\n",
  883: 									con->request.request);
  884: 							}
  885: 
  886: 
  887: 							con->http_status = 400;
  888: 							con->keep_alive = 0;
  889: 							con->response.keep_alive = 0;
  890: 							return 0;
  891: 						}
  892: 
  893: 						key_b = buffer_init();
  894: 						buffer_copy_string_len(key_b, key, key_len);
  895: 
  896: 						if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key_b->ptr))) {
  897: 							buffer_append_string(ds->value, value);
  898: 						}
  899: 
  900: 						buffer_free(key_b);
  901: 					} else {
  902: 						int s_len;
  903: 						key = con->parse_request->ptr + first;
  904: 
  905: 						s_len = cur - value;
  906: 
  907: 						/* strip trailing white-spaces */
  908: 						for (; s_len > 0 && 
  909: 								(value[s_len - 1] == ' ' || 
  910: 								 value[s_len - 1] == '\t'); s_len--);
  911: 
  912: 						value[s_len] = '\0';
  913: 
  914: 						if (s_len > 0) {
  915: 							int cmp = 0;
  916: 							if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
  917: 								ds = data_string_init();
  918: 							}
  919: 							buffer_copy_string_len(ds->key, key, key_len);
  920: 							buffer_copy_string_len(ds->value, value, s_len);
  921: 
  922: 							/* retreive values
  923: 							 *
  924: 							 *
  925: 							 * the list of options is sorted to simplify the search
  926: 							 */
  927: 
  928: 							if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
  929: 								array *vals;
  930: 								size_t vi;
  931: 
  932: 								/* split on , */
  933: 
  934: 								vals = srv->split_vals;
  935: 
  936: 								array_reset(vals);
  937: 
  938: 								http_request_split_value(vals, ds->value);
  939: 
  940: 								for (vi = 0; vi < vals->used; vi++) {
  941: 									data_string *dsv = (data_string *)vals->data[vi];
  942: 
  943: 									if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
  944: 										keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
  945: 
  946: 										break;
  947: 									} else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
  948: 										keep_alive_set = HTTP_CONNECTION_CLOSE;
  949: 
  950: 										break;
  951: 									}
  952: 								}
  953: 
  954: 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
  955: 								char *err;
  956: 								unsigned long int r;
  957: 								size_t j, jlen;
  958: 
  959: 								if (con_length_set) {
  960: 									con->http_status = 400;
  961: 									con->keep_alive = 0;
  962: 
  963: 									if (srv->srvconf.log_request_header_on_error) {
  964: 										log_error_write(srv, __FILE__, __LINE__, "s",
  965: 												"duplicate Content-Length-header -> 400");
  966: 										log_error_write(srv, __FILE__, __LINE__, "Sb",
  967: 												"request-header:\n",
  968: 												con->request.request);
  969: 									}
  970: 									array_insert_unique(con->request.headers, (data_unset *)ds);
  971: 									return 0;
  972: 								}
  973: 
  974: 								jlen = buffer_string_length(ds->value);
  975: 								for (j = 0; j < jlen; j++) {
  976: 									char c = ds->value->ptr[j];
  977: 									if (!isdigit((unsigned char)c)) {
  978: 										log_error_write(srv, __FILE__, __LINE__, "sbs",
  979: 												"content-length broken:", ds->value, "-> 400");
  980: 
  981: 										con->http_status = 400;
  982: 										con->keep_alive = 0;
  983: 
  984: 										array_insert_unique(con->request.headers, (data_unset *)ds);
  985: 										return 0;
  986: 									}
  987: 								}
  988: 
  989: 								r = strtoul(ds->value->ptr, &err, 10);
  990: 
  991: 								if (*err == '\0') {
  992: 									con_length_set = 1;
  993: 									con->request.content_length = r;
  994: 								} else {
  995: 									log_error_write(srv, __FILE__, __LINE__, "sbs",
  996: 											"content-length broken:", ds->value, "-> 400");
  997: 
  998: 									con->http_status = 400;
  999: 									con->keep_alive = 0;
 1000: 
 1001: 									array_insert_unique(con->request.headers, (data_unset *)ds);
 1002: 									return 0;
 1003: 								}
 1004: 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Type")))) {
 1005: 								/* if dup, only the first one will survive */
 1006: 								if (!con->request.http_content_type) {
 1007: 									con->request.http_content_type = ds->value->ptr;
 1008: 								} else {
 1009: 									con->http_status = 400;
 1010: 									con->keep_alive = 0;
 1011: 
 1012: 									if (srv->srvconf.log_request_header_on_error) {
 1013: 										log_error_write(srv, __FILE__, __LINE__, "s",
 1014: 												"duplicate Content-Type-header -> 400");
 1015: 										log_error_write(srv, __FILE__, __LINE__, "Sb",
 1016: 												"request-header:\n",
 1017: 												con->request.request);
 1018: 									}
 1019: 									array_insert_unique(con->request.headers, (data_unset *)ds);
 1020: 									return 0;
 1021: 								}
 1022: 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
 1023: 								/* HTTP 2616 8.2.3
 1024: 								 * Expect: 100-continue
 1025: 								 *
 1026: 								 *   -> (10.1.1)  100 (read content, process request, send final status-code)
 1027: 								 *   -> (10.4.18) 417 (close)
 1028: 								 *
 1029: 								 * (not handled at all yet, we always send 417 here)
 1030: 								 *
 1031: 								 * What has to be added ?
 1032: 								 * 1. handling of chunked request body
 1033: 								 * 2. out-of-order sending from the HTTP/1.1 100 Continue
 1034: 								 *    header
 1035: 								 *
 1036: 								 */
 1037: 
 1038: 								if (srv->srvconf.reject_expect_100_with_417 && 0 == buffer_caseless_compare(CONST_BUF_LEN(ds->value), CONST_STR_LEN("100-continue"))) {
 1039: 									con->http_status = 417;
 1040: 									con->keep_alive = 0;
 1041: 									array_insert_unique(con->request.headers, (data_unset *)ds);
 1042: 									return 0;
 1043: 								}
 1044: 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
 1045: 								if (reqline_host) {
 1046: 									/* ignore all host: headers as we got the host in the request line */
 1047: 									ds->free((data_unset*) ds);
 1048: 									ds = NULL;
 1049: 								} else if (!con->request.http_host) {
 1050: 									con->request.http_host = ds->value;
 1051: 								} else {
 1052: 									con->http_status = 400;
 1053: 									con->keep_alive = 0;
 1054: 
 1055: 									if (srv->srvconf.log_request_header_on_error) {
 1056: 										log_error_write(srv, __FILE__, __LINE__, "s",
 1057: 												"duplicate Host-header -> 400");
 1058: 										log_error_write(srv, __FILE__, __LINE__, "Sb",
 1059: 												"request-header:\n",
 1060: 												con->request.request);
 1061: 									}
 1062: 									array_insert_unique(con->request.headers, (data_unset *)ds);
 1063: 									return 0;
 1064: 								}
 1065: 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
 1066: 								/* Proxies sometimes send dup headers
 1067: 								 * if they are the same we ignore the second
 1068: 								 * if not, we raise an error */
 1069: 								if (!con->request.http_if_modified_since) {
 1070: 									con->request.http_if_modified_since = ds->value->ptr;
 1071: 								} else if (0 == strcasecmp(con->request.http_if_modified_since,
 1072: 											ds->value->ptr)) {
 1073: 									/* ignore it if they are the same */
 1074: 
 1075: 									ds->free((data_unset *)ds);
 1076: 									ds = NULL;
 1077: 								} else {
 1078: 									con->http_status = 400;
 1079: 									con->keep_alive = 0;
 1080: 
 1081: 									if (srv->srvconf.log_request_header_on_error) {
 1082: 										log_error_write(srv, __FILE__, __LINE__, "s",
 1083: 												"duplicate If-Modified-Since header -> 400");
 1084: 										log_error_write(srv, __FILE__, __LINE__, "Sb",
 1085: 												"request-header:\n",
 1086: 												con->request.request);
 1087: 									}
 1088: 									array_insert_unique(con->request.headers, (data_unset *)ds);
 1089: 									return 0;
 1090: 								}
 1091: 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
 1092: 								/* if dup, only the first one will survive */
 1093: 								if (!con->request.http_if_none_match) {
 1094: 									con->request.http_if_none_match = ds->value->ptr;
 1095: 								} else {
 1096: 									ds->free((data_unset*) ds);
 1097: 									ds = NULL;
 1098: 								}
 1099: 							} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
 1100: 								if (!con->request.http_range) {
 1101: 									/* bytes=.*-.* */
 1102: 
 1103: 									if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
 1104: 									    NULL != strchr(ds->value->ptr+6, '-')) {
 1105: 
 1106: 										/* if dup, only the first one will survive */
 1107: 										con->request.http_range = ds->value->ptr + 6;
 1108: 									}
 1109: 								} else {
 1110: 									con->http_status = 400;
 1111: 									con->keep_alive = 0;
 1112: 
 1113: 									if (srv->srvconf.log_request_header_on_error) {
 1114: 										log_error_write(srv, __FILE__, __LINE__, "s",
 1115: 												"duplicate Range-header -> 400");
 1116: 										log_error_write(srv, __FILE__, __LINE__, "Sb",
 1117: 												"request-header:\n",
 1118: 												con->request.request);
 1119: 									}
 1120: 									array_insert_unique(con->request.headers, (data_unset *)ds);
 1121: 									return 0;
 1122: 								}
 1123: 							}
 1124: 
 1125: 							if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
 1126: 						} else {
 1127: 							/* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
 1128: 						}
 1129: 					}
 1130: 
 1131: 					i++;
 1132: 					first = i+1;
 1133: 					is_key = 1;
 1134: 					value = NULL;
 1135: #if 0
 1136: 					/**
 1137: 					 * for Bug 1230 keep the key_len a live
 1138: 					 */
 1139: 					key_len = 0; 
 1140: #endif
 1141: 					in_folding = 0;
 1142: 				} else {
 1143: 					if (srv->srvconf.log_request_header_on_error) {
 1144: 						log_error_write(srv, __FILE__, __LINE__, "sbs",
 1145: 								"CR without LF", con->request.request, "-> 400");
 1146: 					}
 1147: 
 1148: 					con->http_status = 400;
 1149: 					con->keep_alive = 0;
 1150: 					con->response.keep_alive = 0;
 1151: 					return 0;
 1152: 				}
 1153: 				break;
 1154: 			case ' ':
 1155: 			case '\t':
 1156: 				/* strip leading WS */
 1157: 				if (value == cur) value = cur+1;
 1158: 				break;
 1159: 			default:
 1160: 				if (http_header_strict ? (*cur >= 0 && *cur < 32) : *cur == '\0') {
 1161: 					if (srv->srvconf.log_request_header_on_error) {
 1162: 						log_error_write(srv, __FILE__, __LINE__, "sds",
 1163: 								"invalid char in header", (int)*cur, "-> 400");
 1164: 					}
 1165: 
 1166: 					con->http_status = 400;
 1167: 					con->keep_alive = 0;
 1168: 
 1169: 					return 0;
 1170: 				}
 1171: 				break;
 1172: 			}
 1173: 		}
 1174: 	}
 1175: 
 1176: 	con->header_len = i;
 1177: 
 1178: 	/* do some post-processing */
 1179: 
 1180: 	if (con->request.http_version == HTTP_VERSION_1_1) {
 1181: 		if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
 1182: 			/* no Connection-Header sent */
 1183: 
 1184: 			/* HTTP/1.1 -> keep-alive default TRUE */
 1185: 			con->keep_alive = 1;
 1186: 		} else {
 1187: 			con->keep_alive = 0;
 1188: 		}
 1189: 
 1190: 		/* RFC 2616, 14.23 */
 1191: 		if (con->request.http_host == NULL ||
 1192: 		    buffer_string_is_empty(con->request.http_host)) {
 1193: 			con->http_status = 400;
 1194: 			con->response.keep_alive = 0;
 1195: 			con->keep_alive = 0;
 1196: 
 1197: 			if (srv->srvconf.log_request_header_on_error) {
 1198: 				log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
 1199: 				log_error_write(srv, __FILE__, __LINE__, "Sb",
 1200: 						"request-header:\n",
 1201: 						con->request.request);
 1202: 			}
 1203: 			return 0;
 1204: 		}
 1205: 	} else {
 1206: 		if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
 1207: 			/* no Connection-Header sent */
 1208: 
 1209: 			/* HTTP/1.0 -> keep-alive default FALSE  */
 1210: 			con->keep_alive = 1;
 1211: 		} else {
 1212: 			con->keep_alive = 0;
 1213: 		}
 1214: 	}
 1215: 
 1216: 	/* check hostname field if it is set */
 1217: 	if (!buffer_is_empty(con->request.http_host) &&
 1218: 	    (((con->conf.http_parseopts & HTTP_PARSEOPT_HOST_STRICT) &&
 1219: 	      0 != request_check_hostname(con->request.http_host))
 1220: 	     || ((con->conf.http_parseopts & HTTP_PARSEOPT_HOST_NORMALIZE) &&
 1221: 		 0 != http_request_host_normalize(con->request.http_host)))) {
 1222: 
 1223: 		if (srv->srvconf.log_request_header_on_error) {
 1224: 			log_error_write(srv, __FILE__, __LINE__, "s",
 1225: 					"Invalid Hostname -> 400");
 1226: 			log_error_write(srv, __FILE__, __LINE__, "Sb",
 1227: 					"request-header:\n",
 1228: 					con->request.request);
 1229: 		}
 1230: 
 1231: 		con->http_status = 400;
 1232: 		con->response.keep_alive = 0;
 1233: 		con->keep_alive = 0;
 1234: 
 1235: 		return 0;
 1236: 	}
 1237: 
 1238: 	switch(con->request.http_method) {
 1239: 	case HTTP_METHOD_GET:
 1240: 	case HTTP_METHOD_HEAD:
 1241: 		/* content-length is forbidden for those */
 1242: 		if (con_length_set && con->request.content_length != 0) {
 1243: 			/* content-length is missing */
 1244: 			log_error_write(srv, __FILE__, __LINE__, "s",
 1245: 					"GET/HEAD with content-length -> 400");
 1246: 
 1247: 			con->keep_alive = 0;
 1248: 			con->http_status = 400;
 1249: 			return 0;
 1250: 		}
 1251: 		break;
 1252: 	case HTTP_METHOD_POST:
 1253: 		/* content-length is required for them */
 1254: 		if (!con_length_set) {
 1255: 			/* content-length is missing */
 1256: 			log_error_write(srv, __FILE__, __LINE__, "s",
 1257: 					"POST-request, but content-length missing -> 411");
 1258: 
 1259: 			con->keep_alive = 0;
 1260: 			con->http_status = 411;
 1261: 			return 0;
 1262: 
 1263: 		}
 1264: 		break;
 1265: 	default:
 1266: 		/* require Content-Length if request contains request body */
 1267: 		if (array_get_element(con->request.headers, "Transfer-Encoding")) {
 1268: 			/* presence of Transfer-Encoding in request headers requires "chunked"
 1269: 			 * be final encoding in HTTP/1.1.  Return 411 Length Required as
 1270: 			 * lighttpd does not support request input transfer-encodings */
 1271: 			con->keep_alive = 0;
 1272: 			con->http_status = 411; /* 411 Length Required */
 1273: 			return 0;
 1274: 		}
 1275: 		break;
 1276: 	}
 1277: 
 1278: 
 1279: 	/* check if we have read post data */
 1280: 	if (con_length_set) {
 1281: 		/* don't handle more the SSIZE_MAX bytes in content-length */
 1282: 		if (con->request.content_length > SSIZE_MAX) {
 1283: 			con->http_status = 413;
 1284: 			con->keep_alive = 0;
 1285: 
 1286: 			log_error_write(srv, __FILE__, __LINE__, "sos",
 1287: 					"request-size too long:", (off_t) con->request.content_length, "-> 413");
 1288: 			return 0;
 1289: 		}
 1290: 
 1291: 		/* we have content */
 1292: 		if (con->request.content_length != 0) {
 1293: 			return 1;
 1294: 		}
 1295: 	}
 1296: 
 1297: 	return 0;
 1298: }
 1299: 
 1300: int http_request_header_finished(server *srv, connection *con) {
 1301: 	UNUSED(srv);
 1302: 
 1303: 	if (buffer_string_length(con->request.request) < 4) return 0;
 1304: 
 1305: 	if (0 == memcmp(con->request.request->ptr + buffer_string_length(con->request.request) - 4, CONST_STR_LEN("\r\n\r\n"))) return 1;
 1306: 	if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
 1307: 
 1308: 	return 0;
 1309: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>