File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / request.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 20:20:06 2014 UTC (10 years ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_35p0, v1_4_35, HEAD
lighttpd 1.4.35

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

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