uhttpd: - make script timeout configurable - catch SIGCHLD to properly interrupt...
authorJo-Philipp Wich <jow@openwrt.org>
Sat, 27 Mar 2010 00:00:33 +0000 (00:00 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sat, 27 Mar 2010 00:00:33 +0000 (00:00 +0000)
SVN-Revision: 20500

package/uhttpd/Makefile
package/uhttpd/files/uhttpd.config
package/uhttpd/files/uhttpd.init
package/uhttpd/src/uhttpd-cgi.c
package/uhttpd/src/uhttpd-lua.c
package/uhttpd/src/uhttpd-utils.h
package/uhttpd/src/uhttpd.c
package/uhttpd/src/uhttpd.h

index d5c07a359a76e20b2022b4a1b8ca4f5c3c7702bf..3e7344911b5dc1bd957c7dccc547620439ca1090 100644 (file)
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=uhttpd
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 
 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 
index 0bca4f516bd34cf656c0351ff1125299fd4211e9..79b018cf809f3df6702bacf0524a6dbcbdb5933e 100644 (file)
@@ -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
index a25bf789cbbb9903e3988a3c96a677f36036ba9c..ba7dd49fbd14ba08d9685995d26bea6044d272ec 100755 (executable)
@@ -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
index 5565197ca7e576a2b1bf6b2069fa19a95172d494..4a30f2fc9a70677c64468c56ab06c5169affc785 100644 (file)
@@ -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;
                                }
index ab09841cd62ea39874f0811d03e8f1c90af8a8c1..c1e749043864507a449f9b5047e62864a3bd07d7 100644 (file)
@@ -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;
                                }
index c7a6c90beb4fc014377dc55623e20744d8c855ce..43a74e561602a5ccb09769b66622ee1748dadf97 100644 (file)
@@ -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;
index a7db794a5bcf64b3a8e9a7c18731eaa86dc0ea5e..97c4f836b7bf58c8cc2cf19e17e8bf1e5317b9a3 100644 (file)
@@ -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);
                                                }
 
index bb08afa1a14bd256545fbb2ab0cffe24e1cd1d75..0e9f1ee88639bcdddab8d797a4ba9018546798f7 100644 (file)
@@ -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;