File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / request.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 10:32:47 2013 UTC (10 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_33, HEAD
1.4.33

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

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