diff options
| -rw-r--r-- | package/uhttpd/Makefile | 2 | ||||
| -rw-r--r-- | package/uhttpd/files/uhttpd.config | 7 | ||||
| -rwxr-xr-x | package/uhttpd/files/uhttpd.init | 7 | ||||
| -rw-r--r-- | package/uhttpd/src/uhttpd-cgi.c | 19 | ||||
| -rw-r--r-- | package/uhttpd/src/uhttpd-cgi.h | 3 | ||||
| -rw-r--r-- | package/uhttpd/src/uhttpd-file.c | 24 | ||||
| -rw-r--r-- | package/uhttpd/src/uhttpd-utils.c | 123 | ||||
| -rw-r--r-- | package/uhttpd/src/uhttpd-utils.h | 5 | ||||
| -rw-r--r-- | package/uhttpd/src/uhttpd.c | 414 | ||||
| -rw-r--r-- | package/uhttpd/src/uhttpd.h | 15 | 
10 files changed, 364 insertions, 255 deletions
| diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile index cb85ad88c..de9eee9e9 100644 --- a/package/uhttpd/Makefile +++ b/package/uhttpd/Makefile @@ -8,7 +8,7 @@  include $(TOPDIR)/rules.mk  PKG_NAME:=uhttpd -PKG_RELEASE:=14 +PKG_RELEASE:=15  PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)  PKG_BUILD_DEPENDS := libcyassl liblua diff --git a/package/uhttpd/files/uhttpd.config b/package/uhttpd/files/uhttpd.config index 534e8f8b2..a29910a65 100644 --- a/package/uhttpd/files/uhttpd.config +++ b/package/uhttpd/files/uhttpd.config @@ -27,6 +27,13 @@ config uhttpd main  	# Default is /cgi-bin  	option cgi_prefix	/cgi-bin +	# List of extension->interpreter mappings. +	# Files with an associated interpreter can +	# be called outside of the CGI prefix and do +	# not need to be executable. +#	list interpreter	".php=/usr/bin/php-cgi" +#	list interpreter	".cgi=/usr/bin/perl" +  	# Lua url prefix and handler script.  	# Lua support is disabled if no prefix given.  #	option lua_prefix	/luci diff --git a/package/uhttpd/files/uhttpd.init b/package/uhttpd/files/uhttpd.init index 8221d859b..f8f1754e9 100755 --- a/package/uhttpd/files/uhttpd.init +++ b/package/uhttpd/files/uhttpd.init @@ -56,7 +56,7 @@ start_instance()  	local cfg="$1"  	local realm="$(uci_get system.@system[0].hostname)" -	local listen http https +	local listen http https interpreter path  	append_arg "$cfg" home "-h"  	append_arg "$cfg" realm "-r" "${realm:-OpenWrt}" @@ -78,6 +78,11 @@ start_instance()  		append UHTTPD_ARGS "-p $listen"  	done +	config_get interpreter "$cfg" interpreter +	for path in $interpreter; do +		append UHTTPD_ARGS "-i $path" +	done +  	config_get https "$cfg" listen_https  	config_get UHTTPD_KEY  "$cfg" key  /etc/uhttpd.key  	config_get UHTTPD_CERT "$cfg" cert /etc/uhttpd.crt diff --git a/package/uhttpd/src/uhttpd-cgi.c b/package/uhttpd/src/uhttpd-cgi.c index 086124916..f9dd9810d 100644 --- a/package/uhttpd/src/uhttpd-cgi.c +++ b/package/uhttpd/src/uhttpd-cgi.c @@ -135,8 +135,10 @@ static int uh_cgi_error_500(struct client *cl, struct http_request *req, const c  } -void uh_cgi_request(struct client *cl, struct http_request *req, struct path_info *pi) -{ +void uh_cgi_request( +	struct client *cl, struct http_request *req, +	struct path_info *pi, struct interpreter *ip +) {  	int i, hdroff, bufoff;  	int hdrlen = 0;  	int buflen = 0; @@ -199,9 +201,9 @@ void uh_cgi_request(struct client *cl, struct http_request *req, struct path_inf  			dup2(rfd[1], 1);  			dup2(wfd[0], 0); -			/* check for regular, world-executable file */ -			if( (pi->stat.st_mode & S_IFREG) && -			    (pi->stat.st_mode & S_IXOTH) +			/* check for regular, world-executable file _or_ interpreter */ +			if( ((pi->stat.st_mode & S_IFREG) && +			     (pi->stat.st_mode & S_IXOTH)) || (ip != NULL)  			) {  				/* build environment */  				clearenv(); @@ -320,14 +322,17 @@ void uh_cgi_request(struct client *cl, struct http_request *req, struct path_inf  				if( chdir(pi->root) )  					perror("chdir()"); -				execl(pi->phys, pi->phys, NULL); +				if( ip != NULL ) +					execl(ip->path, ip->path, pi->phys, NULL); +				else +					execl(pi->phys, pi->phys, NULL);  				/* in case it fails ... */  				printf(  					"Status: 500 Internal Server Error\r\n\r\n"  					"Unable to launch the requested CGI program:\n"  					"  %s: %s\n", -						pi->phys, strerror(errno) +						ip ? ip->path : pi->phys, strerror(errno)  				);  			} diff --git a/package/uhttpd/src/uhttpd-cgi.h b/package/uhttpd/src/uhttpd-cgi.h index c90557d8f..cb84dae0c 100644 --- a/package/uhttpd/src/uhttpd-cgi.h +++ b/package/uhttpd/src/uhttpd-cgi.h @@ -25,7 +25,8 @@  #include <linux/limits.h>  void uh_cgi_request( -	struct client *cl, struct http_request *req, struct path_info *pi +	struct client *cl, struct http_request *req, +	struct path_info *pi, struct interpreter *ip  );  #endif diff --git a/package/uhttpd/src/uhttpd-file.c b/package/uhttpd/src/uhttpd-file.c index ef9a77b6c..25a5f6ece 100644 --- a/package/uhttpd/src/uhttpd-file.c +++ b/package/uhttpd/src/uhttpd-file.c @@ -98,9 +98,9 @@ static char * uh_file_header_lookup(struct http_request *req, const char *name)  }  #define ensure_ret(x) \ -	do { if( x < 0 ) return; } while(0) +	do { if( x < 0 ) return -1; } while(0) -static void uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s)  {  	ensure_ret(uh_http_sendf(cl, NULL, "Connection: close\r\n")); @@ -110,26 +110,26 @@ static void uh_file_response_ok_hdrs(struct client *cl, struct http_request *req  		ensure_ret(uh_http_sendf(cl, NULL, "Last-Modified: %s\r\n", uh_file_unix2date(s->st_mtime)));  	} -	ensure_ret(uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL)))); +	return uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL)));  } -static void uh_file_response_200(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_response_200(struct client *cl, struct http_request *req, struct stat *s)  {  	ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version)); -	uh_file_response_ok_hdrs(cl, req, s); +	return uh_file_response_ok_hdrs(cl, req, s);  } -static void uh_file_response_304(struct client *cl, struct http_request *req, struct stat *s) +static int uh_file_response_304(struct client *cl, struct http_request *req, struct stat *s)  {  	ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version)); -	uh_file_response_ok_hdrs(cl, req, s); +	return uh_file_response_ok_hdrs(cl, req, s);  } -static void uh_file_response_412(struct client *cl, struct http_request *req) +static int uh_file_response_412(struct client *cl, struct http_request *req)  { -	ensure_ret(uh_http_sendf(cl, NULL, +	return uh_http_sendf(cl, NULL,  		"HTTP/%.1f 412 Precondition Failed\r\n" -		"Connection: close\r\n", req->version)); +		"Connection: close\r\n", req->version);  }  static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s) @@ -350,7 +350,7 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in  			uh_file_if_none_match(cl, req, &pi->stat)  		) {  			/* write status */ -			uh_file_response_200(cl, req, &pi->stat); +			ensure_out(uh_file_response_200(cl, req, &pi->stat));  			ensure_out(uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name)));  			ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size)); @@ -385,7 +385,7 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in  	else if( (pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists )  	{  		/* write status */ -		uh_file_response_200(cl, req, NULL); +		ensure_out(uh_file_response_200(cl, req, NULL));  		if( req->version > 1.0 )  			ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c index 4a1423c71..e68926e93 100644 --- a/package/uhttpd/src/uhttpd-utils.c +++ b/package/uhttpd/src/uhttpd-utils.c @@ -605,8 +605,7 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)  } -static char uh_realms[UH_LIMIT_AUTHREALMS * sizeof(struct auth_realm)] = { 0 }; -static int uh_realm_count = 0; +static struct auth_realm *uh_realms = NULL;  struct auth_realm * uh_auth_add(char *path, char *user, char *pass)  { @@ -614,11 +613,8 @@ struct auth_realm * uh_auth_add(char *path, char *user, char *pass)  	struct passwd *pwd;  	struct spwd *spwd; -	if( uh_realm_count < UH_LIMIT_AUTHREALMS ) +	if((new = (struct auth_realm *)malloc(sizeof(struct auth_realm))) != NULL)  	{ -		new = (struct auth_realm *) -			&uh_realms[uh_realm_count * sizeof(struct auth_realm)]; -  		memset(new, 0, sizeof(struct auth_realm));  		memcpy(new->path, path, @@ -655,9 +651,13 @@ struct auth_realm * uh_auth_add(char *path, char *user, char *pass)  		if( new->pass[0] )  		{ -			uh_realm_count++; +			new->next = uh_realms; +			uh_realms = new; +  			return new;  		} + +		free(new);  	}  	return NULL; @@ -677,11 +677,8 @@ int uh_auth_check(  	protected = 0;  	/* check whether at least one realm covers the requested url */ -	for( i = 0; i < uh_realm_count; i++ ) +	for( realm = uh_realms; realm; realm = realm->next )  	{ -		realm = (struct auth_realm *) -			&uh_realms[i * sizeof(struct auth_realm)]; -  		rlen = strlen(realm->path);  		if( (plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen) ) @@ -721,11 +718,8 @@ int uh_auth_check(  		if( user && pass )  		{  			/* find matching realm */ -			for( i = 0, realm = NULL; i < uh_realm_count; i++ ) +			for( realm = uh_realms; realm; realm = realm->next )  			{ -				realm = (struct auth_realm *) -					&uh_realms[i * sizeof(struct auth_realm)]; -  				rlen = strlen(realm->path);  				if( (plen >= rlen) && @@ -769,22 +763,17 @@ int uh_auth_check(  } -static char uh_listeners[UH_LIMIT_LISTENERS * sizeof(struct listener)] = { 0 }; -static char uh_clients[UH_LIMIT_CLIENTS * sizeof(struct client)] = { 0 }; - -static int uh_listener_count = 0; -static int uh_client_count = 0; - +static struct listener *uh_listeners = NULL; +static struct client *uh_clients = NULL;  struct listener * uh_listener_add(int sock, struct config *conf)  {  	struct listener *new = NULL;  	socklen_t sl; -	if( uh_listener_count < UH_LIMIT_LISTENERS ) +	if( (new = (struct listener *)malloc(sizeof(struct listener))) != NULL )  	{ -		new = (struct listener *) -			&uh_listeners[uh_listener_count * sizeof(struct listener)]; +		memset(new, 0, sizeof(struct listener));  		new->socket = sock;  		new->conf   = conf; @@ -794,24 +783,22 @@ struct listener * uh_listener_add(int sock, struct config *conf)  		memset(&(new->addr), 0, sl);  		getsockname(sock, (struct sockaddr *) &(new->addr), &sl); -		uh_listener_count++; +		new->next = uh_listeners; +		uh_listeners = new; + +		return new;  	} -	return new; +	return NULL;  }  struct listener * uh_listener_lookup(int sock)  {  	struct listener *cur = NULL; -	int i; - -	for( i = 0; i < uh_listener_count; i++ ) -	{ -		cur = (struct listener *) &uh_listeners[i * sizeof(struct listener)]; +	for( cur = uh_listeners; cur; cur = cur->next )  		if( cur->socket == sock )  			return cur; -	}  	return NULL;  } @@ -822,10 +809,9 @@ struct client * uh_client_add(int sock, struct listener *serv)  	struct client *new = NULL;  	socklen_t sl; -	if( uh_client_count < UH_LIMIT_CLIENTS ) +	if( (new = (struct client *)malloc(sizeof(struct client))) != NULL )  	{ -		new = (struct client *) -			&uh_clients[uh_client_count * sizeof(struct client)]; +		memset(new, 0, sizeof(struct client));  		new->socket = sock;  		new->server = serv; @@ -840,7 +826,8 @@ struct client * uh_client_add(int sock, struct listener *serv)  		memset(&(new->servaddr), 0, sl);  		getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl); -		uh_client_count++; +		new->next = uh_clients; +		uh_clients = new;  	}  	return new; @@ -849,30 +836,72 @@ struct client * uh_client_add(int sock, struct listener *serv)  struct client * uh_client_lookup(int sock)  {  	struct client *cur = NULL; -	int i; - -	for( i = 0; i < uh_client_count; i++ ) -	{ -		cur = (struct client *) &uh_clients[i * sizeof(struct client)]; +	for( cur = uh_clients; cur; cur = cur->next )  		if( cur->socket == sock )  			return cur; -	}  	return NULL;  }  void uh_client_remove(int sock)  { -	struct client *del = uh_client_lookup(sock); +	struct client *cur = NULL; +	struct client *prv = NULL; + +	for( cur = uh_clients; cur; prv = cur, cur = cur->next ) +	{ +		if( cur->socket == sock ) +		{ +			if( prv ) +				prv->next = cur->next; +			else +				uh_clients = cur->next; + +			free(cur); +			break; +		} +	} +} + + +#ifdef HAVE_CGI +static struct interpreter *uh_interpreters = NULL; + +struct interpreter * uh_interpreter_add(const char *extn, const char *path) +{ +	struct interpreter *new = NULL; -	if( del ) +	if( (new = (struct interpreter *) +			malloc(sizeof(struct interpreter))) != NULL )  	{ -		memmove(del, del + 1, -			sizeof(uh_clients) - (int)((char *)del - uh_clients) - sizeof(struct client)); +		memset(new, 0, sizeof(struct interpreter)); + +		memcpy(new->extn, extn, min(strlen(extn), sizeof(new->extn)-1)); +		memcpy(new->path, path, min(strlen(path), sizeof(new->path)-1)); + +		new->next = uh_interpreters; +		uh_interpreters = new; -		uh_client_count--; +		return new;  	} + +	return NULL;  } +struct interpreter * uh_interpreter_lookup(const char *path) +{ +	struct interpreter *cur = NULL; +	const char *e; + +	for( cur = uh_interpreters; cur; cur = cur->next ) +	{ +		e = &path[max(strlen(path) - strlen(cur->extn), 0)]; +		if( !strcmp(e, cur->extn) ) +			return cur; +	} + +	return NULL; +} +#endif diff --git a/package/uhttpd/src/uhttpd-utils.h b/package/uhttpd/src/uhttpd-utils.h index 1b1826541..95535d6fe 100644 --- a/package/uhttpd/src/uhttpd-utils.h +++ b/package/uhttpd/src/uhttpd-utils.h @@ -101,4 +101,9 @@ struct client * uh_client_add(int sock, struct listener *serv);  struct client * uh_client_lookup(int sock);  void uh_client_remove(int sock); +#ifdef HAVE_CGI +struct interpreter * uh_interpreter_add(const char *extn, const char *path); +struct interpreter * uh_interpreter_lookup(const char *path); +#endif +  #endif diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c index 764ff7d57..6406e459a 100644 --- a/package/uhttpd/src/uhttpd.c +++ b/package/uhttpd/src/uhttpd.c @@ -51,8 +51,8 @@ static void uh_config_parse(struct config *conf)  {  	FILE *c;  	char line[512]; -	char *user = NULL; -	char *pass = NULL; +	char *col1 = NULL; +	char *col2 = NULL;  	char *eol  = NULL;  	const char *path = conf->file ? conf->file : "/etc/httpd.conf"; @@ -66,35 +66,51 @@ static void uh_config_parse(struct config *conf)  		{  			if( (line[0] == '/') && (strchr(line, ':') != NULL) )  			{ -				if( !(user = strchr(line, ':')) || (*user++ = 0) || -				    !(pass = strchr(user, ':')) || (*pass++ = 0) || -					!(eol = strchr(pass, '\n')) || (*eol++  = 0) ) +				if( !(col1 = strchr(line, ':')) || (*col1++ = 0) || +				    !(col2 = strchr(col1, ':')) || (*col2++ = 0) || +					!(eol = strchr(col2, '\n')) || (*eol++  = 0) )  						continue; -				if( !uh_auth_add(line, user, pass) ) +				if( !uh_auth_add(line, col1, col2) )  				{  					fprintf(stderr,  						"Notice: No password set for user %s, ignoring " -						"authentication on %s\n", user, line +						"authentication on %s\n", col1, line  					);  				}  			}  			else if( !strncmp(line, "I:", 2) )  			{ -				if( !(user = strchr(line, ':')) || (*user++ = 0) || -				    !(eol = strchr(user, '\n')) || (*eol++  = 0) ) +				if( !(col1 = strchr(line, ':')) || (*col1++ = 0) || +				    !(eol = strchr(col1, '\n')) || (*eol++  = 0) )  				    	continue; -				conf->index_file = strdup(user); +				conf->index_file = strdup(col1);  			}  			else if( !strncmp(line, "E404:", 5) )  			{ -				if( !(user = strchr(line, ':')) || (*user++ = 0) || -				    !(eol = strchr(user, '\n')) || (*eol++  = 0) ) +				if( !(col1 = strchr(line, ':')) || (*col1++ = 0) || +				    !(eol = strchr(col1, '\n')) || (*eol++  = 0) )  						continue; -				conf->error_handler = strdup(user); +				conf->error_handler = strdup(col1);  			} +#ifdef HAVE_CGI +			else if( (line[0] == '.') && (strchr(line, ':') != NULL) ) +			{ +				if( !(col1 = strchr(line, ':')) || (*col1++ = 0) || +				    !(eol = strchr(col1, '\n')) || (*eol++  = 0) ) +						continue; + +				if( !uh_interpreter_add(line, col1) ) +				{ +					fprintf(stderr, +						"Unable to add interpreter %s for extension %s: " +						"Out of memory\n", col1, line +					); +				} +			} +#endif  		}  		fclose(c); @@ -162,11 +178,7 @@ static int uh_socket_bind(  		/* add listener to global list */  		if( ! (l = uh_listener_add(sock, conf)) )  		{ -			fprintf(stderr, -				"uh_listener_add(): Can not create more than " -				"%i listen sockets\n", UH_LIMIT_LISTENERS -			); - +			fprintf(stderr, "uh_listener_add(): Failed to allocate memory\n");  			goto error;  		} @@ -397,6 +409,7 @@ static struct http_request * uh_http_header_recv(struct client *cl)  	return NULL;  } +#if defined(HAVE_LUA) || defined(HAVE_CGI)  static int uh_path_match(const char *prefix, const char *url)  {  	if( (strstr(url, prefix) == url) && @@ -409,23 +422,193 @@ static int uh_path_match(const char *prefix, const char *url)  	return 0;  } +#endif +static void uh_dispatch_request( +	struct client *cl, struct http_request *req, struct path_info *pin +) { +#ifdef HAVE_CGI +	struct interpreter *ipr = NULL; -int main (int argc, char **argv) +	if( uh_path_match(cl->server->conf->cgi_prefix, pin->name) || +		(ipr = uh_interpreter_lookup(pin->phys)) ) +	{ +		uh_cgi_request(cl, req, pin, ipr); +	} +	else +#endif +	{ +		uh_file_request(cl, req, pin); +	} +} + +static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)  { +	/* master file descriptor list */ +	fd_set used_fds, read_fds; + +	/* working structs */ +	struct http_request *req; +	struct path_info *pin; +	struct client *cl; + +	/* maximum file descriptor number */ +	int new_fd, cur_fd = 0; + +	/* clear the master and temp sets */ +	FD_ZERO(&used_fds); +	FD_ZERO(&read_fds); + +	/* backup server descriptor set */ +	used_fds = serv_fds; + +	/* loop */ +	while(run) +	{ +		/* create a working copy of the used fd set */ +		read_fds = used_fds; + +		/* sleep until socket activity */ +		if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 ) +		{ +			perror("select()"); +			exit(1); +		} + +		/* run through the existing connections looking for data to be read */ +		for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ ) +		{ +			/* is a socket managed by us */ +			if( FD_ISSET(cur_fd, &read_fds) ) +			{ +				/* is one of our listen sockets */ +				if( FD_ISSET(cur_fd, &serv_fds) ) +				{ +					/* handle new connections */ +					if( (new_fd = accept(cur_fd, NULL, 0)) != -1 ) +					{ +						/* add to global client list */ +						if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL ) +						{ +#ifdef HAVE_TLS +							/* setup client tls context */ +							if( conf->tls ) +								conf->tls_accept(cl); +#endif + +							/* add client socket to global fdset */ +							FD_SET(new_fd, &used_fds); +							fd_cloexec(new_fd); +							max_fd = max(max_fd, new_fd); +						} + +						/* insufficient resources */ +						else +						{ +							fprintf(stderr, +								"uh_client_add(): Cannot allocate memory\n"); + +							close(new_fd); +						} +					} +				} + +				/* is a client socket */ +				else +				{ +					if( ! (cl = uh_client_lookup(cur_fd)) ) +					{ +						/* this should not happen! */ +						fprintf(stderr, +							"uh_client_lookup(): No entry for fd %i!\n", +							cur_fd); + +						goto cleanup; +					} + +					/* parse message header */ +					if( (req = uh_http_header_recv(cl)) != NULL ) +					{ +						/* RFC1918 filtering required? */ +						if( conf->rfc1918_filter && +						    sa_rfc1918(&cl->peeraddr) && +						    !sa_rfc1918(&cl->servaddr) ) +						{ +							uh_http_sendhf(cl, 403, "Forbidden", +								"Rejected request from RFC1918 IP " +								"to public server address"); +						} +						else  #ifdef HAVE_LUA -	/* Lua runtime */ -	lua_State *L = NULL; +						/* Lua request? */ +						if( conf->lua_state && +						    uh_path_match(conf->lua_prefix, req->url) ) +						{ +							conf->lua_request(cl, req, conf->lua_state); +						} +						else  #endif +						/* dispatch request */ +						if( (pin = uh_path_lookup(cl, req->url)) != NULL ) +						{ +							/* auth ok? */ +							if( uh_auth_check(cl, req, pin) ) +								uh_dispatch_request(cl, req, pin); +						} +						/* 404 */ +						else +						{ +							/* Try to invoke an error handler */ +							pin = uh_path_lookup(cl, conf->error_handler); + +							if( pin && uh_auth_check(cl, req, pin) ) +							{ +								req->redirect_status = 404; +								uh_dispatch_request(cl, req, pin); +							} +							else +							{ +								uh_http_sendhf(cl, 404, "Not Found", +									"No such file or directory"); +							} +						} +					} + +#ifdef HAVE_TLS +					/* free client tls context */ +					if( conf->tls ) +						conf->tls_close(cl); +#endif + +					cleanup: + +					/* close client socket */ +					close(cur_fd); +					FD_CLR(cur_fd, &used_fds); + +					/* remove from global client list */ +					uh_client_remove(cur_fd); +				} +			} +		} +	} + +#ifdef HAVE_LUA +	/* destroy the Lua state */ +	if( conf->lua_state != NULL ) +		conf->lua_close(conf->lua_state); +#endif +} + + +int main (int argc, char **argv) +{  	/* master file descriptor list */  	fd_set used_fds, serv_fds, read_fds;  	/* working structs */  	struct addrinfo hints; -	struct http_request *req; -	struct path_info *pin; -	struct client *cl;  	struct sigaction sa;  	struct config conf; @@ -433,7 +616,7 @@ int main (int argc, char **argv)  	sigset_t ss;  	/* maximum file descriptor number */ -	int new_fd, cur_fd, max_fd = 0; +	int cur_fd, max_fd = 0;  #ifdef HAVE_TLS  	int tls = 0; @@ -525,7 +708,7 @@ int main (int argc, char **argv)  #endif  	while( (opt = getopt(argc, argv, -		"fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0 +		"fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:i:t:T:")) > 0  	) {  		switch(opt)  		{ @@ -658,6 +841,21 @@ int main (int argc, char **argv)  			case 'x':  				conf.cgi_prefix = optarg;  				break; + +			/* interpreter */ +			case 'i': +				if( (optarg[0] == '.') && (port = strchr(optarg, '=')) ) +				{ +					*port++ = 0; +					uh_interpreter_add(optarg, port); +				} +				else +				{ +					fprintf(stderr, "Error: Invalid interpreter: %s\n", +						optarg); +					exit(1); +				} +				break;  #endif  #ifdef HAVE_LUA @@ -740,6 +938,7 @@ int main (int argc, char **argv)  #endif  #ifdef HAVE_CGI  					"	-x string       URL prefix for CGI handler, default is '/cgi-bin'\n" +					"	-i .ext=path    Use interpreter at path for files with the given extension\n"  #endif  #if defined(HAVE_CGI) || defined(HAVE_LUA)  					"	-t seconds      CGI and Lua script timeout in seconds, default is 60\n" @@ -830,7 +1029,7 @@ int main (int argc, char **argv)  			if( ! conf.lua_prefix )  				conf.lua_prefix = "/lua"; -			L = conf.lua_init(conf.lua_handler); +			conf.lua_state = conf.lua_init(conf.lua_handler);  		}  	}  #endif @@ -865,166 +1064,13 @@ int main (int argc, char **argv)  		}  	} -	/* backup server descriptor set */ -	used_fds = serv_fds; - -	/* loop */ -	while(run) -	{ -		/* create a working copy of the used fd set */ -		read_fds = used_fds; - -		/* sleep until socket activity */ -		if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 ) -		{ -			perror("select()"); -			exit(1); -		} - -		/* run through the existing connections looking for data to be read */ -		for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ ) -		{ -			/* is a socket managed by us */ -			if( FD_ISSET(cur_fd, &read_fds) ) -			{ -				/* is one of our listen sockets */ -				if( FD_ISSET(cur_fd, &serv_fds) ) -				{ -					/* handle new connections */ -					if( (new_fd = accept(cur_fd, NULL, 0)) != -1 ) -					{ -						/* add to global client list */ -						if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL ) -						{ -#ifdef HAVE_TLS -							/* setup client tls context */ -							if( conf.tls ) -								conf.tls_accept(cl); -#endif - -							/* add client socket to global fdset */ -							FD_SET(new_fd, &used_fds); -							fd_cloexec(new_fd); -							max_fd = max(max_fd, new_fd); -						} - -						/* insufficient resources */ -						else -						{ -							fprintf(stderr, -								"uh_client_add(): Can not manage more than " -								"%i client sockets, connection dropped\n", -								UH_LIMIT_CLIENTS -							); - -							close(new_fd); -						} -					} -				} - -				/* is a client socket */ -				else -				{ -					if( ! (cl = uh_client_lookup(cur_fd)) ) -					{ -						/* this should not happen! */ -						fprintf(stderr, -							"uh_client_lookup(): No entry for fd %i!\n", -							cur_fd); - -						goto cleanup; -					} - -					/* parse message header */ -					if( (req = uh_http_header_recv(cl)) != NULL ) -					{ -						/* RFC1918 filtering required? */ -						if( conf.rfc1918_filter && sa_rfc1918(&cl->peeraddr) && -						    !sa_rfc1918(&cl->servaddr) ) -						{ -							uh_http_sendhf(cl, 403, "Forbidden", -								"Rejected request from RFC1918 IP to public server address"); -						} -						else -#ifdef HAVE_LUA -						/* Lua request? */ -						if( L && uh_path_match(conf.lua_prefix, req->url) ) -						{ -							conf.lua_request(cl, req, L); -						} -						else -#endif -						/* dispatch request */ -						if( (pin = uh_path_lookup(cl, req->url)) != NULL ) -						{ -							/* auth ok? */ -							if( uh_auth_check(cl, req, pin) ) -							{ -#ifdef HAVE_CGI -								if( uh_path_match(conf.cgi_prefix, pin->name) ) -								{ -									uh_cgi_request(cl, req, pin); -								} -								else -#endif -								{ -									uh_file_request(cl, req, pin); -								} -							} -						} - -						/* 404 */ -						else -						{ -							/* Try to invoke an error handler */ -							pin = uh_path_lookup(cl, conf.error_handler); - -							if( pin && uh_auth_check(cl, req, pin) ) -							{ -								req->redirect_status = 404; - -#ifdef HAVE_CGI -								if( uh_path_match(conf.cgi_prefix, pin->name) ) -								{ -									uh_cgi_request(cl, req, pin); -								} -								else -#endif -								{ -									uh_file_request(cl, req, pin); -								} -							} -							else -							{ -								uh_http_sendhf(cl, 404, "Not Found", -									"No such file or directory"); -							} -						} -					} - -#ifdef HAVE_TLS -					/* free client tls context */ -					if( conf.tls ) -						conf.tls_close(cl); -#endif - -					cleanup: - -					/* close client socket */ -					close(cur_fd); -					FD_CLR(cur_fd, &used_fds); - -					/* remove from global client list */ -					uh_client_remove(cur_fd); -				} -			} -		} -	} +	/* server main loop */ +	uh_mainloop(&conf, serv_fds, max_fd);  #ifdef HAVE_LUA  	/* destroy the Lua state */ -	if( L != NULL ) -		conf.lua_close(L); +	if( conf.lua_state != NULL ) +		conf.lua_close(conf.lua_state);  #endif  	return 0; diff --git a/package/uhttpd/src/uhttpd.h b/package/uhttpd/src/uhttpd.h index fd2176ebd..78cca7b3b 100644 --- a/package/uhttpd/src/uhttpd.h +++ b/package/uhttpd/src/uhttpd.h @@ -48,9 +48,7 @@  #define UH_LIMIT_MSGHEAD	4096  #define UH_LIMIT_HEADERS	64 -#define UH_LIMIT_LISTENERS	16  #define UH_LIMIT_CLIENTS	64 -#define UH_LIMIT_AUTHREALMS	8  #define UH_HTTP_MSG_GET		0  #define UH_HTTP_MSG_HEAD	1 @@ -58,6 +56,7 @@  struct listener;  struct client; +struct interpreter;  struct http_request;  struct config { @@ -76,6 +75,7 @@ struct config {  #ifdef HAVE_LUA  	char *lua_prefix;  	char *lua_handler; +	lua_State *lua_state;  	lua_State * (*lua_init) (const char *handler);  	void (*lua_close) (lua_State *L);  	void (*lua_request) (struct client *cl, struct http_request *req, lua_State *L); @@ -105,6 +105,7 @@ struct listener {  #ifdef HAVE_TLS  	SSL_CTX *tls;  #endif +	struct listener *next;  };  struct client { @@ -117,12 +118,14 @@ struct client {  #ifdef HAVE_TLS  	SSL *tls;  #endif +	struct client *next;  };  struct auth_realm {  	char path[PATH_MAX];  	char user[32];  	char pass[128]; +	struct auth_realm *next;  };  struct http_request { @@ -140,5 +143,13 @@ struct http_response {  	char *headers[UH_LIMIT_HEADERS];  }; +#ifdef HAVE_CGI +struct interpreter { +	char path[PATH_MAX]; +	char extn[32]; +	struct interpreter *next; +}; +#endif +  #endif | 
