uhttpd: - fix parsing of interpreter entries in the config file, fixes serving of static files as .cgi with X-Wrt - better cope with connection aborts, especially during header transfer - fix return value checking of TLS reads and writes, solves some blocking issues
SVN-Revision: 22692
This commit is contained in:
		| @@ -8,7 +8,7 @@ | ||||
| include $(TOPDIR)/rules.mk | ||||
|  | ||||
| PKG_NAME:=uhttpd | ||||
| PKG_RELEASE:=15 | ||||
| PKG_RELEASE:=16 | ||||
|  | ||||
| PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) | ||||
| PKG_BUILD_DEPENDS := libcyassl liblua | ||||
|   | ||||
| @@ -139,7 +139,7 @@ void uh_cgi_request( | ||||
| 	struct client *cl, struct http_request *req, | ||||
| 	struct path_info *pi, struct interpreter *ip | ||||
| ) { | ||||
| 	int i, hdroff, bufoff; | ||||
| 	int i, hdroff, bufoff, rv; | ||||
| 	int hdrlen = 0; | ||||
| 	int buflen = 0; | ||||
| 	int fd_max = 0; | ||||
| @@ -376,12 +376,6 @@ void uh_cgi_request( | ||||
|  | ||||
| 			memset(hdr, 0, sizeof(hdr)); | ||||
|  | ||||
| 			timeout.tv_sec = cl->server->conf->script_timeout; | ||||
| 			timeout.tv_usec = 0; | ||||
|  | ||||
| #define ensure(x) \ | ||||
| 	do { if( x < 0 ) goto out; } while(0) | ||||
|  | ||||
| 			/* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */ | ||||
| 			while( 1 ) | ||||
| 			{ | ||||
| @@ -391,11 +385,21 @@ void uh_cgi_request( | ||||
| 				FD_SET(rfd[0], &reader); | ||||
| 				FD_SET(wfd[1], &writer); | ||||
|  | ||||
| 				timeout.tv_sec = (header_sent < 1) ? cl->server->conf->script_timeout : 3; | ||||
| 				timeout.tv_usec = 0; | ||||
|  | ||||
| 				ensure_out(rv = select_intr(fd_max, &reader, | ||||
| 					(content_length > -1) ? &writer : NULL, NULL, &timeout)); | ||||
|  | ||||
| 				/* timeout */ | ||||
| 				if( rv == 0 ) | ||||
| 				{ | ||||
| 					ensure_out(kill(child, 0)); | ||||
| 				} | ||||
|  | ||||
| 				/* wait until we can read or write or both */ | ||||
| 				if( select_intr(fd_max, &reader, | ||||
| 					(content_length > -1) ? &writer : NULL, NULL, | ||||
| 					(header_sent < 1) ? &timeout : NULL) > 0 | ||||
| 				) { | ||||
| 				else if( rv > 0 ) | ||||
| 				{ | ||||
| 					/* ready to write to cgi program */ | ||||
| 					if( FD_ISSET(wfd[1], &writer) ) | ||||
| 					{ | ||||
| @@ -403,7 +407,10 @@ void uh_cgi_request( | ||||
| 						if( content_length > 0 ) | ||||
| 						{ | ||||
| 							/* read it from socket ... */ | ||||
| 							if( (buflen = uh_tcp_recv(cl, buf, min(content_length, sizeof(buf)))) > 0 ) | ||||
| 							ensure_out(buflen = uh_tcp_recv(cl, buf, | ||||
| 								min(content_length, sizeof(buf)))); | ||||
|  | ||||
| 							if( buflen > 0 ) | ||||
| 							{ | ||||
| 								/* ... and write it to child's stdin */ | ||||
| 								if( write(wfd[1], buf, buflen) < 0 ) | ||||
| @@ -456,7 +463,7 @@ void uh_cgi_request( | ||||
| 								if( (res = uh_cgi_header_parse(hdr, hdrlen, &hdroff)) != NULL ) | ||||
| 								{ | ||||
| 									/* write status */ | ||||
| 									ensure(uh_http_sendf(cl, NULL, | ||||
| 									ensure_out(uh_http_sendf(cl, NULL, | ||||
| 										"HTTP/%.1f %03d %s\r\n" | ||||
| 										"Connection: close\r\n", | ||||
| 										req->version, res->statuscode, | ||||
| @@ -466,7 +473,7 @@ void uh_cgi_request( | ||||
| 									if( !uh_cgi_header_lookup(res, "Location") && | ||||
| 									    !uh_cgi_header_lookup(res, "Content-Type") | ||||
| 									) { | ||||
| 										ensure(uh_http_send(cl, NULL, | ||||
| 										ensure_out(uh_http_send(cl, NULL, | ||||
| 											"Content-Type: text/plain\r\n", -1)); | ||||
| 									} | ||||
|  | ||||
| @@ -474,32 +481,32 @@ void uh_cgi_request( | ||||
| 									if( (req->version > 1.0) && | ||||
| 									    !uh_cgi_header_lookup(res, "Transfer-Encoding") | ||||
| 									) { | ||||
| 										ensure(uh_http_send(cl, NULL, | ||||
| 										ensure_out(uh_http_send(cl, NULL, | ||||
| 											"Transfer-Encoding: chunked\r\n", -1)); | ||||
| 									} | ||||
|  | ||||
| 									/* write headers from CGI program */ | ||||
| 									foreach_header(i, res->headers) | ||||
| 									{ | ||||
| 										ensure(uh_http_sendf(cl, NULL, "%s: %s\r\n", | ||||
| 										ensure_out(uh_http_sendf(cl, NULL, "%s: %s\r\n", | ||||
| 											res->headers[i], res->headers[i+1])); | ||||
| 									} | ||||
|  | ||||
| 									/* terminate header */ | ||||
| 									ensure(uh_http_send(cl, NULL, "\r\n", -1)); | ||||
| 									ensure_out(uh_http_send(cl, NULL, "\r\n", -1)); | ||||
|  | ||||
| 									/* push out remaining head buffer */ | ||||
| 									if( hdroff < hdrlen ) | ||||
| 										ensure(uh_http_send(cl, req, &hdr[hdroff], hdrlen - hdroff)); | ||||
| 										ensure_out(uh_http_send(cl, req, &hdr[hdroff], hdrlen - hdroff)); | ||||
| 								} | ||||
|  | ||||
| 								/* ... failed and head buffer exceeded */ | ||||
| 								else if( hdrlen >= sizeof(hdr) ) | ||||
| 								{ | ||||
| 									ensure(uh_cgi_error_500(cl, req, | ||||
| 									ensure_out(uh_cgi_error_500(cl, req, | ||||
| 										"The CGI program generated an invalid response:\n\n")); | ||||
|  | ||||
| 									ensure(uh_http_send(cl, req, hdr, hdrlen)); | ||||
| 									ensure_out(uh_http_send(cl, req, hdr, hdrlen)); | ||||
| 								} | ||||
|  | ||||
| 								/* ... failed but free buffer space, try again */ | ||||
| @@ -510,7 +517,7 @@ void uh_cgi_request( | ||||
|  | ||||
| 								/* push out remaining read buffer */ | ||||
| 								if( bufoff < buflen ) | ||||
| 									ensure(uh_http_send(cl, req, &buf[bufoff], buflen - bufoff)); | ||||
| 									ensure_out(uh_http_send(cl, req, &buf[bufoff], buflen - bufoff)); | ||||
|  | ||||
| 								header_sent = 1; | ||||
| 								continue; | ||||
| @@ -518,7 +525,7 @@ void uh_cgi_request( | ||||
|  | ||||
|  | ||||
| 							/* headers complete, pass through buffer to socket */ | ||||
| 							ensure(uh_http_send(cl, req, buf, buflen)); | ||||
| 							ensure_out(uh_http_send(cl, req, buf, buflen)); | ||||
| 						} | ||||
|  | ||||
| 						/* looks like eof from child */ | ||||
| @@ -538,7 +545,7 @@ void uh_cgi_request( | ||||
| 								 * build the required headers here. | ||||
| 								 */ | ||||
|  | ||||
| 								ensure(uh_http_sendf(cl, NULL, | ||||
| 								ensure_out(uh_http_sendf(cl, NULL, | ||||
| 									"HTTP/%.1f 200 OK\r\n" | ||||
| 									"Content-Type: text/plain\r\n" | ||||
| 									"%s\r\n", | ||||
| @@ -546,11 +553,11 @@ void uh_cgi_request( | ||||
| 											? "Transfer-Encoding: chunked\r\n" : "" | ||||
| 								)); | ||||
|  | ||||
| 								ensure(uh_http_send(cl, req, hdr, hdrlen)); | ||||
| 								ensure_out(uh_http_send(cl, req, hdr, hdrlen)); | ||||
| 							} | ||||
|  | ||||
| 							/* send final chunk if we're in chunked transfer mode */ | ||||
| 							ensure(uh_http_send(cl, req, "", 0)); | ||||
| 							ensure_out(uh_http_send(cl, req, "", 0)); | ||||
| 							break; | ||||
| 						} | ||||
| 					} | ||||
| @@ -561,13 +568,13 @@ void uh_cgi_request( | ||||
| 				{ | ||||
| 					if( (errno != EINTR) && ! header_sent ) | ||||
| 					{ | ||||
| 						ensure(uh_http_sendhf(cl, 504, "Gateway Timeout", | ||||
| 						ensure_out(uh_http_sendhf(cl, 504, "Gateway Timeout", | ||||
| 							"The CGI script took too long to produce " | ||||
| 							"a response")); | ||||
| 					} | ||||
|  | ||||
| 					/* send final chunk if we're in chunked transfer mode */ | ||||
| 					ensure(uh_http_send(cl, req, "", 0)); | ||||
| 					ensure_out(uh_http_send(cl, req, "", 0)); | ||||
|  | ||||
| 					break; | ||||
| 				} | ||||
|   | ||||
| @@ -97,8 +97,6 @@ static char * uh_file_header_lookup(struct http_request *req, const char *name) | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| #define ensure_ret(x) \ | ||||
| 	do { if( x < 0 ) return -1; } while(0) | ||||
|  | ||||
| static int uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s) | ||||
| { | ||||
| @@ -132,7 +130,7 @@ static int uh_file_response_412(struct client *cl, struct http_request *req) | ||||
| 		"Connection: close\r\n", req->version); | ||||
| } | ||||
|  | ||||
| static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s) | ||||
| static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s, int *ok) | ||||
| { | ||||
| 	const char *tag = uh_file_mktag(s); | ||||
| 	char *hdr = uh_file_header_lookup(req, "If-Match"); | ||||
| @@ -152,43 +150,44 @@ static int uh_file_if_match(struct client *cl, struct http_request *req, struct | ||||
| 			} | ||||
| 			else if( !strcmp(p, "*") || !strcmp(p, tag) ) | ||||
| 			{ | ||||
| 				return 1; | ||||
| 				*ok = 1; | ||||
| 				return *ok; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		uh_file_response_412(cl, req); | ||||
| 		return 0; | ||||
| 		*ok = 0; | ||||
| 		ensure_ret(uh_file_response_412(cl, req)); | ||||
| 		return *ok; | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| 	*ok = 1; | ||||
| 	return *ok; | ||||
| } | ||||
|  | ||||
| static int uh_file_if_modified_since(struct client *cl, struct http_request *req, struct stat *s) | ||||
| static int uh_file_if_modified_since(struct client *cl, struct http_request *req, struct stat *s, int *ok) | ||||
| { | ||||
| 	char *hdr = uh_file_header_lookup(req, "If-Modified-Since"); | ||||
| 	*ok = 1; | ||||
|  | ||||
| 	if( hdr ) | ||||
| 	{ | ||||
| 		if( uh_file_date2unix(hdr) < s->st_mtime ) | ||||
| 		if( uh_file_date2unix(hdr) >= s->st_mtime ) | ||||
| 		{ | ||||
| 			return 1; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			uh_file_response_304(cl, req, s); | ||||
| 			return 0; | ||||
| 			*ok = 0; | ||||
| 			ensure_ret(uh_file_response_304(cl, req, s)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| 	return *ok; | ||||
| } | ||||
|  | ||||
| static int uh_file_if_none_match(struct client *cl, struct http_request *req, struct stat *s) | ||||
| static int uh_file_if_none_match(struct client *cl, struct http_request *req, struct stat *s, int *ok) | ||||
| { | ||||
| 	const char *tag = uh_file_mktag(s); | ||||
| 	char *hdr = uh_file_header_lookup(req, "If-None-Match"); | ||||
| 	char *p; | ||||
| 	int i; | ||||
| 	*ok = 1; | ||||
|  | ||||
| 	if( hdr ) | ||||
| 	{ | ||||
| @@ -203,53 +202,54 @@ static int uh_file_if_none_match(struct client *cl, struct http_request *req, st | ||||
| 			} | ||||
| 			else if( !strcmp(p, "*") || !strcmp(p, tag) ) | ||||
| 			{ | ||||
| 				*ok = 0; | ||||
|  | ||||
| 				if( (req->method == UH_HTTP_MSG_GET) || | ||||
| 				    (req->method == UH_HTTP_MSG_HEAD) ) | ||||
| 					uh_file_response_304(cl, req, s); | ||||
| 					ensure_ret(uh_file_response_304(cl, req, s)); | ||||
| 				else | ||||
| 					uh_file_response_412(cl, req); | ||||
| 					ensure_ret(uh_file_response_412(cl, req)); | ||||
|  | ||||
| 				return 0; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| 	return *ok; | ||||
| } | ||||
|  | ||||
| static int uh_file_if_range(struct client *cl, struct http_request *req, struct stat *s) | ||||
| static int uh_file_if_range(struct client *cl, struct http_request *req, struct stat *s, int *ok) | ||||
| { | ||||
| 	char *hdr = uh_file_header_lookup(req, "If-Range"); | ||||
| 	*ok = 1; | ||||
|  | ||||
| 	if( hdr ) | ||||
| 	{ | ||||
| 		uh_file_response_412(cl, req); | ||||
| 		return 0; | ||||
| 		*ok = 0; | ||||
| 		ensure_ret(uh_file_response_412(cl, req)); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| 	return *ok; | ||||
| } | ||||
|  | ||||
| static int uh_file_if_unmodified_since(struct client *cl, struct http_request *req, struct stat *s) | ||||
| static int uh_file_if_unmodified_since(struct client *cl, struct http_request *req, struct stat *s, int *ok) | ||||
| { | ||||
| 	char *hdr = uh_file_header_lookup(req, "If-Unmodified-Since"); | ||||
| 	*ok = 1; | ||||
|  | ||||
| 	if( hdr ) | ||||
| 	{ | ||||
| 		if( uh_file_date2unix(hdr) <= s->st_mtime ) | ||||
| 		{ | ||||
| 			uh_file_response_412(cl, req); | ||||
| 			return 0; | ||||
| 			*ok = 0; | ||||
| 			ensure_ret(uh_file_response_412(cl, req)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| 	return *ok; | ||||
| } | ||||
|  | ||||
|  | ||||
| #define ensure_out(x) \ | ||||
| 	do { if( x < 0 ) goto out; } while(0) | ||||
|  | ||||
| static int uh_file_scandir_filter_dir(const struct dirent *e) | ||||
| { | ||||
| 	return strcmp(e->d_name, ".") ? 1 : 0; | ||||
| @@ -335,6 +335,7 @@ out: | ||||
| void uh_file_request(struct client *cl, struct http_request *req, struct path_info *pi) | ||||
| { | ||||
| 	int rlen; | ||||
| 	int ok = 1; | ||||
| 	int fd = -1; | ||||
| 	char buf[UH_LIMIT_MSGHEAD]; | ||||
|  | ||||
| @@ -342,13 +343,14 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in | ||||
| 	if( (pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0) ) | ||||
| 	{ | ||||
| 		/* test preconditions */ | ||||
| 		if( | ||||
| 			uh_file_if_modified_since(cl, req, &pi->stat)  	&& | ||||
| 			uh_file_if_match(cl, req, &pi->stat)           	&& | ||||
| 			uh_file_if_range(cl, req, &pi->stat)           	&& | ||||
| 			uh_file_if_unmodified_since(cl, req, &pi->stat)	&& | ||||
| 			uh_file_if_none_match(cl, req, &pi->stat) | ||||
| 		) { | ||||
| 		if(ok) ensure_out(uh_file_if_modified_since(cl, req, &pi->stat, &ok)); | ||||
| 		if(ok) ensure_out(uh_file_if_match(cl, req, &pi->stat, &ok)); | ||||
| 		if(ok) ensure_out(uh_file_if_range(cl, req, &pi->stat, &ok)); | ||||
| 		if(ok) ensure_out(uh_file_if_unmodified_since(cl, req, &pi->stat, &ok)); | ||||
| 		if(ok) ensure_out(uh_file_if_none_match(cl, req, &pi->stat, &ok)); | ||||
|  | ||||
| 		if( ok > 0 ) | ||||
| 		{ | ||||
| 			/* write status */ | ||||
| 			ensure_out(uh_file_response_200(cl, req, &pi->stat)); | ||||
|  | ||||
|   | ||||
| @@ -70,12 +70,14 @@ void uh_tls_client_accept(struct client *c) | ||||
|  | ||||
| int uh_tls_client_recv(struct client *c, void *buf, int len) | ||||
| { | ||||
| 	return SSL_read(c->tls, buf, len); | ||||
| 	int rv = SSL_read(c->tls, buf, len); | ||||
| 	return (rv > 0) ? rv : -1; | ||||
| } | ||||
|  | ||||
| int uh_tls_client_send(struct client *c, void *buf, int len) | ||||
| { | ||||
| 	return SSL_write(c->tls, buf, len); | ||||
| 	int rv = SSL_write(c->tls, buf, len); | ||||
| 	return (rv > 0) ? rv : -1; | ||||
| } | ||||
|  | ||||
| void uh_tls_client_close(struct client *c) | ||||
|   | ||||
| @@ -112,6 +112,7 @@ int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t) | ||||
| 	/* unblock SIGCHLD */ | ||||
| 	sigemptyset(&ssn); | ||||
| 	sigaddset(&ssn, SIGCHLD); | ||||
| 	sigaddset(&ssn, SIGPIPE); | ||||
| 	sigprocmask(SIG_UNBLOCK, &ssn, &sso); | ||||
|  | ||||
| 	rv = select(n, r, w, e, t); | ||||
| @@ -193,8 +194,6 @@ int uh_tcp_recv(struct client *cl, char *buf, int len) | ||||
| 	return sz; | ||||
| } | ||||
|  | ||||
| #define ensure(x) \ | ||||
| 	do { if( x < 0 ) return -1; } while(0) | ||||
|  | ||||
| int uh_http_sendhf(struct client *cl, int code, const char *summary, const char *fmt, ...) | ||||
| { | ||||
| @@ -211,14 +210,14 @@ int uh_http_sendhf(struct client *cl, int code, const char *summary, const char | ||||
| 			code, summary | ||||
| 	); | ||||
|  | ||||
| 	ensure(uh_tcp_send(cl, buffer, len)); | ||||
| 	ensure_ret(uh_tcp_send(cl, buffer, len)); | ||||
|  | ||||
| 	va_start(ap, fmt); | ||||
| 	len = vsnprintf(buffer, sizeof(buffer), fmt, ap); | ||||
| 	va_end(ap); | ||||
|  | ||||
| 	ensure(uh_http_sendc(cl, buffer, len)); | ||||
| 	ensure(uh_http_sendc(cl, NULL, 0)); | ||||
| 	ensure_ret(uh_http_sendc(cl, buffer, len)); | ||||
| 	ensure_ret(uh_http_sendc(cl, NULL, 0)); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -235,13 +234,13 @@ int uh_http_sendc(struct client *cl, const char *data, int len) | ||||
| 	if( len > 0 ) | ||||
| 	{ | ||||
| 	 	clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len); | ||||
| 		ensure(uh_tcp_send(cl, chunk, clen)); | ||||
| 		ensure(uh_tcp_send(cl, data, len)); | ||||
| 		ensure(uh_tcp_send(cl, "\r\n", 2)); | ||||
| 		ensure_ret(uh_tcp_send(cl, chunk, clen)); | ||||
| 		ensure_ret(uh_tcp_send(cl, data, len)); | ||||
| 		ensure_ret(uh_tcp_send(cl, "\r\n", 2)); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		ensure(uh_tcp_send(cl, "0\r\n\r\n", 5)); | ||||
| 		ensure_ret(uh_tcp_send(cl, "0\r\n\r\n", 5)); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| @@ -259,9 +258,9 @@ int uh_http_sendf( | ||||
| 	va_end(ap); | ||||
|  | ||||
| 	if( (req != NULL) && (req->version > 1.0) ) | ||||
| 		ensure(uh_http_sendc(cl, buffer, len)); | ||||
| 		ensure_ret(uh_http_sendc(cl, buffer, len)); | ||||
| 	else if( len > 0 ) | ||||
| 		ensure(uh_tcp_send(cl, buffer, len)); | ||||
| 		ensure_ret(uh_tcp_send(cl, buffer, len)); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -273,9 +272,9 @@ int uh_http_send( | ||||
| 		len = strlen(buf); | ||||
|  | ||||
| 	if( (req != NULL) && (req->version > 1.0) ) | ||||
| 		ensure(uh_http_sendc(cl, buf, len)); | ||||
| 		ensure_ret(uh_http_sendc(cl, buf, len)); | ||||
| 	else if( len > 0 ) | ||||
| 		ensure(uh_tcp_send(cl, buf, len)); | ||||
| 		ensure_ret(uh_tcp_send(cl, buf, len)); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|   | ||||
| @@ -36,6 +36,13 @@ | ||||
| #define fd_cloexec(fd) \ | ||||
| 	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) | ||||
|  | ||||
| #define ensure_out(x) \ | ||||
| 	do { if((x) < 0) goto out; } while(0) | ||||
|  | ||||
| #define ensure_ret(x) \ | ||||
| 	do { if((x) < 0) return -1; } while(0) | ||||
|  | ||||
|  | ||||
| struct path_info { | ||||
| 	char *root; | ||||
| 	char *phys; | ||||
|   | ||||
| @@ -96,17 +96,18 @@ static void uh_config_parse(struct config *conf) | ||||
| 				conf->error_handler = strdup(col1); | ||||
| 			} | ||||
| #ifdef HAVE_CGI | ||||
| 			else if( (line[0] == '.') && (strchr(line, ':') != NULL) ) | ||||
| 			else if( (line[0] == '*') && (strchr(line, ':') != NULL) ) | ||||
| 			{ | ||||
| 				if( !(col1 = strchr(line, ':')) || (*col1++ = 0) || | ||||
| 				    !(eol = strchr(col1, '\n')) || (*eol++  = 0) ) | ||||
| 				if( !(col1 = strchr(line, '*')) || (*col1++ = 0) || | ||||
| 				    !(col2 = strchr(col1, ':')) || (*col2++ = 0) || | ||||
| 				    !(eol = strchr(col2, '\n')) || (*eol++  = 0) ) | ||||
| 						continue; | ||||
|  | ||||
| 				if( !uh_interpreter_add(line, col1) ) | ||||
| 				if( !uh_interpreter_add(col1, col2) ) | ||||
| 				{ | ||||
| 					fprintf(stderr, | ||||
| 						"Unable to add interpreter %s for extension %s: " | ||||
| 						"Out of memory\n", col1, line | ||||
| 						"Out of memory\n", col2, col1 | ||||
| 					); | ||||
| 				} | ||||
| 			} | ||||
| @@ -126,6 +127,10 @@ static int uh_socket_bind( | ||||
| 	int status; | ||||
| 	int bound = 0; | ||||
|  | ||||
| 	int tcp_ka_idl = 1; | ||||
| 	int tcp_ka_int = 1; | ||||
| 	int tcp_ka_cnt = 3; | ||||
|  | ||||
| 	struct listener *l = NULL; | ||||
| 	struct addrinfo *addrs = NULL, *p = NULL; | ||||
|  | ||||
| @@ -145,12 +150,22 @@ static int uh_socket_bind( | ||||
| 		} | ||||
|  | ||||
| 		/* "address already in use" */ | ||||
| 		if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1 ) | ||||
| 		if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) ) | ||||
| 		{ | ||||
| 			perror("setsockopt()"); | ||||
| 			goto error; | ||||
| 		} | ||||
|  | ||||
| 		/* TCP keep-alive */ | ||||
| 		if( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) || | ||||
| 		    setsockopt(sock, SOL_TCP, TCP_KEEPIDLE,  &tcp_ka_idl, sizeof(tcp_ka_idl)) || | ||||
| 		    setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) || | ||||
| 		    setsockopt(sock, SOL_TCP, TCP_KEEPCNT,   &tcp_ka_cnt, sizeof(tcp_ka_cnt)) ) | ||||
| 		{ | ||||
| 		    fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n", | ||||
| 		    	strerror(errno)); | ||||
| 		} | ||||
|  | ||||
| 		/* required to get parallel v4 + v6 working */ | ||||
| 		if( p->ai_family == AF_INET6 ) | ||||
| 		{ | ||||
| @@ -355,7 +370,6 @@ static struct http_request * uh_http_header_recv(struct client *cl) | ||||
| 	ssize_t blen = sizeof(buffer)-1; | ||||
| 	ssize_t rlen = 0; | ||||
|  | ||||
|  | ||||
| 	memset(buffer, 0, sizeof(buffer)); | ||||
|  | ||||
| 	while( blen > 0 ) | ||||
| @@ -371,20 +385,22 @@ static struct http_request * uh_http_header_recv(struct client *cl) | ||||
| 		if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 ) | ||||
| 		{ | ||||
| 			/* receive data */ | ||||
| 			rlen = uh_tcp_peek(cl, bufptr, blen); | ||||
| 			ensure_out(rlen = uh_tcp_peek(cl, bufptr, blen)); | ||||
|  | ||||
| 			if( rlen > 0 ) | ||||
| 			{ | ||||
| 			if( (idxptr = strfind(buffer, sizeof(buffer), "\r\n\r\n", 4)) ) | ||||
| 			{ | ||||
| 					blen -= uh_tcp_recv(cl, bufptr, (int)(idxptr - bufptr) + 4); | ||||
| 				ensure_out(rlen = uh_tcp_recv(cl, bufptr, | ||||
| 					(int)(idxptr - bufptr) + 4)); | ||||
|  | ||||
| 				/* header read complete ... */ | ||||
| 					return uh_http_header_parse(cl, buffer, sizeof(buffer) - blen - 1); | ||||
| 				blen -= rlen; | ||||
| 				return uh_http_header_parse(cl, buffer, | ||||
| 					sizeof(buffer) - blen - 1); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 					rlen = uh_tcp_recv(cl, bufptr, rlen); | ||||
| 				ensure_out(rlen = uh_tcp_recv(cl, bufptr, rlen)); | ||||
|  | ||||
| 				blen -= rlen; | ||||
| 				bufptr += rlen; | ||||
| 			} | ||||
| @@ -392,20 +408,14 @@ static struct http_request * uh_http_header_recv(struct client *cl) | ||||
| 		else | ||||
| 		{ | ||||
| 			/* invalid request (unexpected eof/timeout) */ | ||||
| 				uh_http_response(cl, 408, "Request Timeout"); | ||||
| 				return NULL; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			/* invalid request (unexpected eof/timeout) */ | ||||
| 			uh_http_response(cl, 408, "Request Timeout"); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* request entity too large */ | ||||
| 	uh_http_response(cl, 413, "Request Entity Too Large"); | ||||
|  | ||||
| out: | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -28,6 +28,7 @@ | ||||
| #include <sys/select.h> | ||||
| #include <sys/wait.h> | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/tcp.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <linux/limits.h> | ||||
| #include <netdb.h> | ||||
| @@ -44,6 +45,11 @@ | ||||
| #include <openssl/ssl.h> | ||||
| #endif | ||||
|  | ||||
| /* uClibc... */ | ||||
| #ifndef SOL_TCP | ||||
| #define SOL_TCP	6 | ||||
| #endif | ||||
|  | ||||
|  | ||||
| #define UH_LIMIT_MSGHEAD	4096 | ||||
| #define UH_LIMIT_HEADERS	64 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jo-Philipp Wich
					Jo-Philipp Wich