From 410c95eb98f84c413a839bb2d1d6e9611f3e2d9f Mon Sep 17 00:00:00 2001
From: jow <jow@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Date: Sat, 27 Mar 2010 00:00:33 +0000
Subject: [package] uhttpd: 	- make script timeout configurable 	-
 catch SIGCHLD to properly interrupt select() 	- flag listen and client
 sockets as close-on-exec

git-svn-id: svn://svn.openwrt.org/openwrt/trunk@20500 3c298f89-4303-0410-b956-a3cf2f4a3e73
---
 package/uhttpd/Makefile            |  2 +-
 package/uhttpd/files/uhttpd.config | 20 +++++++++++++-------
 package/uhttpd/files/uhttpd.init   |  1 +
 package/uhttpd/src/uhttpd-cgi.c    | 15 +++++++++++----
 package/uhttpd/src/uhttpd-lua.c    | 12 ++++++++----
 package/uhttpd/src/uhttpd-utils.h  |  3 +++
 package/uhttpd/src/uhttpd.c        | 27 ++++++++++++++++++++++++++-
 package/uhttpd/src/uhttpd.h        |  4 ++++
 8 files changed, 67 insertions(+), 17 deletions(-)

(limited to 'package')

diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile
index d5c07a359..3e7344911 100644
--- a/package/uhttpd/Makefile
+++ b/package/uhttpd/Makefile
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=uhttpd
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 
diff --git a/package/uhttpd/files/uhttpd.config b/package/uhttpd/files/uhttpd.config
index 0bca4f516..79b018cf8 100644
--- a/package/uhttpd/files/uhttpd.config
+++ b/package/uhttpd/files/uhttpd.config
@@ -1,6 +1,14 @@
 # Server configuration
 config uhttpd main
 
+	# HTTP listen addresses, multiple allowed
+	list listen_http	0.0.0.0:80
+#	list listen_http	[::]:80
+
+	# HTTPS listen addresses, multiple allowed
+	list listen_https	0.0.0.0:443
+#	list listen_https	[::]:443
+
 	# Server document root
 	option home		/www
 
@@ -19,13 +27,11 @@ config uhttpd main
 #	option lua_prefix	/luci
 #	option lua_handler	/usr/lib/lua/luci/sgi/uhttpd.lua
 
-	# HTTP listen addresses, multiple allowed
-	list listen_http	0.0.0.0:80
-#	list listen_http	[::]:80
-
-	# HTTPS listen addresses, multiple allowed
-	list listen_https	0.0.0.0:443
-#	list listen_https	[::]:443
+	# CGI/Lua timeout, if the called script does not
+	# write data within the given amount of seconds,
+	# the server will temrinate the request with
+	# 504 Gateway Timeout response.
+	option script_timeout	60
 
 	# Basic auth realm, defaults to local hostname
 #	option realm	OpenWrt
diff --git a/package/uhttpd/files/uhttpd.init b/package/uhttpd/files/uhttpd.init
index a25bf789c..ba7dd49fb 100755
--- a/package/uhttpd/files/uhttpd.init
+++ b/package/uhttpd/files/uhttpd.init
@@ -65,6 +65,7 @@ start_instance()
 	append_arg "$cfg" cgi_prefix "-x"
 	append_arg "$cfg" lua_prefix "-l"
 	append_arg "$cfg" lua_handler "-L"
+	append_arg "$cfg" script_timeout "-t"
 
 	config_list_foreach "$cfg" listen_http \
 		append_listen_http
diff --git a/package/uhttpd/src/uhttpd-cgi.c b/package/uhttpd/src/uhttpd-cgi.c
index 5565197ca..4a30f2fc9 100644
--- a/package/uhttpd/src/uhttpd-cgi.c
+++ b/package/uhttpd/src/uhttpd-cgi.c
@@ -372,7 +372,7 @@ void uh_cgi_request(struct client *cl, struct http_request *req, struct path_inf
 				FD_SET(rfd[0], &reader);
 				FD_SET(wfd[1], &writer);
 
-				timeout.tv_sec = 15;
+				timeout.tv_sec = cl->server->conf->script_timeout;
 				timeout.tv_usec = 0;
 
 				/* wait until we can read or write or both */
@@ -538,11 +538,18 @@ void uh_cgi_request(struct client *cl, struct http_request *req, struct path_inf
 					}
 				}
 
-				/* no activity for 15 seconds... looks dead */
+				/* timeout exceeded or interrupted by SIGCHLD */
 				else
 				{
-					ensure(uh_http_sendhf(cl, 504, "Gateway Timeout",
-						"The CGI script took too long to produce a response"));
+					if( (errno != EINTR) && ! header_sent )
+					{
+						ensure(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));
 
 					break;
 				}
diff --git a/package/uhttpd/src/uhttpd-lua.c b/package/uhttpd/src/uhttpd-lua.c
index ab09841cd..c1e749043 100644
--- a/package/uhttpd/src/uhttpd-lua.c
+++ b/package/uhttpd/src/uhttpd-lua.c
@@ -448,7 +448,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
 				FD_SET(rfd[0], &reader);
 				FD_SET(wfd[1], &writer);
 
-				timeout.tv_sec = 15;
+				timeout.tv_sec = cl->server->conf->script_timeout;
 				timeout.tv_usec = 0;
 
 				/* wait until we can read or write or both */
@@ -512,11 +512,15 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
 					}
 				}
 
-				/* no activity for 15 seconds... looks dead */
+				/* timeout exceeded or interrupted by SIGCHLD */
 				else
 				{
-					ensure(uh_http_sendhf(cl, 504, "Gateway Timeout",
-						"The Lua handler took too long to produce a response"));
+					if( (errno != EINTR) && ! data_sent )
+					{
+						ensure(uh_http_sendhf(cl, 504, "Gateway Timeout",
+							"The Lua script took too long to produce "
+							"a response"));
+					}
 
 					break;
 				}
diff --git a/package/uhttpd/src/uhttpd-utils.h b/package/uhttpd/src/uhttpd-utils.h
index c7a6c90be..43a74e561 100644
--- a/package/uhttpd/src/uhttpd-utils.h
+++ b/package/uhttpd/src/uhttpd-utils.h
@@ -33,6 +33,9 @@
 #define foreach_header(i, h) \
 	for( i = 0; (i + 1) < (sizeof(h) / sizeof(h[0])) && h[i]; i += 2 )
 
+#define fd_cloexec(fd) \
+	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)
+
 struct path_info {
 	char *root;
 	char *phys;
diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c
index a7db794a5..97c4f836b 100644
--- a/package/uhttpd/src/uhttpd.c
+++ b/package/uhttpd/src/uhttpd.c
@@ -42,6 +42,11 @@ static void uh_sigterm(int sig)
 	run = 0;
 }
 
+static void uh_sigchld(int sig)
+{
+	while( waitpid(-1, NULL, WNOHANG) > 0 ) { }
+}
+
 static void uh_config_parse(const char *path)
 {
 	FILE *c;
@@ -155,6 +160,7 @@ static int uh_socket_bind(
 
 		/* add socket to server fd set */
 		FD_SET(sock, serv_fds);
+		fd_cloexec(sock);
 		*max_fd = max(*max_fd, sock);
 
 		bound++;
@@ -432,6 +438,8 @@ int main (int argc, char **argv)
 
 	sa.sa_handler = SIG_IGN;
 	sigaction(SIGPIPE, &sa, NULL);
+
+	sa.sa_handler = uh_sigchld;
 	sigaction(SIGCHLD, &sa, NULL);
 
 	sa.sa_handler = uh_sigterm;
@@ -485,7 +493,7 @@ int main (int argc, char **argv)
 	}
 #endif
 
-	while( (opt = getopt(argc, argv, "fC:K:p:s:h:c:l:L:d:r:m:x:")) > 0 )
+	while( (opt = getopt(argc, argv, "fC:K:p:s:h:c:l:L:d:r:m:x:t:")) > 0 )
 	{
 		switch(opt)
 		{
@@ -593,6 +601,13 @@ int main (int argc, char **argv)
 				break;
 #endif
 
+#if defined(HAVE_CGI) || defined(HAVE_LUA)
+			/* script timeout */
+			case 't':
+				conf.script_timeout = atoi(optarg);
+				break;
+#endif
+
 			/* no fork */
 			case 'f':
 				nofork = 1;
@@ -644,6 +659,9 @@ int main (int argc, char **argv)
 #endif
 #ifdef HAVE_CGI
 					"	-x string       URL prefix for CGI handler, default is '/cgi-bin'\n"
+#endif
+#if defined(HAVE_CGI) || defined(HAVE_LUA)
+					"	-t seconds      CGI and Lua script timeout in seconds, default is 60\n"
 #endif
 					"	-d string       URL decode given string\n"
 					"	-r string       Specify basic auth realm\n"
@@ -684,6 +702,12 @@ int main (int argc, char **argv)
 	/* config file */
 	uh_config_parse(conf.file);
 
+#if defined(HAVE_CGI) || defined(HAVE_LUA)
+	/* default script timeout */
+	if( conf.script_timeout <= 0 )
+		conf.script_timeout = 60;
+#endif
+
 #ifdef HAVE_CGI
 	/* default cgi prefix */
 	if( ! conf.cgi_prefix )
@@ -794,6 +818,7 @@ int main (int argc, char **argv)
 
 							/* add client socket to global fdset */
 							FD_SET(new_fd, &used_fds);
+							fd_cloexec(new_fd);
 							max_fd = max(max_fd, new_fd);
 						}
 
diff --git a/package/uhttpd/src/uhttpd.h b/package/uhttpd/src/uhttpd.h
index bb08afa1a..0e9f1ee88 100644
--- a/package/uhttpd/src/uhttpd.h
+++ b/package/uhttpd/src/uhttpd.h
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/select.h>
+#include <sys/wait.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <linux/limits.h>
@@ -73,6 +74,9 @@ struct config {
 	void (*lua_close) (lua_State *L);
 	void (*lua_request) (struct client *cl, struct http_request *req, lua_State *L);
 #endif
+#if defined(HAVE_CGI) || defined(HAVE_LUA)
+	int script_timeout;
+#endif
 #ifdef HAVE_TLS
 	char *cert;
 	char *key;
-- 
cgit v1.2.3