From 0f18174879e121e5c5a64de0e3cb88a9c78e2b37 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sat, 20 Mar 2010 13:45:50 +0000 Subject: uhttpd: - rework url parsing and path resolving - handle more cgi quirks - change request dispatching - clean up cflags --- contrib/package/uhttpd/src/Makefile | 4 +- contrib/package/uhttpd/src/uhttpd-cgi.c | 208 +++++++++++++++--------------- contrib/package/uhttpd/src/uhttpd-cgi.h | 13 +- contrib/package/uhttpd/src/uhttpd-file.c | 101 +++++++-------- contrib/package/uhttpd/src/uhttpd-file.h | 6 +- contrib/package/uhttpd/src/uhttpd-lua.c | 18 ++- contrib/package/uhttpd/src/uhttpd-lua.h | 4 +- contrib/package/uhttpd/src/uhttpd-utils.c | 164 ++++++++++------------- contrib/package/uhttpd/src/uhttpd-utils.h | 4 +- contrib/package/uhttpd/src/uhttpd.c | 77 +++++------ 10 files changed, 273 insertions(+), 326 deletions(-) (limited to 'contrib') diff --git a/contrib/package/uhttpd/src/Makefile b/contrib/package/uhttpd/src/Makefile index a94dff9f8d..7bbb23afc1 100644 --- a/contrib/package/uhttpd/src/Makefile +++ b/contrib/package/uhttpd/src/Makefile @@ -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 diff --git a/contrib/package/uhttpd/src/uhttpd-cgi.c b/contrib/package/uhttpd/src/uhttpd-cgi.c index 7c4703759a..7836167ff8 100644 --- a/contrib/package/uhttpd/src/uhttpd-cgi.c +++ b/contrib/package/uhttpd/src/uhttpd-cgi.c @@ -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; diff --git a/contrib/package/uhttpd/src/uhttpd-cgi.h b/contrib/package/uhttpd/src/uhttpd-cgi.h index 4632bcc278..c505076f4f 100644 --- a/contrib/package/uhttpd/src/uhttpd-cgi.h +++ b/contrib/package/uhttpd/src/uhttpd-cgi.h @@ -6,15 +6,8 @@ #include #include -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 diff --git a/contrib/package/uhttpd/src/uhttpd-file.c b/contrib/package/uhttpd/src/uhttpd-file.c index c0e353a8ef..c300f0e455 100644 --- a/contrib/package/uhttpd/src/uhttpd-file.c +++ b/contrib/package/uhttpd/src/uhttpd-file.c @@ -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"); } } diff --git a/contrib/package/uhttpd/src/uhttpd-file.h b/contrib/package/uhttpd/src/uhttpd-file.h index 9e56c3876f..37303e07bd 100644 --- a/contrib/package/uhttpd/src/uhttpd-file.h +++ b/contrib/package/uhttpd/src/uhttpd-file.h @@ -1,4 +1,4 @@ -#ifndef _UHTTPD_CGI_ +#ifndef _UHTTPD_FILE_ #include #include @@ -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 diff --git a/contrib/package/uhttpd/src/uhttpd-lua.c b/contrib/package/uhttpd/src/uhttpd-lua.c index 79fb76770c..b2ca34e0c1 100644 --- a/contrib/package/uhttpd/src/uhttpd-lua.c +++ b/contrib/package/uhttpd/src/uhttpd-lua.c @@ -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"); } diff --git a/contrib/package/uhttpd/src/uhttpd-lua.h b/contrib/package/uhttpd/src/uhttpd-lua.h index 7596b354d5..2a0d6411c4 100644 --- a/contrib/package/uhttpd/src/uhttpd-lua.h +++ b/contrib/package/uhttpd/src/uhttpd-lua.h @@ -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 diff --git a/contrib/package/uhttpd/src/uhttpd-utils.c b/contrib/package/uhttpd/src/uhttpd-utils.c index 89ee46ffd0..89a23686cd 100644 --- a/contrib/package/uhttpd/src/uhttpd-utils.c +++ b/contrib/package/uhttpd/src/uhttpd-utils.c @@ -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)]; } } diff --git a/contrib/package/uhttpd/src/uhttpd-utils.h b/contrib/package/uhttpd/src/uhttpd-utils.h index ec7dbcb9b4..01b95afca7 100644 --- a/contrib/package/uhttpd/src/uhttpd-utils.h +++ b/contrib/package/uhttpd/src/uhttpd-utils.h @@ -4,8 +4,8 @@ #include #include -#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])) diff --git a/contrib/package/uhttpd/src/uhttpd.c b/contrib/package/uhttpd/src/uhttpd.c index 80029ca095..804d397b85 100644 --- a/contrib/package/uhttpd/src/uhttpd.c +++ b/contrib/package/uhttpd/src/uhttpd.c @@ -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 */ -- cgit v1.2.3