uhttpd:
authorJo-Philipp Wich <jow@openwrt.org>
Sat, 20 Mar 2010 13:45:50 +0000 (13:45 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sat, 20 Mar 2010 13:45:50 +0000 (13:45 +0000)
- rework url parsing and path resolving
- handle more cgi quirks
- change request dispatching
- clean up cflags

contrib/package/uhttpd/src/Makefile
contrib/package/uhttpd/src/uhttpd-cgi.c
contrib/package/uhttpd/src/uhttpd-cgi.h
contrib/package/uhttpd/src/uhttpd-file.c
contrib/package/uhttpd/src/uhttpd-file.h
contrib/package/uhttpd/src/uhttpd-lua.c
contrib/package/uhttpd/src/uhttpd-lua.h
contrib/package/uhttpd/src/uhttpd-utils.c
contrib/package/uhttpd/src/uhttpd-utils.h
contrib/package/uhttpd/src/uhttpd.c

index a94dff9..7bbb23a 100644 (file)
@@ -2,10 +2,10 @@ CGI_SUPPORT ?= 1
 LUA_SUPPORT ?= 1
 TLS_SUPPORT ?= 1
 
+CFLAGS ?= -I./lua-5.1.4/src -I./cyassl-1.4.0/include -O0 -ggdb3
 LDFLAGS ?= -L./lua-5.1.4/src -L./cyassl-1.4.0/src/.libs -lm
-CFLAGS  ?= -Wall -I./lua-5.1.4/src -I./cyassl-1.4.0/include -O0 -ggdb3
 
-CFLAGS += --std=c99 -D_POSIX_C_SOURCE=200112L -D_XOPEN_SOURCE=500
+CFLAGS += -Wall --std=gnu99
 LDFLAGS += -lm -lcrypt
 
 OBJ = uhttpd.o uhttpd-file.o uhttpd-utils.o
index 7c47037..7836167 100644 (file)
@@ -1,6 +1,6 @@
 #include "uhttpd.h"
-#include "uhttpd-cgi.h"
 #include "uhttpd-utils.h"
+#include "uhttpd-cgi.h"
 
 static struct http_response * uh_cgi_header_parse(char *buf, int len, int *off)
 {
@@ -114,7 +114,7 @@ static void uh_cgi_error_500(struct client *cl, struct http_request *req, const
 }
 
 
-void uh_cgi_request(struct client *cl, struct http_request *req)
+void uh_cgi_request(struct client *cl, struct http_request *req, struct uh_path_info *pi)
 {
        int i, hdroff, bufoff;
        int hdrlen = 0;
@@ -134,7 +134,6 @@ void uh_cgi_request(struct client *cl, struct http_request *req)
 
        struct timeval timeout;
        struct http_response *res;
-       struct uh_path_info *pi;
 
 
        /* spawn pipes for me->child, child->me */
@@ -170,143 +169,129 @@ void uh_cgi_request(struct client *cl, struct http_request *req)
                        dup2(rfd[1], 1);
                        dup2(wfd[0], 0);
 
-                       if( (pi = uh_path_lookup(cl, req->url)) != NULL )
-                       {
-                               /* check for regular, world-executable file */
-                               if( (pi->stat.st_mode & S_IFREG) &&
-                                   (pi->stat.st_mode & S_IXOTH)
-                               ) {
-                                       /* build environment */
-                                       clearenv();
-
-                                       /* common information */
-                                       setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
-                                       setenv("SERVER_SOFTWARE", "uHTTPd", 1);
-                                       setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1);
+                       /* check for regular, world-executable file */
+                       if( (pi->stat.st_mode & S_IFREG) &&
+                           (pi->stat.st_mode & S_IXOTH)
+                       ) {
+                               /* build environment */
+                               clearenv();
+
+                               /* common information */
+                               setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
+                               setenv("SERVER_SOFTWARE", "uHTTPd", 1);
+                               setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1);
 
 #ifdef HAVE_TLS
-                                       /* https? */
-                                       if( cl->tls )
-                                               setenv("HTTPS", "on", 1);
+                               /* https? */
+                               if( cl->tls )
+                                       setenv("HTTPS", "on", 1);
 #endif
 
-                                       /* addresses */
-                                       setenv("SERVER_NAME", sa_straddr(&cl->servaddr), 1);
-                                       setenv("SERVER_ADDR", sa_straddr(&cl->servaddr), 1);
-                                       setenv("SERVER_PORT", sa_strport(&cl->servaddr), 1);
-                                       setenv("REMOTE_HOST", sa_straddr(&cl->peeraddr), 1);
-                                       setenv("REMOTE_ADDR", sa_straddr(&cl->peeraddr), 1);
-                                       setenv("REMOTE_PORT", sa_strport(&cl->peeraddr), 1);
+                               /* addresses */
+                               setenv("SERVER_NAME", sa_straddr(&cl->servaddr), 1);
+                               setenv("SERVER_ADDR", sa_straddr(&cl->servaddr), 1);
+                               setenv("SERVER_PORT", sa_strport(&cl->servaddr), 1);
+                               setenv("REMOTE_HOST", sa_straddr(&cl->peeraddr), 1);
+                               setenv("REMOTE_ADDR", sa_straddr(&cl->peeraddr), 1);
+                               setenv("REMOTE_PORT", sa_strport(&cl->peeraddr), 1);
 
-                                       /* path information */
-                                       setenv("SCRIPT_NAME", pi->name, 1);
-                                       setenv("SCRIPT_FILENAME", pi->phys, 1);
-                                       setenv("SCRIPT_WORKDIR", pi->wdir, 1);  /* nonstandard */
-                                       setenv("DOCUMENT_ROOT", pi->root, 1);
-                                       setenv("QUERY_STRING", pi->query ? pi->query : "", 1);
+                               /* path information */
+                               setenv("SCRIPT_NAME", pi->name, 1);
+                               setenv("SCRIPT_FILENAME", pi->phys, 1);
+                               setenv("DOCUMENT_ROOT", pi->root, 1);
+                               setenv("QUERY_STRING", pi->query ? pi->query : "", 1);
 
-                                       if( pi->info )
-                                               setenv("PATH_INFO", pi->info, 1);
+                               if( pi->info )
+                                       setenv("PATH_INFO", pi->info, 1);
 
 
-                                       /* http version */
-                                       if( req->version > 1.0 )
-                                               setenv("SERVER_PROTOCOL", "HTTP/1.1", 1);
-                                       else
-                                               setenv("SERVER_PROTOCOL", "HTTP/1.0", 1);
-
-                                       /* request method */
-                                       switch( req->method )
-                                       {
-                                               case UH_HTTP_MSG_GET:
-                                                       setenv("REQUEST_METHOD", "GET", 1);
-                                                       break;
+                               /* http version */
+                               if( req->version > 1.0 )
+                                       setenv("SERVER_PROTOCOL", "HTTP/1.1", 1);
+                               else
+                                       setenv("SERVER_PROTOCOL", "HTTP/1.0", 1);
 
-                                               case UH_HTTP_MSG_HEAD:
-                                                       setenv("REQUEST_METHOD", "HEAD", 1);
-                                                       break;
+                               /* request method */
+                               switch( req->method )
+                               {
+                                       case UH_HTTP_MSG_GET:
+                                               setenv("REQUEST_METHOD", "GET", 1);
+                                               break;
 
-                                               case UH_HTTP_MSG_POST:
-                                                       setenv("REQUEST_METHOD", "POST", 1);
-                                                       break;
-                                       }
+                                       case UH_HTTP_MSG_HEAD:
+                                               setenv("REQUEST_METHOD", "HEAD", 1);
+                                               break;
 
-                                       /* request url */
-                                       setenv("REQUEST_URI", req->url, 1);
+                                       case UH_HTTP_MSG_POST:
+                                               setenv("REQUEST_METHOD", "POST", 1);
+                                               break;
+                               }
 
-                                       /* request message headers */
-                                       foreach_header(i, req->headers)
-                                       {
-                                               if( ! strcasecmp(req->headers[i], "Accept") )
-                                                       setenv("HTTP_ACCEPT", req->headers[i+1], 1);
+                               /* request url */
+                               setenv("REQUEST_URI", req->url, 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Accept-Charset") )
-                                                       setenv("HTTP_ACCEPT_CHARSET", req->headers[i+1], 1);
+                               /* request message headers */
+                               foreach_header(i, req->headers)
+                               {
+                                       if( ! strcasecmp(req->headers[i], "Accept") )
+                                               setenv("HTTP_ACCEPT", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Accept-Encoding") )
-                                                       setenv("HTTP_ACCEPT_ENCODING", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "Accept-Charset") )
+                                               setenv("HTTP_ACCEPT_CHARSET", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Accept-Language") )
-                                                       setenv("HTTP_ACCEPT_LANGUAGE", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "Accept-Encoding") )
+                                               setenv("HTTP_ACCEPT_ENCODING", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Authorization") )
-                                                       setenv("HTTP_AUTHORIZATION", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "Accept-Language") )
+                                               setenv("HTTP_ACCEPT_LANGUAGE", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Connection") )
-                                                       setenv("HTTP_CONNECTION", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "Authorization") )
+                                               setenv("HTTP_AUTHORIZATION", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Cookie") )
-                                                       setenv("HTTP_COOKIE", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "Connection") )
+                                               setenv("HTTP_CONNECTION", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Host") )
-                                                       setenv("HTTP_HOST", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "Cookie") )
+                                               setenv("HTTP_COOKIE", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Referer") )
-                                                       setenv("HTTP_REFERER", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "Host") )
+                                               setenv("HTTP_HOST", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "User-Agent") )
-                                                       setenv("HTTP_USER_AGENT", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "Referer") )
+                                               setenv("HTTP_REFERER", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Content-Type") )
-                                                       setenv("CONTENT_TYPE", req->headers[i+1], 1);
+                                       else if( ! strcasecmp(req->headers[i], "User-Agent") )
+                                               setenv("HTTP_USER_AGENT", req->headers[i+1], 1);
 
-                                               else if( ! strcasecmp(req->headers[i], "Content-Length") )
-                                                       setenv("CONTENT_LENGTH", req->headers[i+1], 1);
-                                       }
+                                       else if( ! strcasecmp(req->headers[i], "Content-Type") )
+                                               setenv("CONTENT_TYPE", req->headers[i+1], 1);
 
+                                       else if( ! strcasecmp(req->headers[i], "Content-Length") )
+                                               setenv("CONTENT_LENGTH", req->headers[i+1], 1);
+                               }
 
-                                       /* execute child code ... */
-                                       if( chdir(pi->wdir) )
-                                               perror("chdir()");
 
-                                       execl(pi->phys, pi->phys, NULL);
+                               /* execute child code ... */
+                               if( chdir(pi->root) )
+                                       perror("chdir()");
 
-                                       /* in case it fails ... */
-                                       printf(
-                                               "Status: 500 Internal Server Error\r\n\r\n"
-                                               "Unable to launch the requested CGI program:\n"
-                                               "  %s: %s\n",
-                                                       pi->phys, strerror(errno)
-                                       );
-                               }
+                               execl(pi->phys, pi->phys, NULL);
 
-                               /* 403 */
-                               else
-                               {
-                                       printf(
-                                               "Status: 403 Forbidden\r\n\r\n"
-                                               "Access to this resource is forbidden\n"
-                                       );
-                               }
+                               /* in case it fails ... */
+                               printf(
+                                       "Status: 500 Internal Server Error\r\n\r\n"
+                                       "Unable to launch the requested CGI program:\n"
+                                       "  %s: %s\n",
+                                               pi->phys, strerror(errno)
+                               );
                        }
 
-                       /* 404 */
+                       /* 403 */
                        else
                        {
                                printf(
-                                       "Status: 404 Not Found\r\n\r\n"
-                                       "Unable to launch the requested CGI program:\n"
-                                       "  No such file or directory\n"
+                                       "Status: 403 Forbidden\r\n\r\n"
+                                       "Access to this resource is forbidden\n"
                                );
                        }
 
@@ -481,6 +466,15 @@ void uh_cgi_request(struct client *cl, struct http_request *req)
                                                /* looks like eof from child */
                                                else
                                                {
+                                                       /* cgi script did not output useful stuff at all */
+                                                       if( ! header_sent )
+                                                       {
+                                                               uh_cgi_error_500(cl, req,
+                                                                       "The CGI program generated an invalid response:\n\n");
+
+                                                               uh_http_send(cl, req, hdr, hdrlen);
+                                                       }
+
                                                        /* send final chunk if we're in chunked transfer mode */
                                                        uh_http_send(cl, req, "", 0);
                                                        break;
index 4632bcc..c505076 100644 (file)
@@ -6,15 +6,8 @@
 #include <sys/types.h>
 #include <linux/limits.h>
 
-void uh_cgi_request(struct client *cl, struct http_request *req);
-
-struct path_info {
-       char *root;
-       char *wdir;
-       char *phys;
-       char *name;
-       char *info;
-       char *query;
-};
+void uh_cgi_request(
+       struct client *cl, struct http_request *req, struct uh_path_info *pi
+);
 
 #endif
index c0e353a..c300f0e 100644 (file)
@@ -2,8 +2,8 @@
 #define _BSD_SOURCE                    /* scandir() ... */
 
 #include "uhttpd.h"
-#include "uhttpd-file.h"
 #include "uhttpd-utils.h"
+#include "uhttpd-file.h"
 
 #include "uhttpd-mimetypes.h"
 
@@ -296,40 +296,38 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct
 }
 
 
-void uh_file_request(struct client *cl, struct http_request *req)
+void uh_file_request(struct client *cl, struct http_request *req, struct uh_path_info *pi)
 {
        int fd, rlen;
        char buf[UH_LIMIT_MSGHEAD];
-       struct uh_path_info *pi;
 
-       /* obtain path information */
-       if( (pi = uh_path_lookup(cl, req->url)) != NULL )
+       /* we have a file */
+       if( (pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0) )
        {
-               /* we have a file */
-               if( (pi->stat.st_mode & S_IFREG) &&
-                   ((fd = open(pi->phys, O_RDONLY)) > 0)
+               /* test preconditions */
+               if(
+                       uh_file_if_modified_since(cl, req, &pi->stat)   &&
+                       uh_file_if_match(cl, req, &pi->stat)            &&
+                       uh_file_if_range(cl, req, &pi->stat)            &&
+                       uh_file_if_unmodified_since(cl, req, &pi->stat) &&
+                       uh_file_if_none_match(cl, req, &pi->stat)
                ) {
-                       /* test preconditions */
-                       if(
-                               uh_file_if_modified_since(cl, req, &pi->stat)   &&
-                               uh_file_if_match(cl, req, &pi->stat)            &&
-                               uh_file_if_range(cl, req, &pi->stat)            &&
-                               uh_file_if_unmodified_since(cl, req, &pi->stat) &&
-                               uh_file_if_none_match(cl, req, &pi->stat)
-                       ) {
-                               /* write status */
-                               uh_file_response_200(cl, req, &pi->stat);
-
-                               uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name));
-                               uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size);
-
-                               /* if request was HTTP 1.1 we'll respond chunked */
-                               if( req->version > 1.0 )
-                                       uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1);
-
-                               /* close header */
-                               uh_http_send(cl, NULL, "\r\n", -1);
+                       /* write status */
+                       uh_file_response_200(cl, req, &pi->stat);
+
+                       uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name));
+                       uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size);
+
+                       /* if request was HTTP 1.1 we'll respond chunked */
+                       if( (req->version > 1.0) && (req->method != UH_HTTP_MSG_HEAD) )
+                               uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1);
 
+                       /* close header */
+                       uh_http_send(cl, NULL, "\r\n", -1);
+
+                       /* send body */
+                       if( req->method != UH_HTTP_MSG_HEAD )
+                       {
                                /* pump file data */
                                while( (rlen = read(fd, buf, sizeof(buf))) > 0 )
                                {
@@ -339,44 +337,37 @@ void uh_file_request(struct client *cl, struct http_request *req)
                                /* send trailer in chunked mode */
                                uh_http_send(cl, req, "", 0);
                        }
-
-                       /* one of the preconditions failed, terminate opened header and exit */
-                       else
-                       {
-                               uh_http_send(cl, NULL, "\r\n", -1);
-                       }
-
-                       close(fd);
                }
 
-               /* directory */
-               else if( pi->stat.st_mode & S_IFDIR )
+               /* one of the preconditions failed, terminate opened header and exit */
+               else
                {
-                       /* write status */
-                       uh_file_response_200(cl, req, NULL);
+                       uh_http_send(cl, NULL, "\r\n", -1);
+               }
 
-                       if( req->version > 1.0 )
-                               uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1);
+               close(fd);
+       }
 
-                       uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1);
+       /* directory */
+       else if( pi->stat.st_mode & S_IFDIR )
+       {
+               /* write status */
+               uh_file_response_200(cl, req, NULL);
 
-                       /* content */
-                       uh_file_dirlist(cl, req, pi);
-               }
+               if( req->version > 1.0 )
+                       uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1);
 
-               /* 403 */
-               else
-               {
-                       uh_http_sendhf(cl, 403, "Forbidden",
-                               "Access to this resource is forbidden");
-               }
+               uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1);
+
+               /* content */
+               uh_file_dirlist(cl, req, pi);
        }
 
-       /* 404 */
+       /* 403 */
        else
        {
-               uh_http_sendhf(cl, 404, "Not Found",
-                       "No such file or directory");
+               uh_http_sendhf(cl, 403, "Forbidden",
+                       "Access to this resource is forbidden");
        }
 }
 
index 9e56c38..37303e0 100644 (file)
@@ -1,4 +1,4 @@
-#ifndef _UHTTPD_CGI_
+#ifndef _UHTTPD_FILE_
 
 #include <fcntl.h>
 #include <time.h>
@@ -13,6 +13,8 @@ struct mimetype {
        const char *mime;
 };
 
-void uh_file_request(struct client *cl, struct http_request *req);
+void uh_file_request(
+       struct client *cl, struct http_request *req, struct uh_path_info *pi
+);
 
 #endif
index 79fb767..b2ca34e 100644 (file)
@@ -1,6 +1,6 @@
 #include "uhttpd.h"
-#include "uhttpd-lua.h"
 #include "uhttpd-utils.h"
+#include "uhttpd-lua.h"
 
 
 static int uh_lua_recv(lua_State *L)
@@ -196,6 +196,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
 {
        int i;
        char *query_string;
+       const char *prefix = cl->server->conf->lua_prefix;
        const char *err_str = NULL;
 
        /* put handler callback on stack */
@@ -237,12 +238,19 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
                lua_pushstring(L, query_string + 1);
                lua_setfield(L, -2, "query_string");
 
-               lua_pushlstring(L, req->url, (int)(query_string - req->url));
-               lua_setfield(L, -2, "path_info");
+               if( (int)(query_string - req->url) > strlen(prefix) )
+               {
+                       lua_pushlstring(L,
+                               &req->url[strlen(prefix)],
+                               (int)(query_string - req->url) - strlen(prefix)
+                       );
+
+                       lua_setfield(L, -2, "path_info");
+               }
        }
-       else
+       else if( strlen(req->url) > strlen(prefix) )
        {
-               lua_pushstring(L, req->url);
+               lua_pushstring(L, &req->url[strlen(prefix)]);
                lua_setfield(L, -2, "path_info");
        }
 
index 7596b35..2a0d641 100644 (file)
@@ -15,6 +15,8 @@
 
 lua_State * uh_lua_init();
 
-void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L);
+void uh_lua_request(
+       struct client *cl, struct http_request *req, lua_State *L
+);
 
 #endif
index 89ee46f..89a2368 100644 (file)
@@ -344,9 +344,7 @@ struct uh_path_info * uh_path_lookup(struct client *cl, const char *url)
        char *docroot = cl->server->conf->docroot;
        char *pathptr = NULL;
 
-       int skip = 0;
-       int plen = 0;
-
+       int i = 0;
        struct stat s;
 
 
@@ -355,129 +353,101 @@ struct uh_path_info * uh_path_lookup(struct client *cl, const char *url)
        memset(buffer, 0, sizeof(buffer));
        memset(&p, 0, sizeof(p));
 
-       /* first separate query string from url */
+       /* copy docroot */
+       memcpy(buffer, docroot, sizeof(buffer));
+
+       /* separate query string from url */
        if( (pathptr = strchr(url, '?')) != NULL )
        {
                p.query = pathptr[1] ? pathptr + 1 : NULL;
 
                /* urldecode component w/o query */
                if( pathptr > url )
-                       plen = uh_urldecode(
-                               buffer, sizeof(buffer), url,
-                               (int)(pathptr - url) - 1
+                       uh_urldecode(
+                               &buffer[strlen(docroot)],
+                               sizeof(buffer) - strlen(docroot) - 1,
+                               url, (int)(pathptr - url) - 1
                        );
-               else
-                       plen = 0;
        }
 
        /* no query string, decode all of url */
        else
        {
-               plen = uh_urldecode(
-                       buffer, sizeof(buffer), url, strlen(url)
+               uh_urldecode(
+                       &buffer[strlen(docroot)],
+                       sizeof(buffer) - strlen(docroot) - 1,
+                       url, strlen(url)
                );
        }
 
-       /* copy docroot */
-       memcpy(path_phys, docroot, sizeof(path_phys));
-
-       /* append normalized path, leave two bytes free
-        * for trailing slash and terminating zero byte */
-       plen = strlen(docroot) + uh_path_normalize(
-               &path_phys[strlen(docroot)],
-               sizeof(path_phys) - strlen(docroot) - 2,
-               buffer, plen
-       );
-
-       /* copy result to info buffer */
-       memcpy(path_info, path_phys, sizeof(path_info));
-
-       /* find path */
-       while( 1 )
+       /* create canon path */
+       for( i = strlen(buffer); i >= 0; i-- )
        {
-               /* test current path */
-               if( !stat(path_phys, &p.stat) )
+               if( (buffer[i] == 0) || (buffer[i] == '/') )
                {
-                       /* is a regular file */
-                       if( p.stat.st_mode & S_IFREG )
-                       {
-                               p.root = docroot;
-                               p.phys = path_phys;
-                               p.name = &path_phys[strlen(docroot)-1];
-
-                               /* find workdir */
-                               if( (pathptr = strrchr(path_phys, '/')) != NULL )
-                               {
-                                       path_info[(int)(pathptr - path_phys) + 1] = 0;
-                                       p.wdir = path_info;
-                               }
-                               else
-                               {
-                                       p.wdir = docroot;
-                               }
+                       memset(path_info, 0, sizeof(path_info));
+                       memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
 
-                               /* find path info */
-                               if( path_info[strlen(path_phys)] != 0 )
-                               {
-                                       p.info = &path_info[strlen(path_phys)];
-                               }
+                       if( realpath(path_info, path_phys) )
+                       {
+                               memset(path_info, 0, sizeof(path_info));
+                               memcpy(path_info, &buffer[i],
+                                       min(strlen(buffer) - i, sizeof(path_info) - 1));
 
                                break;
                        }
+               }
+       }
 
-                       /* is a directory */
-                       else if( (p.stat.st_mode & S_IFDIR) && (skip < 1) )
-                       {
-                               /* ensure trailing slash */
-                               if( path_phys[plen-1] != '/' )
-                                       path_phys[plen] = '/';
-
-                               /* try to locate index file */
-                               memset(buffer, 0, sizeof(buffer));
-                               memcpy(buffer, path_phys, sizeof(buffer));
-                               pathptr = &buffer[strlen(buffer)];
+       /* check whether found path is within docroot */
+       if( strncmp(path_phys, docroot, strlen(docroot)) ||
+           ((path_phys[strlen(docroot)] != 0) &&
+                (path_phys[strlen(docroot)] != '/'))
+       ) {
+               return NULL;
+       }
 
-                               for( skip = 0; skip < array_size(uh_index_files); skip++ )
-                               {
-                                       strncat(buffer, uh_index_files[skip], sizeof(buffer));
-
-                                       if( !stat(buffer, &s) && (s.st_mode & S_IFREG) )
-                                       {
-                                               memset(path_info, 0, sizeof(path_info));
-                                               memcpy(path_info, path_phys, strlen(path_phys));
-                                               memcpy(path_phys, buffer, sizeof(path_phys));
-                                               memcpy(&p.stat, &s, sizeof(p.stat));
-                                               p.wdir = path_info;
-                                               break;
-                                       }
-
-                                       *pathptr = 0;
-                               }
+       /* test current path */
+       if( ! stat(path_phys, &p.stat) )
+       {
+               /* is a regular file */
+               if( p.stat.st_mode & S_IFREG )
+               {
+                       p.root = docroot;
+                       p.phys = path_phys;
+                       p.name = &path_phys[strlen(docroot)];
+                       p.info = path_info[0] ? path_info : NULL;
+               }
 
-                               p.root = docroot;
-                               p.phys = path_phys;
-                               p.name = &path_phys[strlen(docroot)-1];
+               /* is a directory */
+               else if( (p.stat.st_mode & S_IFDIR) && !strlen(path_info) )
+               {
+                       /* ensure trailing slash */
+                       if( path_phys[strlen(path_phys)-1] != '/' )
+                               path_phys[strlen(path_phys)] = '/';
 
-                               break;
-                       }
+                       /* try to locate index file */
+                       memset(buffer, 0, sizeof(buffer));
+                       memcpy(buffer, path_phys, sizeof(buffer));
+                       pathptr = &buffer[strlen(buffer)];
 
-                       /* not found */
-                       else if( skip )
+                       for( i = 0; i < array_size(uh_index_files); i++ )
                        {
-                               break;
-                       }
-               }
+                               strncat(buffer, uh_index_files[i], sizeof(buffer));
 
-               else if( (strlen(path_phys) > strlen(docroot)) &&
-                        ((pathptr = strrchr(path_phys, '/')) != NULL)
-               ) {
-                       *pathptr = 0;
-                       skip = 1;
-               }
+                               if( !stat(buffer, &s) && (s.st_mode & S_IFREG) )
+                               {
+                                       memcpy(path_phys, buffer, sizeof(path_phys));
+                                       memcpy(&p.stat, &s, sizeof(p.stat));
+                                       break;
+                               }
 
-               else
-               {
-                       break;
+                               *pathptr = 0;
+                       }
+
+                       p.root = docroot;
+                       p.phys = path_phys;
+                       p.name = &path_phys[strlen(docroot)];
                }
        }
 
index ec7dbcb..01b95af 100644 (file)
@@ -4,8 +4,8 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
-#define min(x, y) ((x) < (y)) ? (x) : (y)
-#define max(x, y) ((x) > (y)) ? (x) : (y)
+#define min(x, y) (((x) < (y)) ? (x) : (y))
+#define max(x, y) (((x) > (y)) ? (x) : (y))
 
 #define array_size(x) \
        (sizeof(x) / sizeof(x[0]))
index 80029ca..804d397 100644 (file)
@@ -315,34 +315,6 @@ static struct http_request * uh_http_header_recv(struct client *cl)
        return NULL;
 }
 
-static int uh_docroot_resolve(const char *path, char *buf)
-{
-       char curpath[PATH_MAX];
-
-       if( ! getcwd(curpath, sizeof(curpath)) )
-       {
-               perror("getcwd()");
-               return 0;
-       }
-
-       if( chdir(path) || !getcwd(buf, PATH_MAX) )
-       {
-               return 0;
-       }
-       else
-       {
-               buf[strlen(buf)] = '/';
-       }
-
-       if( chdir(curpath) )
-       {
-               perror("chdir()");
-               return 0;
-       }
-
-       return 1;
-}
-
 
 int main (int argc, char **argv)
 {
@@ -357,6 +329,7 @@ int main (int argc, char **argv)
        /* working structs */
        struct addrinfo hints;
        struct http_request *req;
+       struct uh_path_info *pin;
        struct client *cl;
        struct sigaction sa;
        struct config conf;
@@ -467,9 +440,9 @@ int main (int argc, char **argv)
 
                        /* docroot */
                        case 'h':
-                               if( ! uh_docroot_resolve(optarg, conf.docroot) )
+                               if( ! realpath(optarg, conf.docroot) )
                                {
-                                       fprintf(stderr, "Invalid directory: %s\n", optarg);
+                                       fprintf(stderr, "Invalid directory %s: %s\n", optarg, strerror(errno));
                                        exit(1);
                                }
                                break;
@@ -551,9 +524,10 @@ int main (int argc, char **argv)
        }
 
        /* default docroot */
-       if( !conf.docroot[0] && !uh_docroot_resolve(".", conf.docroot) )
+       if( !conf.docroot[0] && !realpath(".", conf.docroot) )
        {
-               fprintf(stderr, "Can not determine default document root\n");
+               fprintf(stderr, "Can not determine default document root: %s\n",
+                       strerror(errno));
                exit(1);
        }
 
@@ -673,31 +647,44 @@ int main (int argc, char **argv)
                                                goto cleanup;
                                        }
 
-                                       /* parse message header and dispatch request */
+                                       /* parse message header */
                                        if( (req = uh_http_header_recv(cl)) != NULL )
                                        {
-#ifdef HAVE_CGI
-                                               if( strstr(req->url, conf.cgi_prefix) == req->url )
+                                               /* dispatch request */
+                                               if( (pin = uh_path_lookup(cl, req->url)) != NULL )
                                                {
-                                                       uh_cgi_request(cl, req);
-                                               }
-                                               else
+#ifdef HAVE_CGI
+                                                       if( strstr(pin->name, conf.cgi_prefix) == pin->name )
+                                                       {
+                                                               uh_cgi_request(cl, req, pin);
+                                                       }
+                                                       else
 #endif
-
+                                                       {
+                                                               uh_file_request(cl, req, pin);
+                                                       }
+                                               }
 #ifdef HAVE_LUA
-                                               if( (L != NULL) &&
-                                                   (strstr(req->url, conf.lua_prefix) == req->url)
-                                               {
+                                               /* Lua request? */
+                                               else if( strstr(req->url, conf.lua_prefix) == req->url )
+                                               {
                                                        uh_lua_request(cl, req, L);
                                                }
-                                               else
 #endif
-
+                                               /* 404 */
+                                               else
                                                {
-                                                       uh_file_request(cl, req);
+                                                       uh_http_sendhf(cl, 404, "Not Found",
+                                                               "No such file or directory");
                                                }
                                        }
 
+                                       /* 400 */
+                                       else
+                                       {
+                                               uh_http_sendhf(cl, 400, "Bad Request",
+                                                       "Malformed request received");
+                                       }
 
 #ifdef HAVE_TLS
                                        /* free client tls context */