[package] uhttpd:
authorJo-Philipp Wich <jow@openwrt.org>
Thu, 15 Apr 2010 19:46:35 +0000 (19:46 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 15 Apr 2010 19:46:35 +0000 (19:46 +0000)
- 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

package/uhttpd/Makefile
package/uhttpd/files/uhttpd.config
package/uhttpd/files/uhttpd.init
package/uhttpd/src/uhttpd-file.c
package/uhttpd/src/uhttpd-mimetypes.h
package/uhttpd/src/uhttpd-utils.c
package/uhttpd/src/uhttpd.c
package/uhttpd/src/uhttpd.h

index 6b4db3e15f437001fad573a5078c66a2871e6945..0f267be2af97cdac104e25e7d2e48adf95643dc2 100644 (file)
@@ -8,7 +8,7 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=uhttpd
-PKG_RELEASE:=7
+PKG_RELEASE:=8
 
 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
 
index 79b018cf809f3df6702bacf0524a6dbcbdb5933e..acdd62ea4eb471aba1e9f5f9397ad1715ff008bb 100644 (file)
@@ -29,10 +29,16 @@ config uhttpd main
 
        # CGI/Lua timeout, if the called script does not
        # 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.
        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
 #      option realm    OpenWrt
 
index 4b747a0da1d47bdb0c7315d53ec6b097c85142cd..14f8fc4c468d79ebe2b171ab258fb99aca010273 100755 (executable)
@@ -58,6 +58,7 @@ start_instance()
        append_arg "$cfg" lua_prefix "-l"
        append_arg "$cfg" lua_handler "-L"
        append_arg "$cfg" script_timeout "-t"
+       append_arg "$cfg" network_timeout "-T"
 
        config_get http "$cfg" listen_http
        for listen in $http; do
index 2a06f85206255de0cc8129e679e9d9fd7edd542a..81f66a34b0250c81890152587ab828b569fb89f6 100644 (file)
 static const char * uh_file_mime_lookup(const char *path)
 {
        struct mimetype *m = &uh_mime_types[0];
-       char *p, *pd, *ps;
+       char *e;
 
-       ps = strrchr(path, '/');
-       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 )
        {
-               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;
 
-                       m++;
+                       e--;
                }
+
+               m++;
        }
 
        return "application/octet-stream";
index 1c93f31133236e9b073b06fd267408f0a19a8391..032d3d0c25f181410edd542162a1a32d7bf83c5a 100644 (file)
 
 static struct mimetype uh_mime_types[] = {
 
-       { "txt",    "text/plain" },
-       { "log",    "text/plain" },
-       { "js",     "text/javascript" },
-       { "css",    "text/css" },
-       { "htm",    "text/html" },
-       { "html",   "text/html" },
-       { "diff",   "text/x-patch" },
-       { "patch",  "text/x-patch" },
-       { "c",      "text/x-csrc" },
-       { "h",      "text/x-chdr" },
-       { "o",      "text/x-object" },
-       { "ko",     "text/x-object" },
+       { "txt",     "text/plain" },
+       { "log",     "text/plain" },
+       { "js",      "text/javascript" },
+       { "css",     "text/css" },
+       { "htm",     "text/html" },
+       { "html",    "text/html" },
+       { "diff",    "text/x-patch" },
+       { "patch",   "text/x-patch" },
+       { "c",       "text/x-csrc" },
+       { "h",       "text/x-chdr" },
+       { "o",       "text/x-object" },
+       { "ko",      "text/x-object" },
 
-       { "bmp",    "image/bmp" },
-       { "gif",    "image/gif" },
-       { "png",    "image/png" },
-       { "jpg",    "image/jpeg" },
-       { "jpeg",   "image/jpeg" },
-       { "svg",    "image/svg+xml" },
+       { "bmp",     "image/bmp" },
+       { "gif",     "image/gif" },
+       { "png",     "image/png" },
+       { "jpg",     "image/jpeg" },
+       { "jpeg",    "image/jpeg" },
+       { "svg",     "image/svg+xml" },
 
-       { "zip",    "application/zip" },
-       { "pdf",    "application/pdf" },
-       { "xml",    "application/xml" },
-       { "xsl",    "application/xml" },
-       { "doc",    "application/msword" },
-       { "ppt",    "application/vnd.ms-powerpoint" },
-       { "xls",    "application/vnd.ms-excel" },
-       { "odt",    "application/vnd.oasis.opendocument.text" },
-       { "odp",    "application/vnd.oasis.opendocument.presentation" },
-       { "pl",     "application/x-perl" },
-       { "sh",     "application/x-shellscript" },
-       { "php",    "application/x-php" },
-       { "deb",    "application/x-deb" },
-       { "iso",    "application/x-cd-image" },
-       { "tgz",    "application/x-compressed-tar" },
-       { "gz",     "application/x-gzip" },
-       { "bz2",    "application/x-bzip" },
-       { "tar",    "application/x-tar" },
-       { "rar",    "application/x-rar-compressed" },
+       { "zip",     "application/zip" },
+       { "pdf",     "application/pdf" },
+       { "xml",     "application/xml" },
+       { "xsl",     "application/xml" },
+       { "doc",     "application/msword" },
+       { "ppt",     "application/vnd.ms-powerpoint" },
+       { "xls",     "application/vnd.ms-excel" },
+       { "odt",     "application/vnd.oasis.opendocument.text" },
+       { "odp",     "application/vnd.oasis.opendocument.presentation" },
+       { "pl",      "application/x-perl" },
+       { "sh",      "application/x-shellscript" },
+       { "php",     "application/x-php" },
+       { "deb",     "application/x-deb" },
+       { "iso",     "application/x-cd-image" },
+       { "tar.gz",  "application/x-compressed-tar" },
+       { "tgz",     "application/x-compressed-tar" },
+       { "gz",      "application/x-gzip" },
+       { "tar.bz2", "application/x-bzip-compressed-tar" },
+       { "tbz",     "application/x-bzip-compressed-tar" },
+       { "bz2",     "application/x-bzip" },
+       { "tar",     "application/x-tar" },
+       { "rar",     "application/x-rar-compressed" },
 
-       { "mp3",    "audio/mpeg" },
-       { "ogg",    "audio/x-vorbis+ogg" },
-       { "wav",    "audio/x-wav" },
+       { "mp3",     "audio/mpeg" },
+       { "ogg",     "audio/x-vorbis+ogg" },
+       { "wav",     "audio/x-wav" },
 
-       { "mpg",    "video/mpeg" },
-       { "mpeg",   "video/mpeg" },
-       { "avi",    "video/x-msvideo" },
+       { "mpg",     "video/mpeg" },
+       { "mpeg",    "video/mpeg" },
+       { "avi",     "video/x-msvideo" },
 
-       { "README", "text/plain" },
-       { "log",    "text/plain" },
-       { "cfg",    "text/plain" },
-       { "conf",   "text/plain" },
+       { "README",  "text/plain" },
+       { "log",     "text/plain" },
+       { "cfg",     "text/plain" },
+       { "conf",    "text/plain" },
 
        { NULL, NULL }
 };
index 55b2c410e35714702bfd6aaf0d8159ca8076e693..e65f2136d64fce7b8518087eb4295e2bf22b2f3a 100644 (file)
@@ -116,8 +116,8 @@ int uh_tcp_send(struct client *cl, const char *buf, int len)
        FD_ZERO(&writer);
        FD_SET(cl->socket, &writer);
 
-       timeout.tv_sec = 0;
-       timeout.tv_usec = 500000;
+       timeout.tv_sec = cl->server->conf->network_timeout;
+       timeout.tv_usec = 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;
 }
 
+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)
 {
@@ -387,6 +459,7 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
        char *docroot = cl->server->conf->docroot;
        char *pathptr = NULL;
 
+       int no_sym = cl->server->conf->no_symlinks;
        int i = 0;
        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));
                        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));
                                memcpy(path_info, &buffer[i],
                                        min(strlen(buffer) - i, sizeof(path_info) - 1));
index da3779413ecd6f92ca8f768962cd3bed8f0eba8a..9de77c814d3fd043fb68ecfead7db6e55e309cd6 100644 (file)
@@ -416,8 +416,11 @@ int main (int argc, char **argv)
        /* maximum file descriptor number */
        int new_fd, cur_fd, max_fd = 0;
 
+#ifdef HAVE_TLS
        int tls = 0;
        int keys = 0;
+#endif
+
        int bound = 0;
        int nofork = 0;
 
@@ -426,9 +429,10 @@ int main (int argc, char **argv)
        char bind[128];
        char *port = NULL;
 
-       /* library handles */
-       void *tls_lib;
-       void *lua_lib;
+#if defined(HAVE_TLS) || defined(HAVE_LUA)
+       /* library handle */
+       void *lib;
+#endif
 
        /* clear the master and temp sets */
        FD_ZERO(&used_fds);
@@ -466,7 +470,7 @@ int main (int argc, char **argv)
 
 #ifdef HAVE_TLS
        /* 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,
                        "Notice: Unable to load TLS plugin - disabling SSL support! "
@@ -476,14 +480,14 @@ int main (int argc, char **argv)
        else
        {
                /* resolve functions */
-               if( !(conf.tls_init   = dlsym(tls_lib, "uh_tls_ctx_init"))      ||
-                   !(conf.tls_cert   = dlsym(tls_lib, "uh_tls_ctx_cert"))      ||
-                   !(conf.tls_key    = dlsym(tls_lib, "uh_tls_ctx_key"))       ||
-                   !(conf.tls_free   = dlsym(tls_lib, "uh_tls_ctx_free"))      ||
-                       !(conf.tls_accept = dlsym(tls_lib, "uh_tls_client_accept")) ||
-                       !(conf.tls_close  = dlsym(tls_lib, "uh_tls_client_close"))  ||
-                       !(conf.tls_recv   = dlsym(tls_lib, "uh_tls_client_recv"))   ||
-                       !(conf.tls_send   = dlsym(tls_lib, "uh_tls_client_send"))
+               if( !(conf.tls_init   = dlsym(lib, "uh_tls_ctx_init"))      ||
+                   !(conf.tls_cert   = dlsym(lib, "uh_tls_ctx_cert"))      ||
+                   !(conf.tls_key    = dlsym(lib, "uh_tls_ctx_key"))       ||
+                   !(conf.tls_free   = dlsym(lib, "uh_tls_ctx_free"))      ||
+                       !(conf.tls_accept = dlsym(lib, "uh_tls_client_accept")) ||
+                       !(conf.tls_close  = dlsym(lib, "uh_tls_client_close"))  ||
+                       !(conf.tls_recv   = dlsym(lib, "uh_tls_client_recv"))   ||
+                       !(conf.tls_send   = dlsym(lib, "uh_tls_client_send"))
                ) {
                        fprintf(stderr,
                                "Error: Failed to lookup required symbols "
@@ -501,7 +505,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:t:")) > 0 )
+       while( (opt = getopt(argc, argv, "fSC:K:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0 )
        {
                switch(opt)
                {
@@ -592,6 +596,11 @@ int main (int argc, char **argv)
                                }
                                break;
 
+                       /* don't follow symlinks */
+                       case 'S':
+                               conf.no_symlinks = 1;
+                               break;
+
 #ifdef HAVE_CGI
                        /* cgi prefix */
                        case 'x':
@@ -618,6 +627,11 @@ int main (int argc, char **argv)
                                break;
 #endif
 
+                       /* network timeout */
+                       case 'T':
+                               conf.network_timeout = atoi(optarg);
+                               break;
+
                        /* no fork */
                        case 'f':
                                nofork = 1;
@@ -663,6 +677,7 @@ int main (int argc, char **argv)
                                        "       -K file         ASN.1 server private key file\n"
 #endif
                                        "       -h directory    Specify the document root, default is '.'\n"
+                                       "       -S              Do not follow symbolic links outside of the docroot\n"
 #ifdef HAVE_LUA
                                        "       -l string       URL prefix for Lua handler, default is '/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)
                                        "       -t seconds      CGI and Lua script timeout in seconds, default is 60\n"
 #endif
+                                       "       -T seconds      Network timeout in seconds, default is 30\n"
                                        "       -d string       URL decode given string\n"
                                        "       -r string       Specify basic auth realm\n"
                                        "       -m string       MD5 crypt given string\n"
@@ -712,6 +728,10 @@ int main (int argc, char **argv)
        /* config 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)
        /* default script timeout */
        if( conf.script_timeout <= 0 )
@@ -726,7 +746,7 @@ int main (int argc, char **argv)
 
 #ifdef HAVE_LUA
        /* 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,
                        "Notice: Unable to load Lua plugin - disabling Lua support! "
@@ -736,9 +756,9 @@ int main (int argc, char **argv)
        else
        {
                /* resolve functions */
-               if( !(conf.lua_init    = dlsym(lua_lib, "uh_lua_init"))    ||
-                   !(conf.lua_close   = dlsym(lua_lib, "uh_lua_close"))   ||
-                   !(conf.lua_request = dlsym(lua_lib, "uh_lua_request"))
+               if( !(conf.lua_init    = dlsym(lib, "uh_lua_init"))    ||
+                   !(conf.lua_close   = dlsym(lib, "uh_lua_close"))   ||
+                   !(conf.lua_request = dlsym(lib, "uh_lua_request"))
                ) {
                        fprintf(stderr,
                                "Error: Failed to lookup required symbols "
index 0e9f1ee88639bcdddab8d797a4ba9018546798f7..32e39700722c7c41488539ad1d197fa71a77f181 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/limits.h>
 #include <netdb.h>
 #include <ctype.h>
-
+#include <errno.h>
 #include <dlfcn.h>
 
 
@@ -64,6 +64,8 @@ struct config {
        char docroot[PATH_MAX];
        char *realm;
        char *file;
+       int no_symlinks;
+       int network_timeout;
 #ifdef HAVE_CGI
        char *cgi_prefix;
 #endif