uhttpd: - fix a compile warning - support custom index file names - support custom error pages (or cgi handler) - add option to disable directory listings - add REDIRECT_STATUS for CGI requests, fixes php-cgi

SVN-Revision: 22366
This commit is contained in:
Jo-Philipp Wich 2010-07-23 13:15:22 +00:00
parent c28ab82e04
commit b688fcaa5c
7 changed files with 139 additions and 18 deletions

View file

@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=uhttpd PKG_NAME:=uhttpd
PKG_RELEASE:=11 PKG_RELEASE:=12
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)

View file

@ -17,6 +17,17 @@ append_arg() {
[ -n "$val" -o -n "$def" ] && append UHTTPD_ARGS "$opt ${val:-$def}" [ -n "$val" -o -n "$def" ] && append UHTTPD_ARGS "$opt ${val:-$def}"
} }
append_bool() {
local cfg="$1"
local var="$2"
local opt="$3"
local def="$4"
local val
config_get_bool val "$cfg" "$var" "$def"
[ "$val" = 1 ] && append UHTTPD_ARGS "$opt"
}
generate_keys() { generate_keys() {
local cfg="$1" local cfg="$1"
local key="$2" local key="$2"
@ -59,6 +70,11 @@ start_instance()
append_arg "$cfg" lua_handler "-L" append_arg "$cfg" lua_handler "-L"
append_arg "$cfg" script_timeout "-t" append_arg "$cfg" script_timeout "-t"
append_arg "$cfg" network_timeout "-T" append_arg "$cfg" network_timeout "-T"
append_arg "$cfg" error_page "-E"
append_arg "$cfg" index_page "-I"
append_bool "$cfg" no_symlinks "-S" 0
append_bool "$cfg" no_dirlists "-D" 0
config_get http "$cfg" listen_http config_get http "$cfg" listen_http
for listen in $http; do for listen in $http; do

View file

@ -234,6 +234,17 @@ void uh_cgi_request(struct client *cl, struct http_request *req, struct path_inf
if( pi->info ) if( pi->info )
setenv("PATH_INFO", pi->info, 1); setenv("PATH_INFO", pi->info, 1);
/* REDIRECT_STATUS, php-cgi wants it */
switch( req->redirect_status )
{
case 404:
setenv("REDIRECT_STATUS", "404", 1);
break;
default:
setenv("REDIRECT_STATUS", "200", 1);
break;
}
/* http version */ /* http version */
if( req->version > 1.0 ) if( req->version > 1.0 )

View file

@ -29,7 +29,7 @@
static const char * uh_file_mime_lookup(const char *path) static const char * uh_file_mime_lookup(const char *path)
{ {
struct mimetype *m = &uh_mime_types[0]; struct mimetype *m = &uh_mime_types[0];
char *e; const char *e;
while( m->extn ) while( m->extn )
{ {
@ -275,7 +275,9 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct
strncat(filename, files[i]->d_name, strncat(filename, files[i]->d_name,
sizeof(filename) - strlen(files[i]->d_name)); sizeof(filename) - strlen(files[i]->d_name));
if( !stat(filename, &s) && (s.st_mode & S_IFDIR) ) if( !stat(filename, &s) &&
(s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH)
)
uh_http_sendf(cl, req, uh_http_sendf(cl, req,
"<li><strong><a href='%s%s'>%s</a>/</strong><br />" "<li><strong><a href='%s%s'>%s</a>/</strong><br />"
"<small>modified: %s<br />directory - %.02f kbyte" "<small>modified: %s<br />directory - %.02f kbyte"
@ -293,7 +295,9 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct
strncat(filename, files[i]->d_name, strncat(filename, files[i]->d_name,
sizeof(filename) - strlen(files[i]->d_name)); sizeof(filename) - strlen(files[i]->d_name));
if( !stat(filename, &s) && !(s.st_mode & S_IFDIR) ) if( !stat(filename, &s) &&
!(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH)
)
uh_http_sendf(cl, req, uh_http_sendf(cl, req,
"<li><strong><a href='%s%s'>%s</a></strong><br />" "<li><strong><a href='%s%s'>%s</a></strong><br />"
"<small>modified: %s<br />%s - %.02f kbyte<br />" "<small>modified: %s<br />%s - %.02f kbyte<br />"
@ -369,7 +373,7 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in
} }
/* directory */ /* directory */
else if( pi->stat.st_mode & S_IFDIR ) else if( (pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists )
{ {
/* write status */ /* write status */
uh_file_response_200(cl, req, NULL); uh_file_response_200(cl, req, NULL);

View file

@ -464,6 +464,9 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
int i = 0; int i = 0;
struct stat s; struct stat s;
/* back out early if url is undefined */
if ( url == NULL )
return NULL;
memset(path_phys, 0, sizeof(path_phys)); memset(path_phys, 0, sizeof(path_phys));
memset(path_info, 0, sizeof(path_info)); memset(path_info, 0, sizeof(path_info));
@ -550,18 +553,31 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
memcpy(buffer, path_phys, sizeof(buffer)); memcpy(buffer, path_phys, sizeof(buffer));
pathptr = &buffer[strlen(buffer)]; pathptr = &buffer[strlen(buffer)];
for( i = 0; i < array_size(uh_index_files); i++ ) if( cl->server->conf->index_file )
{ {
strncat(buffer, uh_index_files[i], sizeof(buffer)); strncat(buffer, cl->server->conf->index_file, sizeof(buffer));
if( !stat(buffer, &s) && (s.st_mode & S_IFREG) ) if( !stat(buffer, &s) && (s.st_mode & S_IFREG) )
{ {
memcpy(path_phys, buffer, sizeof(path_phys)); memcpy(path_phys, buffer, sizeof(path_phys));
memcpy(&p.stat, &s, sizeof(p.stat)); memcpy(&p.stat, &s, sizeof(p.stat));
break;
} }
}
else
{
for( i = 0; i < array_size(uh_index_files); i++ )
{
strncat(buffer, uh_index_files[i], sizeof(buffer));
*pathptr = 0; 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.root = docroot;

View file

@ -47,7 +47,7 @@ static void uh_sigchld(int sig)
while( waitpid(-1, NULL, WNOHANG) > 0 ) { } while( waitpid(-1, NULL, WNOHANG) > 0 ) { }
} }
static void uh_config_parse(const char *path) static void uh_config_parse(struct config *conf)
{ {
FILE *c; FILE *c;
char line[512]; char line[512];
@ -55,7 +55,10 @@ static void uh_config_parse(const char *path)
char *pass = NULL; char *pass = NULL;
char *eol = NULL; char *eol = NULL;
if( (c = fopen(path ? path : "/etc/httpd.conf", "r")) != NULL ) const char *path = conf->file ? conf->file : "/etc/httpd.conf";
if( (c = fopen(path, "r")) != NULL )
{ {
memset(line, 0, sizeof(line)); memset(line, 0, sizeof(line));
@ -74,10 +77,24 @@ static void uh_config_parse(const char *path)
"Notice: No password set for user %s, ignoring " "Notice: No password set for user %s, ignoring "
"authentication on %s\n", user, line "authentication on %s\n", user, line
); );
break;
} }
} }
else if( !strncmp(line, "I:", 2) )
{
if( !(user = strchr(line, ':')) || (*user++ = 0) ||
!(eol = strchr(user, '\n')) || (*eol++ = 0) )
continue;
conf->index_file = strdup(user);
}
else if( !strncmp(line, "E404:", 5) )
{
if( !(user = strchr(line, ':')) || (*user++ = 0) ||
!(eol = strchr(user, '\n')) || (*eol++ = 0) )
continue;
conf->error_handler = strdup(user);
}
} }
fclose(c); fclose(c);
@ -302,6 +319,7 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
} }
/* valid enough */ /* valid enough */
req.redirect_status = 200;
return &req; return &req;
} }
@ -505,8 +523,9 @@ int main (int argc, char **argv)
} }
#endif #endif
while( (opt = getopt(argc, argv, "fSC:K:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0 ) while( (opt = getopt(argc, argv,
{ "fSDC:K:E:I:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0
) {
switch(opt) switch(opt)
{ {
/* [addr:]port */ /* [addr:]port */
@ -597,11 +616,38 @@ int main (int argc, char **argv)
} }
break; break;
/* error handler */
case 'E':
if( (strlen(optarg) == 0) || (optarg[0] != '/') )
{
fprintf(stderr, "Error: Invalid error handler: %s\n",
optarg);
exit(1);
}
conf.error_handler = optarg;
break;
/* index file */
case 'I':
if( (strlen(optarg) == 0) || (optarg[0] == '/') )
{
fprintf(stderr, "Error: Invalid index page: %s\n",
optarg);
exit(1);
}
conf.index_file = optarg;
break;
/* don't follow symlinks */ /* don't follow symlinks */
case 'S': case 'S':
conf.no_symlinks = 1; conf.no_symlinks = 1;
break; break;
/* don't list directories */
case 'D':
conf.no_dirlists = 1;
break;
#ifdef HAVE_CGI #ifdef HAVE_CGI
/* cgi prefix */ /* cgi prefix */
case 'x': case 'x':
@ -678,7 +724,10 @@ int main (int argc, char **argv)
" -K file ASN.1 server private key file\n" " -K file ASN.1 server private key file\n"
#endif #endif
" -h directory Specify the document root, default is '.'\n" " -h directory Specify the document root, default is '.'\n"
" -E string Use given virtual URL as 404 error handler\n"
" -I string Use given filename as index page for directories\n"
" -S Do not follow symbolic links outside of the docroot\n" " -S Do not follow symbolic links outside of the docroot\n"
" -D Do not allow directory listings, send 403 instead\n"
#ifdef HAVE_LUA #ifdef HAVE_LUA
" -l string URL prefix for Lua handler, default is '/lua'\n" " -l string URL prefix for Lua handler, default is '/lua'\n"
" -L file Lua handler script, omit to disable Lua\n" " -L file Lua handler script, omit to disable Lua\n"
@ -727,7 +776,7 @@ int main (int argc, char **argv)
conf.realm = "Protected Area"; conf.realm = "Protected Area";
/* config file */ /* config file */
uh_config_parse(conf.file); uh_config_parse(&conf);
/* default network timeout */ /* default network timeout */
if( conf.network_timeout <= 0 ) if( conf.network_timeout <= 0 )
@ -913,8 +962,29 @@ int main (int argc, char **argv)
/* 404 */ /* 404 */
else else
{ {
uh_http_sendhf(cl, 404, "Not Found", /* Try to invoke an error handler */
"No such file or directory"); pin = uh_path_lookup(cl, conf.error_handler);
if( pin && uh_auth_check(cl, req, pin) )
{
req->redirect_status = 404;
#ifdef HAVE_CGI
if( uh_path_match(conf.cgi_prefix, pin->name) )
{
uh_cgi_request(cl, req, pin);
}
else
#endif
{
uh_file_request(cl, req, pin);
}
}
else
{
uh_http_sendhf(cl, 404, "Not Found",
"No such file or directory");
}
} }
} }

View file

@ -64,7 +64,10 @@ struct config {
char docroot[PATH_MAX]; char docroot[PATH_MAX];
char *realm; char *realm;
char *file; char *file;
char *index_file;
char *error_handler;
int no_symlinks; int no_symlinks;
int no_dirlists;
int network_timeout; int network_timeout;
#ifdef HAVE_CGI #ifdef HAVE_CGI
char *cgi_prefix; char *cgi_prefix;
@ -124,6 +127,7 @@ struct auth_realm {
struct http_request { struct http_request {
int method; int method;
float version; float version;
int redirect_status;
char *url; char *url;
char *headers[UH_LIMIT_HEADERS]; char *headers[UH_LIMIT_HEADERS];
struct auth_realm *realm; struct auth_realm *realm;