summaryrefslogtreecommitdiffhomepage
path: root/contrib
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2010-03-20 13:45:50 +0000
committerJo-Philipp Wich <jow@openwrt.org>2010-03-20 13:45:50 +0000
commit0f18174879e121e5c5a64de0e3cb88a9c78e2b37 (patch)
treeb6baf4fa1aacd49304075b00765e70c8ff0eb3fe /contrib
parent66ffcefa5555b35fc2e71429d9be16ac6de82801 (diff)
uhttpd:
- rework url parsing and path resolving - handle more cgi quirks - change request dispatching - clean up cflags
Diffstat (limited to 'contrib')
-rw-r--r--contrib/package/uhttpd/src/Makefile4
-rw-r--r--contrib/package/uhttpd/src/uhttpd-cgi.c208
-rw-r--r--contrib/package/uhttpd/src/uhttpd-cgi.h13
-rw-r--r--contrib/package/uhttpd/src/uhttpd-file.c101
-rw-r--r--contrib/package/uhttpd/src/uhttpd-file.h6
-rw-r--r--contrib/package/uhttpd/src/uhttpd-lua.c18
-rw-r--r--contrib/package/uhttpd/src/uhttpd-lua.h4
-rw-r--r--contrib/package/uhttpd/src/uhttpd-utils.c164
-rw-r--r--contrib/package/uhttpd/src/uhttpd-utils.h4
-rw-r--r--contrib/package/uhttpd/src/uhttpd.c77
10 files changed, 273 insertions, 326 deletions
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 <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
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 <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
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 <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]))
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 */