uhttpd: - make network timeout configurable, increase default to 30 seconds (#7067) - follow symlinks in docroot and add option to disable that - fix mimetype detection for files with combined extensions (.tar.gz, ...)

SVN-Revision: 20883
lede-17.01
Jo-Philipp Wich 2010-04-15 19:46:35 +00:00
parent a8e20318c5
commit 20ef055c2f
8 changed files with 186 additions and 82 deletions

View File

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

View File

@ -29,10 +29,16 @@ config uhttpd main
# CGI/Lua timeout, if the called script does not # CGI/Lua timeout, if the called script does not
# write data within the given amount of seconds, # write data within the given amount of seconds,
# the server will temrinate the request with # the server will terminate the request with
# 504 Gateway Timeout response. # 504 Gateway Timeout response.
option script_timeout 60 option script_timeout 60
# Network timeout, if the current connection is
# blocked for the specified amount of seconds,
# the server will terminate the associated
# request process.
option network_timeout 30
# Basic auth realm, defaults to local hostname # Basic auth realm, defaults to local hostname
# option realm OpenWrt # option realm OpenWrt

View File

@ -58,6 +58,7 @@ start_instance()
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" append_arg "$cfg" script_timeout "-t"
append_arg "$cfg" network_timeout "-T"
config_get http "$cfg" listen_http config_get http "$cfg" listen_http
for listen in $http; do for listen in $http; do

View File

@ -29,23 +29,21 @@
static const char * uh_file_mime_lookup(const char *path) static const char * uh_file_mime_lookup(const char *path)
{ {
struct mimetype *m = &uh_mime_types[0]; struct mimetype *m = &uh_mime_types[0];
char *p, *pd, *ps; char *e;
ps = strrchr(path, '/'); while( m->extn )
pd = strrchr(path, '.');
/* use either slash or dot as separator, whatever comes last */
p = (ps && pd && (ps > pd)) ? ps : pd;
if( (p != NULL) && (*(++p) != 0) )
{ {
while( m->extn ) e = &path[strlen(path)-1];
while( e >= path )
{ {
if( ! strcasecmp(p, m->extn) ) if( (*e == '.') && !strcasecmp(&e[1], m->extn) )
return m->mime; return m->mime;
m++; e--;
} }
m++;
} }
return "application/octet-stream"; return "application/octet-stream";

View File

@ -20,58 +20,61 @@
static struct mimetype uh_mime_types[] = { static struct mimetype uh_mime_types[] = {
{ "txt", "text/plain" }, { "txt", "text/plain" },
{ "log", "text/plain" }, { "log", "text/plain" },
{ "js", "text/javascript" }, { "js", "text/javascript" },
{ "css", "text/css" }, { "css", "text/css" },
{ "htm", "text/html" }, { "htm", "text/html" },
{ "html", "text/html" }, { "html", "text/html" },
{ "diff", "text/x-patch" }, { "diff", "text/x-patch" },
{ "patch", "text/x-patch" }, { "patch", "text/x-patch" },
{ "c", "text/x-csrc" }, { "c", "text/x-csrc" },
{ "h", "text/x-chdr" }, { "h", "text/x-chdr" },
{ "o", "text/x-object" }, { "o", "text/x-object" },
{ "ko", "text/x-object" }, { "ko", "text/x-object" },
{ "bmp", "image/bmp" }, { "bmp", "image/bmp" },
{ "gif", "image/gif" }, { "gif", "image/gif" },
{ "png", "image/png" }, { "png", "image/png" },
{ "jpg", "image/jpeg" }, { "jpg", "image/jpeg" },
{ "jpeg", "image/jpeg" }, { "jpeg", "image/jpeg" },
{ "svg", "image/svg+xml" }, { "svg", "image/svg+xml" },
{ "zip", "application/zip" }, { "zip", "application/zip" },
{ "pdf", "application/pdf" }, { "pdf", "application/pdf" },
{ "xml", "application/xml" }, { "xml", "application/xml" },
{ "xsl", "application/xml" }, { "xsl", "application/xml" },
{ "doc", "application/msword" }, { "doc", "application/msword" },
{ "ppt", "application/vnd.ms-powerpoint" }, { "ppt", "application/vnd.ms-powerpoint" },
{ "xls", "application/vnd.ms-excel" }, { "xls", "application/vnd.ms-excel" },
{ "odt", "application/vnd.oasis.opendocument.text" }, { "odt", "application/vnd.oasis.opendocument.text" },
{ "odp", "application/vnd.oasis.opendocument.presentation" }, { "odp", "application/vnd.oasis.opendocument.presentation" },
{ "pl", "application/x-perl" }, { "pl", "application/x-perl" },
{ "sh", "application/x-shellscript" }, { "sh", "application/x-shellscript" },
{ "php", "application/x-php" }, { "php", "application/x-php" },
{ "deb", "application/x-deb" }, { "deb", "application/x-deb" },
{ "iso", "application/x-cd-image" }, { "iso", "application/x-cd-image" },
{ "tgz", "application/x-compressed-tar" }, { "tar.gz", "application/x-compressed-tar" },
{ "gz", "application/x-gzip" }, { "tgz", "application/x-compressed-tar" },
{ "bz2", "application/x-bzip" }, { "gz", "application/x-gzip" },
{ "tar", "application/x-tar" }, { "tar.bz2", "application/x-bzip-compressed-tar" },
{ "rar", "application/x-rar-compressed" }, { "tbz", "application/x-bzip-compressed-tar" },
{ "bz2", "application/x-bzip" },
{ "tar", "application/x-tar" },
{ "rar", "application/x-rar-compressed" },
{ "mp3", "audio/mpeg" }, { "mp3", "audio/mpeg" },
{ "ogg", "audio/x-vorbis+ogg" }, { "ogg", "audio/x-vorbis+ogg" },
{ "wav", "audio/x-wav" }, { "wav", "audio/x-wav" },
{ "mpg", "video/mpeg" }, { "mpg", "video/mpeg" },
{ "mpeg", "video/mpeg" }, { "mpeg", "video/mpeg" },
{ "avi", "video/x-msvideo" }, { "avi", "video/x-msvideo" },
{ "README", "text/plain" }, { "README", "text/plain" },
{ "log", "text/plain" }, { "log", "text/plain" },
{ "cfg", "text/plain" }, { "cfg", "text/plain" },
{ "conf", "text/plain" }, { "conf", "text/plain" },
{ NULL, NULL } { NULL, NULL }
}; };

View File

@ -116,8 +116,8 @@ int uh_tcp_send(struct client *cl, const char *buf, int len)
FD_ZERO(&writer); FD_ZERO(&writer);
FD_SET(cl->socket, &writer); FD_SET(cl->socket, &writer);
timeout.tv_sec = 0; timeout.tv_sec = cl->server->conf->network_timeout;
timeout.tv_usec = 500000; timeout.tv_usec = 0;
if( select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0 ) if( select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0 )
{ {
@ -376,6 +376,78 @@ int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen)
return len; return len;
} }
static char * canonpath(const char *path, char *path_resolved)
{
char path_copy[PATH_MAX];
char *path_cpy = path_copy;
char *path_res = path_resolved;
struct stat s;
/* relative -> absolute */
if( *path != '/' )
{
getcwd(path_copy, PATH_MAX);
strncat(path_copy, "/", PATH_MAX - strlen(path_copy));
strncat(path_copy, path, PATH_MAX - strlen(path_copy));
}
else
{
strncpy(path_copy, path, PATH_MAX);
}
/* normalize */
while( (*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)) )
{
if( *path_cpy == '/' )
{
/* skip repeating / */
if( path_cpy[1] == '/' )
{
path_cpy++;
continue;
}
/* /./ or /../ */
else if( path_cpy[1] == '.' )
{
/* skip /./ */
if( (path_cpy[2] == '/') || (path_cpy[2] == '\0') )
{
path_cpy += 2;
continue;
}
/* collapse /x/../ */
else if( path_cpy[2] == '.' )
{
while( (path_res > path_resolved) && (*--path_res != '/') )
;
path_cpy += 3;
continue;
}
}
}
*path_res++ = *path_cpy++;
}
/* remove trailing slash if not root / */
if( (path_res > (path_resolved+1)) && (path_res[-1] == '/') )
path_res--;
else if( path_res == path_resolved )
*path_res++ = '/';
*path_res = '\0';
/* test access */
if( !stat(path_resolved, &s) && (s.st_mode & S_IROTH) )
return path_resolved;
return NULL;
}
struct path_info * uh_path_lookup(struct client *cl, const char *url) struct path_info * uh_path_lookup(struct client *cl, const char *url)
{ {
@ -387,6 +459,7 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
char *docroot = cl->server->conf->docroot; char *docroot = cl->server->conf->docroot;
char *pathptr = NULL; char *pathptr = NULL;
int no_sym = cl->server->conf->no_symlinks;
int i = 0; int i = 0;
struct stat s; struct stat s;
@ -432,8 +505,9 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
memset(path_info, 0, sizeof(path_info)); memset(path_info, 0, sizeof(path_info));
memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1)); memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
if( realpath(path_info, path_phys) ) if( no_sym ? realpath(path_info, path_phys)
{ : canonpath(path_info, path_phys)
) {
memset(path_info, 0, sizeof(path_info)); memset(path_info, 0, sizeof(path_info));
memcpy(path_info, &buffer[i], memcpy(path_info, &buffer[i],
min(strlen(buffer) - i, sizeof(path_info) - 1)); min(strlen(buffer) - i, sizeof(path_info) - 1));

View File

@ -416,8 +416,11 @@ int main (int argc, char **argv)
/* maximum file descriptor number */ /* maximum file descriptor number */
int new_fd, cur_fd, max_fd = 0; int new_fd, cur_fd, max_fd = 0;
#ifdef HAVE_TLS
int tls = 0; int tls = 0;
int keys = 0; int keys = 0;
#endif
int bound = 0; int bound = 0;
int nofork = 0; int nofork = 0;
@ -426,9 +429,10 @@ int main (int argc, char **argv)
char bind[128]; char bind[128];
char *port = NULL; char *port = NULL;
/* library handles */ #if defined(HAVE_TLS) || defined(HAVE_LUA)
void *tls_lib; /* library handle */
void *lua_lib; void *lib;
#endif
/* clear the master and temp sets */ /* clear the master and temp sets */
FD_ZERO(&used_fds); FD_ZERO(&used_fds);
@ -466,7 +470,7 @@ int main (int argc, char **argv)
#ifdef HAVE_TLS #ifdef HAVE_TLS
/* load TLS plugin */ /* load TLS plugin */
if( ! (tls_lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) ) if( ! (lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) )
{ {
fprintf(stderr, fprintf(stderr,
"Notice: Unable to load TLS plugin - disabling SSL support! " "Notice: Unable to load TLS plugin - disabling SSL support! "
@ -476,14 +480,14 @@ int main (int argc, char **argv)
else else
{ {
/* resolve functions */ /* resolve functions */
if( !(conf.tls_init = dlsym(tls_lib, "uh_tls_ctx_init")) || if( !(conf.tls_init = dlsym(lib, "uh_tls_ctx_init")) ||
!(conf.tls_cert = dlsym(tls_lib, "uh_tls_ctx_cert")) || !(conf.tls_cert = dlsym(lib, "uh_tls_ctx_cert")) ||
!(conf.tls_key = dlsym(tls_lib, "uh_tls_ctx_key")) || !(conf.tls_key = dlsym(lib, "uh_tls_ctx_key")) ||
!(conf.tls_free = dlsym(tls_lib, "uh_tls_ctx_free")) || !(conf.tls_free = dlsym(lib, "uh_tls_ctx_free")) ||
!(conf.tls_accept = dlsym(tls_lib, "uh_tls_client_accept")) || !(conf.tls_accept = dlsym(lib, "uh_tls_client_accept")) ||
!(conf.tls_close = dlsym(tls_lib, "uh_tls_client_close")) || !(conf.tls_close = dlsym(lib, "uh_tls_client_close")) ||
!(conf.tls_recv = dlsym(tls_lib, "uh_tls_client_recv")) || !(conf.tls_recv = dlsym(lib, "uh_tls_client_recv")) ||
!(conf.tls_send = dlsym(tls_lib, "uh_tls_client_send")) !(conf.tls_send = dlsym(lib, "uh_tls_client_send"))
) { ) {
fprintf(stderr, fprintf(stderr,
"Error: Failed to lookup required symbols " "Error: Failed to lookup required symbols "
@ -501,7 +505,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:t:")) > 0 ) while( (opt = getopt(argc, argv, "fSC:K:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0 )
{ {
switch(opt) switch(opt)
{ {
@ -592,6 +596,11 @@ int main (int argc, char **argv)
} }
break; break;
/* don't follow symlinks */
case 'S':
conf.no_symlinks = 1;
break;
#ifdef HAVE_CGI #ifdef HAVE_CGI
/* cgi prefix */ /* cgi prefix */
case 'x': case 'x':
@ -618,6 +627,11 @@ int main (int argc, char **argv)
break; break;
#endif #endif
/* network timeout */
case 'T':
conf.network_timeout = atoi(optarg);
break;
/* no fork */ /* no fork */
case 'f': case 'f':
nofork = 1; nofork = 1;
@ -663,6 +677,7 @@ int main (int argc, char **argv)
" -K file ASN.1 server private key file\n" " -K file ASN.1 server private key file\n"
#endif #endif
" -h directory Specify the document root, default is '.'\n" " -h directory Specify the document root, default is '.'\n"
" -S Do not follow symbolic links outside of the docroot\n"
#ifdef HAVE_LUA #ifdef HAVE_LUA
" -l string URL prefix for Lua handler, default is '/lua'\n" " -l string URL prefix for Lua handler, default is '/lua'\n"
" -L file Lua handler script, omit to disable Lua\n" " -L file Lua handler script, omit to disable Lua\n"
@ -673,6 +688,7 @@ int main (int argc, char **argv)
#if defined(HAVE_CGI) || defined(HAVE_LUA) #if defined(HAVE_CGI) || defined(HAVE_LUA)
" -t seconds CGI and Lua script timeout in seconds, default is 60\n" " -t seconds CGI and Lua script timeout in seconds, default is 60\n"
#endif #endif
" -T seconds Network timeout in seconds, default is 30\n"
" -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"
" -m string MD5 crypt given string\n" " -m string MD5 crypt given string\n"
@ -712,6 +728,10 @@ int main (int argc, char **argv)
/* config file */ /* config file */
uh_config_parse(conf.file); uh_config_parse(conf.file);
/* default network timeout */
if( conf.network_timeout <= 0 )
conf.network_timeout = 30;
#if defined(HAVE_CGI) || defined(HAVE_LUA) #if defined(HAVE_CGI) || defined(HAVE_LUA)
/* default script timeout */ /* default script timeout */
if( conf.script_timeout <= 0 ) if( conf.script_timeout <= 0 )
@ -726,7 +746,7 @@ int main (int argc, char **argv)
#ifdef HAVE_LUA #ifdef HAVE_LUA
/* load Lua plugin */ /* load Lua plugin */
if( ! (lua_lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) ) if( ! (lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) )
{ {
fprintf(stderr, fprintf(stderr,
"Notice: Unable to load Lua plugin - disabling Lua support! " "Notice: Unable to load Lua plugin - disabling Lua support! "
@ -736,9 +756,9 @@ int main (int argc, char **argv)
else else
{ {
/* resolve functions */ /* resolve functions */
if( !(conf.lua_init = dlsym(lua_lib, "uh_lua_init")) || if( !(conf.lua_init = dlsym(lib, "uh_lua_init")) ||
!(conf.lua_close = dlsym(lua_lib, "uh_lua_close")) || !(conf.lua_close = dlsym(lib, "uh_lua_close")) ||
!(conf.lua_request = dlsym(lua_lib, "uh_lua_request")) !(conf.lua_request = dlsym(lib, "uh_lua_request"))
) { ) {
fprintf(stderr, fprintf(stderr,
"Error: Failed to lookup required symbols " "Error: Failed to lookup required symbols "

View File

@ -32,7 +32,7 @@
#include <linux/limits.h> #include <linux/limits.h>
#include <netdb.h> #include <netdb.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h>
#include <dlfcn.h> #include <dlfcn.h>
@ -64,6 +64,8 @@ struct config {
char docroot[PATH_MAX]; char docroot[PATH_MAX];
char *realm; char *realm;
char *file; char *file;
int no_symlinks;
int network_timeout;
#ifdef HAVE_CGI #ifdef HAVE_CGI
char *cgi_prefix; char *cgi_prefix;
#endif #endif