[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
master
Jo-Philipp Wich 2010-03-27 00:00:33 +00:00
parent 78c616da82
commit 99e8e7cf2f
8 changed files with 67 additions and 17 deletions

View File

@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=uhttpd PKG_NAME:=uhttpd
PKG_RELEASE:=1 PKG_RELEASE:=2
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

View File

@ -1,6 +1,14 @@
# Server configuration # Server configuration
config uhttpd main 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 # Server document root
option home /www option home /www
@ -19,13 +27,11 @@ config uhttpd main
# option lua_prefix /luci # option lua_prefix /luci
# option lua_handler /usr/lib/lua/luci/sgi/uhttpd.lua # option lua_handler /usr/lib/lua/luci/sgi/uhttpd.lua
# HTTP listen addresses, multiple allowed # CGI/Lua timeout, if the called script does not
list listen_http 0.0.0.0:80 # write data within the given amount of seconds,
# list listen_http [::]:80 # the server will temrinate the request with
# 504 Gateway Timeout response.
# HTTPS listen addresses, multiple allowed option script_timeout 60
list listen_https 0.0.0.0:443
# list listen_https [::]:443
# Basic auth realm, defaults to local hostname # Basic auth realm, defaults to local hostname
# option realm OpenWrt # option realm OpenWrt

View File

@ -65,6 +65,7 @@ start_instance()
append_arg "$cfg" cgi_prefix "-x" append_arg "$cfg" cgi_prefix "-x"
append_arg "$cfg" lua_prefix "-l" append_arg "$cfg" lua_prefix "-l"
append_arg "$cfg" lua_handler "-L" append_arg "$cfg" lua_handler "-L"
append_arg "$cfg" script_timeout "-t"
config_list_foreach "$cfg" listen_http \ config_list_foreach "$cfg" listen_http \
append_listen_http append_listen_http

View 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(rfd[0], &reader);
FD_SET(wfd[1], &writer); FD_SET(wfd[1], &writer);
timeout.tv_sec = 15; timeout.tv_sec = cl->server->conf->script_timeout;
timeout.tv_usec = 0; timeout.tv_usec = 0;
/* wait until we can read or write or both */ /* 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 else
{ {
ensure(uh_http_sendhf(cl, 504, "Gateway Timeout", if( (errno != EINTR) && ! header_sent )
"The CGI script took too long to produce a response")); {
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; break;
} }

View 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(rfd[0], &reader);
FD_SET(wfd[1], &writer); FD_SET(wfd[1], &writer);
timeout.tv_sec = 15; timeout.tv_sec = cl->server->conf->script_timeout;
timeout.tv_usec = 0; timeout.tv_usec = 0;
/* wait until we can read or write or both */ /* 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 else
{ {
ensure(uh_http_sendhf(cl, 504, "Gateway Timeout", if( (errno != EINTR) && ! data_sent )
"The Lua handler took too long to produce a response")); {
ensure(uh_http_sendhf(cl, 504, "Gateway Timeout",
"The Lua script took too long to produce "
"a response"));
}
break; break;
} }

View File

@ -33,6 +33,9 @@
#define foreach_header(i, h) \ #define foreach_header(i, h) \
for( i = 0; (i + 1) < (sizeof(h) / sizeof(h[0])) && h[i]; i += 2 ) 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 { struct path_info {
char *root; char *root;
char *phys; char *phys;

View File

@ -42,6 +42,11 @@ static void uh_sigterm(int sig)
run = 0; run = 0;
} }
static void uh_sigchld(int sig)
{
while( waitpid(-1, NULL, WNOHANG) > 0 ) { }
}
static void uh_config_parse(const char *path) static void uh_config_parse(const char *path)
{ {
FILE *c; FILE *c;
@ -155,6 +160,7 @@ static int uh_socket_bind(
/* add socket to server fd set */ /* add socket to server fd set */
FD_SET(sock, serv_fds); FD_SET(sock, serv_fds);
fd_cloexec(sock);
*max_fd = max(*max_fd, sock); *max_fd = max(*max_fd, sock);
bound++; bound++;
@ -432,6 +438,8 @@ int main (int argc, char **argv)
sa.sa_handler = SIG_IGN; sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL); sigaction(SIGPIPE, &sa, NULL);
sa.sa_handler = uh_sigchld;
sigaction(SIGCHLD, &sa, NULL); sigaction(SIGCHLD, &sa, NULL);
sa.sa_handler = uh_sigterm; sa.sa_handler = uh_sigterm;
@ -485,7 +493,7 @@ int main (int argc, char **argv)
} }
#endif #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) switch(opt)
{ {
@ -593,6 +601,13 @@ int main (int argc, char **argv)
break; break;
#endif #endif
#if defined(HAVE_CGI) || defined(HAVE_LUA)
/* script timeout */
case 't':
conf.script_timeout = atoi(optarg);
break;
#endif
/* no fork */ /* no fork */
case 'f': case 'f':
nofork = 1; nofork = 1;
@ -644,6 +659,9 @@ int main (int argc, char **argv)
#endif #endif
#ifdef HAVE_CGI #ifdef HAVE_CGI
" -x string URL prefix for CGI handler, default is '/cgi-bin'\n" " -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 #endif
" -d string URL decode given string\n" " -d string URL decode given string\n"
" -r string Specify basic auth realm\n" " -r string Specify basic auth realm\n"
@ -684,6 +702,12 @@ int main (int argc, char **argv)
/* config file */ /* config file */
uh_config_parse(conf.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 #ifdef HAVE_CGI
/* default cgi prefix */ /* default cgi prefix */
if( ! conf.cgi_prefix ) if( ! conf.cgi_prefix )
@ -794,6 +818,7 @@ int main (int argc, char **argv)
/* add client socket to global fdset */ /* add client socket to global fdset */
FD_SET(new_fd, &used_fds); FD_SET(new_fd, &used_fds);
fd_cloexec(new_fd);
max_fd = max(max_fd, new_fd); max_fd = max(max_fd, new_fd);
} }

View File

@ -26,6 +26,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/select.h> #include <sys/select.h>
#include <sys/wait.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <linux/limits.h> #include <linux/limits.h>
@ -73,6 +74,9 @@ struct config {
void (*lua_close) (lua_State *L); void (*lua_close) (lua_State *L);
void (*lua_request) (struct client *cl, struct http_request *req, lua_State *L); void (*lua_request) (struct client *cl, struct http_request *req, lua_State *L);
#endif #endif
#if defined(HAVE_CGI) || defined(HAVE_LUA)
int script_timeout;
#endif
#ifdef HAVE_TLS #ifdef HAVE_TLS
char *cert; char *cert;
char *key; char *key;