- rework url parsing and path resolving
	- handle more cgi quirks
	- change request dispatching
	- clean up cflags
This commit is contained in:
Jo-Philipp Wich 2010-03-20 13:45:50 +00:00
parent 66ffcefa55
commit 0f18174879
10 changed files with 291 additions and 344 deletions

View file

@ -2,10 +2,10 @@ CGI_SUPPORT ?= 1
LUA_SUPPORT ?= 1 LUA_SUPPORT ?= 1
TLS_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 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 LDFLAGS += -lm -lcrypt
OBJ = uhttpd.o uhttpd-file.o uhttpd-utils.o OBJ = uhttpd.o uhttpd-file.o uhttpd-utils.o

View file

@ -1,6 +1,6 @@
#include "uhttpd.h" #include "uhttpd.h"
#include "uhttpd-cgi.h"
#include "uhttpd-utils.h" #include "uhttpd-utils.h"
#include "uhttpd-cgi.h"
static struct http_response * uh_cgi_header_parse(char *buf, int len, int *off) 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 i, hdroff, bufoff;
int hdrlen = 0; int hdrlen = 0;
@ -134,7 +134,6 @@ void uh_cgi_request(struct client *cl, struct http_request *req)
struct timeval timeout; struct timeval timeout;
struct http_response *res; struct http_response *res;
struct uh_path_info *pi;
/* spawn pipes for me->child, child->me */ /* 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(rfd[1], 1);
dup2(wfd[0], 0); 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) &&
/* check for regular, world-executable file */ (pi->stat.st_mode & S_IXOTH)
if( (pi->stat.st_mode & S_IFREG) && ) {
(pi->stat.st_mode & S_IXOTH) /* build environment */
) { clearenv();
/* build environment */
clearenv();
/* common information */ /* common information */
setenv("GATEWAY_INTERFACE", "CGI/1.1", 1); setenv("GATEWAY_INTERFACE", "CGI/1.1", 1);
setenv("SERVER_SOFTWARE", "uHTTPd", 1); setenv("SERVER_SOFTWARE", "uHTTPd", 1);
setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1); setenv("PATH", "/sbin:/usr/sbin:/bin:/usr/bin", 1);
#ifdef HAVE_TLS #ifdef HAVE_TLS
/* https? */ /* https? */
if( cl->tls ) if( cl->tls )
setenv("HTTPS", "on", 1); setenv("HTTPS", "on", 1);
#endif #endif
/* addresses */ /* addresses */
setenv("SERVER_NAME", sa_straddr(&cl->servaddr), 1); setenv("SERVER_NAME", sa_straddr(&cl->servaddr), 1);
setenv("SERVER_ADDR", sa_straddr(&cl->servaddr), 1); setenv("SERVER_ADDR", sa_straddr(&cl->servaddr), 1);
setenv("SERVER_PORT", sa_strport(&cl->servaddr), 1); setenv("SERVER_PORT", sa_strport(&cl->servaddr), 1);
setenv("REMOTE_HOST", sa_straddr(&cl->peeraddr), 1); setenv("REMOTE_HOST", sa_straddr(&cl->peeraddr), 1);
setenv("REMOTE_ADDR", sa_straddr(&cl->peeraddr), 1); setenv("REMOTE_ADDR", sa_straddr(&cl->peeraddr), 1);
setenv("REMOTE_PORT", sa_strport(&cl->peeraddr), 1); setenv("REMOTE_PORT", sa_strport(&cl->peeraddr), 1);
/* path information */ /* path information */
setenv("SCRIPT_NAME", pi->name, 1); setenv("SCRIPT_NAME", pi->name, 1);
setenv("SCRIPT_FILENAME", pi->phys, 1); setenv("SCRIPT_FILENAME", pi->phys, 1);
setenv("SCRIPT_WORKDIR", pi->wdir, 1); /* nonstandard */ setenv("DOCUMENT_ROOT", pi->root, 1);
setenv("DOCUMENT_ROOT", pi->root, 1); setenv("QUERY_STRING", pi->query ? pi->query : "", 1);
setenv("QUERY_STRING", pi->query ? pi->query : "", 1);
if( pi->info ) if( pi->info )
setenv("PATH_INFO", pi->info, 1); setenv("PATH_INFO", pi->info, 1);
/* http version */ /* http version */
if( req->version > 1.0 ) if( req->version > 1.0 )
setenv("SERVER_PROTOCOL", "HTTP/1.1", 1); 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;
case UH_HTTP_MSG_HEAD:
setenv("REQUEST_METHOD", "HEAD", 1);
break;
case UH_HTTP_MSG_POST:
setenv("REQUEST_METHOD", "POST", 1);
break;
}
/* request url */
setenv("REQUEST_URI", req->url, 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-Charset") )
setenv("HTTP_ACCEPT_CHARSET", 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-Language") )
setenv("HTTP_ACCEPT_LANGUAGE", 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], "Connection") )
setenv("HTTP_CONNECTION", 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], "Host") )
setenv("HTTP_HOST", 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], "User-Agent") )
setenv("HTTP_USER_AGENT", 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);
/* 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)
);
}
/* 403 */
else else
setenv("SERVER_PROTOCOL", "HTTP/1.0", 1);
/* request method */
switch( req->method )
{ {
printf( case UH_HTTP_MSG_GET:
"Status: 403 Forbidden\r\n\r\n" setenv("REQUEST_METHOD", "GET", 1);
"Access to this resource is forbidden\n" break;
);
case UH_HTTP_MSG_HEAD:
setenv("REQUEST_METHOD", "HEAD", 1);
break;
case UH_HTTP_MSG_POST:
setenv("REQUEST_METHOD", "POST", 1);
break;
} }
/* request url */
setenv("REQUEST_URI", req->url, 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-Charset") )
setenv("HTTP_ACCEPT_CHARSET", 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-Language") )
setenv("HTTP_ACCEPT_LANGUAGE", 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], "Connection") )
setenv("HTTP_CONNECTION", 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], "Host") )
setenv("HTTP_HOST", 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], "User-Agent") )
setenv("HTTP_USER_AGENT", 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->root) )
perror("chdir()");
execl(pi->phys, pi->phys, NULL);
/* 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 else
{ {
printf( printf(
"Status: 404 Not Found\r\n\r\n" "Status: 403 Forbidden\r\n\r\n"
"Unable to launch the requested CGI program:\n" "Access to this resource is forbidden\n"
" No such file or directory\n"
); );
} }
@ -481,6 +466,15 @@ void uh_cgi_request(struct client *cl, struct http_request *req)
/* looks like eof from child */ /* looks like eof from child */
else 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 */ /* send final chunk if we're in chunked transfer mode */
uh_http_send(cl, req, "", 0); uh_http_send(cl, req, "", 0);
break; break;

View file

@ -6,15 +6,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <linux/limits.h> #include <linux/limits.h>
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
struct path_info { );
char *root;
char *wdir;
char *phys;
char *name;
char *info;
char *query;
};
#endif #endif

View file

@ -2,8 +2,8 @@
#define _BSD_SOURCE /* scandir() ... */ #define _BSD_SOURCE /* scandir() ... */
#include "uhttpd.h" #include "uhttpd.h"
#include "uhttpd-file.h"
#include "uhttpd-utils.h" #include "uhttpd-utils.h"
#include "uhttpd-file.h"
#include "uhttpd-mimetypes.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; int fd, rlen;
char buf[UH_LIMIT_MSGHEAD]; char buf[UH_LIMIT_MSGHEAD];
struct uh_path_info *pi;
/* obtain path information */ /* we have a file */
if( (pi = uh_path_lookup(cl, req->url)) != NULL ) if( (pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0) )
{ {
/* we have a file */ /* test preconditions */
if( (pi->stat.st_mode & S_IFREG) && if(
((fd = open(pi->phys, O_RDONLY)) > 0) 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 */ /* write status */
if( uh_file_response_200(cl, req, &pi->stat);
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-Type: %s\r\n", uh_file_mime_lookup(pi->name));
uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size); 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 request was HTTP 1.1 we'll respond chunked */
if( req->version > 1.0 ) if( (req->version > 1.0) && (req->method != UH_HTTP_MSG_HEAD) )
uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1); uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1);
/* close header */ /* close header */
uh_http_send(cl, NULL, "\r\n", -1); uh_http_send(cl, NULL, "\r\n", -1);
/* send body */
if( req->method != UH_HTTP_MSG_HEAD )
{
/* pump file data */ /* pump file data */
while( (rlen = read(fd, buf, sizeof(buf))) > 0 ) 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 */ /* send trailer in chunked mode */
uh_http_send(cl, req, "", 0); 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 */ /* one of the preconditions failed, terminate opened header and exit */
else if( pi->stat.st_mode & S_IFDIR )
{
/* write status */
uh_file_response_200(cl, req, NULL);
if( req->version > 1.0 )
uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1);
uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1);
/* content */
uh_file_dirlist(cl, req, pi);
}
/* 403 */
else else
{ {
uh_http_sendhf(cl, 403, "Forbidden", uh_http_send(cl, NULL, "\r\n", -1);
"Access to this resource is forbidden");
} }
close(fd);
} }
/* 404 */ /* directory */
else if( pi->stat.st_mode & S_IFDIR )
{
/* write status */
uh_file_response_200(cl, req, NULL);
if( req->version > 1.0 )
uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1);
uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1);
/* content */
uh_file_dirlist(cl, req, pi);
}
/* 403 */
else else
{ {
uh_http_sendhf(cl, 404, "Not Found", uh_http_sendhf(cl, 403, "Forbidden",
"No such file or directory"); "Access to this resource is forbidden");
} }
} }

View file

@ -1,4 +1,4 @@
#ifndef _UHTTPD_CGI_ #ifndef _UHTTPD_FILE_
#include <fcntl.h> #include <fcntl.h>
#include <time.h> #include <time.h>
@ -13,6 +13,8 @@ struct mimetype {
const char *mime; 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 #endif

View file

@ -1,6 +1,6 @@
#include "uhttpd.h" #include "uhttpd.h"
#include "uhttpd-lua.h"
#include "uhttpd-utils.h" #include "uhttpd-utils.h"
#include "uhttpd-lua.h"
static int uh_lua_recv(lua_State *L) 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; int i;
char *query_string; char *query_string;
const char *prefix = cl->server->conf->lua_prefix;
const char *err_str = NULL; const char *err_str = NULL;
/* put handler callback on stack */ /* 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_pushstring(L, query_string + 1);
lua_setfield(L, -2, "query_string"); lua_setfield(L, -2, "query_string");
lua_pushlstring(L, req->url, (int)(query_string - req->url)); if( (int)(query_string - req->url) > strlen(prefix) )
lua_setfield(L, -2, "path_info"); {
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"); lua_setfield(L, -2, "path_info");
} }

View file

@ -15,6 +15,8 @@
lua_State * uh_lua_init(); 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 #endif

View 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 *docroot = cl->server->conf->docroot;
char *pathptr = NULL; char *pathptr = NULL;
int skip = 0; int i = 0;
int plen = 0;
struct stat s; 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(buffer, 0, sizeof(buffer));
memset(&p, 0, sizeof(p)); 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 ) if( (pathptr = strchr(url, '?')) != NULL )
{ {
p.query = pathptr[1] ? pathptr + 1 : NULL; p.query = pathptr[1] ? pathptr + 1 : NULL;
/* urldecode component w/o query */ /* urldecode component w/o query */
if( pathptr > url ) if( pathptr > url )
plen = uh_urldecode( uh_urldecode(
buffer, sizeof(buffer), url, &buffer[strlen(docroot)],
(int)(pathptr - url) - 1 sizeof(buffer) - strlen(docroot) - 1,
url, (int)(pathptr - url) - 1
); );
else
plen = 0;
} }
/* no query string, decode all of url */ /* no query string, decode all of url */
else else
{ {
plen = uh_urldecode( uh_urldecode(
buffer, sizeof(buffer), url, strlen(url) &buffer[strlen(docroot)],
sizeof(buffer) - strlen(docroot) - 1,
url, strlen(url)
); );
} }
/* copy docroot */ /* create canon path */
memcpy(path_phys, docroot, sizeof(path_phys)); for( i = strlen(buffer); i >= 0; i-- )
/* 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 )
{ {
/* test current path */ if( (buffer[i] == 0) || (buffer[i] == '/') )
if( !stat(path_phys, &p.stat) )
{ {
/* is a regular file */ memset(path_info, 0, sizeof(path_info));
if( p.stat.st_mode & S_IFREG ) memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
if( realpath(path_info, path_phys) )
{ {
p.root = docroot; memset(path_info, 0, sizeof(path_info));
p.phys = path_phys; memcpy(path_info, &buffer[i],
p.name = &path_phys[strlen(docroot)-1]; min(strlen(buffer) - i, sizeof(path_info) - 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;
}
/* find path info */
if( path_info[strlen(path_phys)] != 0 )
{
p.info = &path_info[strlen(path_phys)];
}
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)];
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;
}
p.root = docroot;
p.phys = path_phys;
p.name = &path_phys[strlen(docroot)-1];
break;
}
/* not found */
else if( skip )
{
break; break;
} }
} }
}
else if( (strlen(path_phys) > strlen(docroot)) && /* check whether found path is within docroot */
((pathptr = strrchr(path_phys, '/')) != NULL) if( strncmp(path_phys, docroot, strlen(docroot)) ||
) { ((path_phys[strlen(docroot)] != 0) &&
*pathptr = 0; (path_phys[strlen(docroot)] != '/'))
skip = 1; ) {
return NULL;
}
/* 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;
} }
else /* is a directory */
else if( (p.stat.st_mode & S_IFDIR) && !strlen(path_info) )
{ {
break; /* ensure trailing slash */
if( path_phys[strlen(path_phys)-1] != '/' )
path_phys[strlen(path_phys)] = '/';
/* try to locate index file */
memset(buffer, 0, sizeof(buffer));
memcpy(buffer, path_phys, sizeof(buffer));
pathptr = &buffer[strlen(buffer)];
for( i = 0; i < array_size(uh_index_files); i++ )
{
strncat(buffer, uh_index_files[i], sizeof(buffer));
if( !stat(buffer, &s) && (s.st_mode & S_IFREG) )
{
memcpy(path_phys, buffer, sizeof(path_phys));
memcpy(&p.stat, &s, sizeof(p.stat));
break;
}
*pathptr = 0;
}
p.root = docroot;
p.phys = path_phys;
p.name = &path_phys[strlen(docroot)];
} }
} }

View file

@ -4,8 +4,8 @@
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#define min(x, y) ((x) < (y)) ? (x) : (y) #define min(x, y) (((x) < (y)) ? (x) : (y))
#define max(x, y) ((x) > (y)) ? (x) : (y) #define max(x, y) (((x) > (y)) ? (x) : (y))
#define array_size(x) \ #define array_size(x) \
(sizeof(x) / sizeof(x[0])) (sizeof(x) / sizeof(x[0]))

View file

@ -315,34 +315,6 @@ static struct http_request * uh_http_header_recv(struct client *cl)
return NULL; 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) int main (int argc, char **argv)
{ {
@ -357,6 +329,7 @@ int main (int argc, char **argv)
/* working structs */ /* working structs */
struct addrinfo hints; struct addrinfo hints;
struct http_request *req; struct http_request *req;
struct uh_path_info *pin;
struct client *cl; struct client *cl;
struct sigaction sa; struct sigaction sa;
struct config conf; struct config conf;
@ -467,9 +440,9 @@ int main (int argc, char **argv)
/* docroot */ /* docroot */
case 'h': 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); exit(1);
} }
break; break;
@ -551,9 +524,10 @@ int main (int argc, char **argv)
} }
/* default docroot */ /* 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); exit(1);
} }
@ -673,31 +647,44 @@ int main (int argc, char **argv)
goto cleanup; goto cleanup;
} }
/* parse message header and dispatch request */ /* parse message header */
if( (req = uh_http_header_recv(cl)) != NULL ) if( (req = uh_http_header_recv(cl)) != NULL )
{ {
#ifdef HAVE_CGI /* dispatch request */
if( strstr(req->url, conf.cgi_prefix) == req->url ) if( (pin = uh_path_lookup(cl, req->url)) != NULL )
{ {
uh_cgi_request(cl, req); #ifdef HAVE_CGI
} if( strstr(pin->name, conf.cgi_prefix) == pin->name )
else {
uh_cgi_request(cl, req, pin);
}
else
#endif #endif
{
uh_file_request(cl, req, pin);
}
}
#ifdef HAVE_LUA #ifdef HAVE_LUA
if( (L != NULL) && /* Lua request? */
(strstr(req->url, conf.lua_prefix) == req->url) else if( strstr(req->url, conf.lua_prefix) == req->url )
) { {
uh_lua_request(cl, req, L); uh_lua_request(cl, req, L);
} }
else
#endif #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 #ifdef HAVE_TLS
/* free client tls context */ /* free client tls context */