From 8c9b818a24045c15f40fc415cd1dde78c438555a Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 27 Mar 2010 00:00:33 +0000 Subject: [PATCH] uhttpd: - make script timeout configurable - catch SIGCHLD to properly interrupt select() - flag listen and client sockets as close-on-exec SVN-Revision: 20500 --- 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(-) diff --git a/package/uhttpd/Makefile b/package/uhttpd/Makefile index d5c07a359a..3e7344911b 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 0bca4f516b..79b018cf80 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 a25bf789cb..ba7dd49fbd 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 5565197ca7..4a30f2fc9a 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 ab09841cd6..c1e7490438 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 c7a6c90beb..43a74e5616 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 a7db794a5b..97c4f836b7 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 bb08afa1a1..0e9f1ee886 100644 --- a/package/uhttpd/src/uhttpd.h +++ b/package/uhttpd/src/uhttpd.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -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; -- 2.30.2