aboutsummaryrefslogtreecommitdiffstats
path: root/package/uhttpd/src
diff options
context:
space:
mode:
authorJo-Philipp Wich <jow@openwrt.org>2010-08-14 00:54:24 +0000
committerJo-Philipp Wich <jow@openwrt.org>2010-08-14 00:54:24 +0000
commit36e143f8304389d2de1f08cb738a83c5e23265e5 (patch)
tree17bc5dc1b3511e6b222aeb5d83d1d62a758d43b5 /package/uhttpd/src
parent65d6e285f1998cd7c5431ecbbd46c64464a82062 (diff)
downloadmaster-187ad058-36e143f8304389d2de1f08cb738a83c5e23265e5.tar.gz
master-187ad058-36e143f8304389d2de1f08cb738a83c5e23265e5.tar.bz2
master-187ad058-36e143f8304389d2de1f08cb738a83c5e23265e5.zip
[package] uhttpd:
- more robust handling of network failures on static file serving - support unlimited amount of authentication realms, listener and client sockets - support for interpreters (.php => /usr/bin/php-cgi) git-svn-id: svn://svn.openwrt.org/openwrt/trunk@22630 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'package/uhttpd/src')
-rw-r--r--package/uhttpd/src/uhttpd-cgi.c19
-rw-r--r--package/uhttpd/src/uhttpd-cgi.h3
-rw-r--r--package/uhttpd/src/uhttpd-file.c24
-rw-r--r--package/uhttpd/src/uhttpd-utils.c123
-rw-r--r--package/uhttpd/src/uhttpd-utils.h5
-rw-r--r--package/uhttpd/src/uhttpd.c414
-rw-r--r--package/uhttpd/src/uhttpd.h15
7 files changed, 350 insertions, 253 deletions
diff --git a/package/uhttpd/src/uhttpd-cgi.c b/package/uhttpd/src/uhttpd-cgi.c
index 0861249162..f9dd9810da 100644
--- a/package/uhttpd/src/uhttpd-cgi.c
+++ b/package/uhttpd/src/uhttpd-cgi.c
@@ -135,8 +135,10 @@ static int uh_cgi_error_500(struct client *cl, struct http_request *req, const c
}
-void uh_cgi_request(struct client *cl, struct http_request *req, struct path_info *pi)
-{
+void uh_cgi_request(
+ struct client *cl, struct http_request *req,
+ struct path_info *pi, struct interpreter *ip
+) {
int i, hdroff, bufoff;
int hdrlen = 0;
int buflen = 0;
@@ -199,9 +201,9 @@ void uh_cgi_request(struct client *cl, struct http_request *req, struct path_inf
dup2(rfd[1], 1);
dup2(wfd[0], 0);
- /* check for regular, world-executable file */
- if( (pi->stat.st_mode & S_IFREG) &&
- (pi->stat.st_mode & S_IXOTH)
+ /* check for regular, world-executable file _or_ interpreter */
+ if( ((pi->stat.st_mode & S_IFREG) &&
+ (pi->stat.st_mode & S_IXOTH)) || (ip != NULL)
) {
/* build environment */
clearenv();
@@ -320,14 +322,17 @@ void uh_cgi_request(struct client *cl, struct http_request *req, struct path_inf
if( chdir(pi->root) )
perror("chdir()");
- execl(pi->phys, pi->phys, NULL);
+ if( ip != NULL )
+ execl(ip->path, ip->path, pi->phys, NULL);
+ else
+ 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)
+ ip ? ip->path : pi->phys, strerror(errno)
);
}
diff --git a/package/uhttpd/src/uhttpd-cgi.h b/package/uhttpd/src/uhttpd-cgi.h
index c90557d8fd..cb84dae0c6 100644
--- a/package/uhttpd/src/uhttpd-cgi.h
+++ b/package/uhttpd/src/uhttpd-cgi.h
@@ -25,7 +25,8 @@
#include <linux/limits.h>
void uh_cgi_request(
- struct client *cl, struct http_request *req, struct path_info *pi
+ struct client *cl, struct http_request *req,
+ struct path_info *pi, struct interpreter *ip
);
#endif
diff --git a/package/uhttpd/src/uhttpd-file.c b/package/uhttpd/src/uhttpd-file.c
index ef9a77b6cc..25a5f6ece3 100644
--- a/package/uhttpd/src/uhttpd-file.c
+++ b/package/uhttpd/src/uhttpd-file.c
@@ -98,9 +98,9 @@ static char * uh_file_header_lookup(struct http_request *req, const char *name)
}
#define ensure_ret(x) \
- do { if( x < 0 ) return; } while(0)
+ do { if( x < 0 ) return -1; } while(0)
-static void uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s)
+static int uh_file_response_ok_hdrs(struct client *cl, struct http_request *req, struct stat *s)
{
ensure_ret(uh_http_sendf(cl, NULL, "Connection: close\r\n"));
@@ -110,26 +110,26 @@ static void uh_file_response_ok_hdrs(struct client *cl, struct http_request *req
ensure_ret(uh_http_sendf(cl, NULL, "Last-Modified: %s\r\n", uh_file_unix2date(s->st_mtime)));
}
- ensure_ret(uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL))));
+ return uh_http_sendf(cl, NULL, "Date: %s\r\n", uh_file_unix2date(time(NULL)));
}
-static void uh_file_response_200(struct client *cl, struct http_request *req, struct stat *s)
+static int uh_file_response_200(struct client *cl, struct http_request *req, struct stat *s)
{
ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version));
- uh_file_response_ok_hdrs(cl, req, s);
+ return uh_file_response_ok_hdrs(cl, req, s);
}
-static void uh_file_response_304(struct client *cl, struct http_request *req, struct stat *s)
+static int uh_file_response_304(struct client *cl, struct http_request *req, struct stat *s)
{
ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version));
- uh_file_response_ok_hdrs(cl, req, s);
+ return uh_file_response_ok_hdrs(cl, req, s);
}
-static void uh_file_response_412(struct client *cl, struct http_request *req)
+static int uh_file_response_412(struct client *cl, struct http_request *req)
{
- ensure_ret(uh_http_sendf(cl, NULL,
+ return uh_http_sendf(cl, NULL,
"HTTP/%.1f 412 Precondition Failed\r\n"
- "Connection: close\r\n", req->version));
+ "Connection: close\r\n", req->version);
}
static int uh_file_if_match(struct client *cl, struct http_request *req, struct stat *s)
@@ -350,7 +350,7 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in
uh_file_if_none_match(cl, req, &pi->stat)
) {
/* write status */
- uh_file_response_200(cl, req, &pi->stat);
+ ensure_out(uh_file_response_200(cl, req, &pi->stat));
ensure_out(uh_http_sendf(cl, NULL, "Content-Type: %s\r\n", uh_file_mime_lookup(pi->name)));
ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size));
@@ -385,7 +385,7 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in
else if( (pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists )
{
/* write status */
- uh_file_response_200(cl, req, NULL);
+ ensure_out(uh_file_response_200(cl, req, NULL));
if( req->version > 1.0 )
ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1));
diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c
index 4a1423c715..e68926e935 100644
--- a/package/uhttpd/src/uhttpd-utils.c
+++ b/package/uhttpd/src/uhttpd-utils.c
@@ -605,8 +605,7 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
}
-static char uh_realms[UH_LIMIT_AUTHREALMS * sizeof(struct auth_realm)] = { 0 };
-static int uh_realm_count = 0;
+static struct auth_realm *uh_realms = NULL;
struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
{
@@ -614,11 +613,8 @@ struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
struct passwd *pwd;
struct spwd *spwd;
- if( uh_realm_count < UH_LIMIT_AUTHREALMS )
+ if((new = (struct auth_realm *)malloc(sizeof(struct auth_realm))) != NULL)
{
- new = (struct auth_realm *)
- &uh_realms[uh_realm_count * sizeof(struct auth_realm)];
-
memset(new, 0, sizeof(struct auth_realm));
memcpy(new->path, path,
@@ -655,9 +651,13 @@ struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
if( new->pass[0] )
{
- uh_realm_count++;
+ new->next = uh_realms;
+ uh_realms = new;
+
return new;
}
+
+ free(new);
}
return NULL;
@@ -677,11 +677,8 @@ int uh_auth_check(
protected = 0;
/* check whether at least one realm covers the requested url */
- for( i = 0; i < uh_realm_count; i++ )
+ for( realm = uh_realms; realm; realm = realm->next )
{
- realm = (struct auth_realm *)
- &uh_realms[i * sizeof(struct auth_realm)];
-
rlen = strlen(realm->path);
if( (plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen) )
@@ -721,11 +718,8 @@ int uh_auth_check(
if( user && pass )
{
/* find matching realm */
- for( i = 0, realm = NULL; i < uh_realm_count; i++ )
+ for( realm = uh_realms; realm; realm = realm->next )
{
- realm = (struct auth_realm *)
- &uh_realms[i * sizeof(struct auth_realm)];
-
rlen = strlen(realm->path);
if( (plen >= rlen) &&
@@ -769,22 +763,17 @@ int uh_auth_check(
}
-static char uh_listeners[UH_LIMIT_LISTENERS * sizeof(struct listener)] = { 0 };
-static char uh_clients[UH_LIMIT_CLIENTS * sizeof(struct client)] = { 0 };
-
-static int uh_listener_count = 0;
-static int uh_client_count = 0;
-
+static struct listener *uh_listeners = NULL;
+static struct client *uh_clients = NULL;
struct listener * uh_listener_add(int sock, struct config *conf)
{
struct listener *new = NULL;
socklen_t sl;
- if( uh_listener_count < UH_LIMIT_LISTENERS )
+ if( (new = (struct listener *)malloc(sizeof(struct listener))) != NULL )
{
- new = (struct listener *)
- &uh_listeners[uh_listener_count * sizeof(struct listener)];
+ memset(new, 0, sizeof(struct listener));
new->socket = sock;
new->conf = conf;
@@ -794,24 +783,22 @@ struct listener * uh_listener_add(int sock, struct config *conf)
memset(&(new->addr), 0, sl);
getsockname(sock, (struct sockaddr *) &(new->addr), &sl);
- uh_listener_count++;
+ new->next = uh_listeners;
+ uh_listeners = new;
+
+ return new;
}
- return new;
+ return NULL;
}
struct listener * uh_listener_lookup(int sock)
{
struct listener *cur = NULL;
- int i;
-
- for( i = 0; i < uh_listener_count; i++ )
- {
- cur = (struct listener *) &uh_listeners[i * sizeof(struct listener)];
+ for( cur = uh_listeners; cur; cur = cur->next )
if( cur->socket == sock )
return cur;
- }
return NULL;
}
@@ -822,10 +809,9 @@ struct client * uh_client_add(int sock, struct listener *serv)
struct client *new = NULL;
socklen_t sl;
- if( uh_client_count < UH_LIMIT_CLIENTS )
+ if( (new = (struct client *)malloc(sizeof(struct client))) != NULL )
{
- new = (struct client *)
- &uh_clients[uh_client_count * sizeof(struct client)];
+ memset(new, 0, sizeof(struct client));
new->socket = sock;
new->server = serv;
@@ -840,7 +826,8 @@ struct client * uh_client_add(int sock, struct listener *serv)
memset(&(new->servaddr), 0, sl);
getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl);
- uh_client_count++;
+ new->next = uh_clients;
+ uh_clients = new;
}
return new;
@@ -849,30 +836,72 @@ struct client * uh_client_add(int sock, struct listener *serv)
struct client * uh_client_lookup(int sock)
{
struct client *cur = NULL;
- int i;
-
- for( i = 0; i < uh_client_count; i++ )
- {
- cur = (struct client *) &uh_clients[i * sizeof(struct client)];
+ for( cur = uh_clients; cur; cur = cur->next )
if( cur->socket == sock )
return cur;
- }
return NULL;
}
void uh_client_remove(int sock)
{
- struct client *del = uh_client_lookup(sock);
+ struct client *cur = NULL;
+ struct client *prv = NULL;
+
+ for( cur = uh_clients; cur; prv = cur, cur = cur->next )
+ {
+ if( cur->socket == sock )
+ {
+ if( prv )
+ prv->next = cur->next;
+ else
+ uh_clients = cur->next;
+
+ free(cur);
+ break;
+ }
+ }
+}
+
+
+#ifdef HAVE_CGI
+static struct interpreter *uh_interpreters = NULL;
+
+struct interpreter * uh_interpreter_add(const char *extn, const char *path)
+{
+ struct interpreter *new = NULL;
- if( del )
+ if( (new = (struct interpreter *)
+ malloc(sizeof(struct interpreter))) != NULL )
{
- memmove(del, del + 1,
- sizeof(uh_clients) - (int)((char *)del - uh_clients) - sizeof(struct client));
+ memset(new, 0, sizeof(struct interpreter));
+
+ memcpy(new->extn, extn, min(strlen(extn), sizeof(new->extn)-1));
+ memcpy(new->path, path, min(strlen(path), sizeof(new->path)-1));
+
+ new->next = uh_interpreters;
+ uh_interpreters = new;
- uh_client_count--;
+ return new;
}
+
+ return NULL;
}
+struct interpreter * uh_interpreter_lookup(const char *path)
+{
+ struct interpreter *cur = NULL;
+ const char *e;
+
+ for( cur = uh_interpreters; cur; cur = cur->next )
+ {
+ e = &path[max(strlen(path) - strlen(cur->extn), 0)];
+ if( !strcmp(e, cur->extn) )
+ return cur;
+ }
+
+ return NULL;
+}
+#endif
diff --git a/package/uhttpd/src/uhttpd-utils.h b/package/uhttpd/src/uhttpd-utils.h
index 1b18265417..95535d6fe7 100644
--- a/package/uhttpd/src/uhttpd-utils.h
+++ b/package/uhttpd/src/uhttpd-utils.h
@@ -101,4 +101,9 @@ struct client * uh_client_add(int sock, struct listener *serv);
struct client * uh_client_lookup(int sock);
void uh_client_remove(int sock);
+#ifdef HAVE_CGI
+struct interpreter * uh_interpreter_add(const char *extn, const char *path);
+struct interpreter * uh_interpreter_lookup(const char *path);
+#endif
+
#endif
diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c
index 764ff7d570..6406e459ad 100644
--- a/package/uhttpd/src/uhttpd.c
+++ b/package/uhttpd/src/uhttpd.c
@@ -51,8 +51,8 @@ static void uh_config_parse(struct config *conf)
{
FILE *c;
char line[512];
- char *user = NULL;
- char *pass = NULL;
+ char *col1 = NULL;
+ char *col2 = NULL;
char *eol = NULL;
const char *path = conf->file ? conf->file : "/etc/httpd.conf";
@@ -66,35 +66,51 @@ static void uh_config_parse(struct config *conf)
{
if( (line[0] == '/') && (strchr(line, ':') != NULL) )
{
- if( !(user = strchr(line, ':')) || (*user++ = 0) ||
- !(pass = strchr(user, ':')) || (*pass++ = 0) ||
- !(eol = strchr(pass, '\n')) || (*eol++ = 0) )
+ if( !(col1 = strchr(line, ':')) || (*col1++ = 0) ||
+ !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
+ !(eol = strchr(col2, '\n')) || (*eol++ = 0) )
continue;
- if( !uh_auth_add(line, user, pass) )
+ if( !uh_auth_add(line, col1, col2) )
{
fprintf(stderr,
"Notice: No password set for user %s, ignoring "
- "authentication on %s\n", user, line
+ "authentication on %s\n", col1, line
);
}
}
else if( !strncmp(line, "I:", 2) )
{
- if( !(user = strchr(line, ':')) || (*user++ = 0) ||
- !(eol = strchr(user, '\n')) || (*eol++ = 0) )
+ if( !(col1 = strchr(line, ':')) || (*col1++ = 0) ||
+ !(eol = strchr(col1, '\n')) || (*eol++ = 0) )
continue;
- conf->index_file = strdup(user);
+ conf->index_file = strdup(col1);
}
else if( !strncmp(line, "E404:", 5) )
{
- if( !(user = strchr(line, ':')) || (*user++ = 0) ||
- !(eol = strchr(user, '\n')) || (*eol++ = 0) )
+ if( !(col1 = strchr(line, ':')) || (*col1++ = 0) ||
+ !(eol = strchr(col1, '\n')) || (*eol++ = 0) )
continue;
- conf->error_handler = strdup(user);
+ conf->error_handler = strdup(col1);
}
+#ifdef HAVE_CGI
+ else if( (line[0] == '.') && (strchr(line, ':') != NULL) )
+ {
+ if( !(col1 = strchr(line, ':')) || (*col1++ = 0) ||
+ !(eol = strchr(col1, '\n')) || (*eol++ = 0) )
+ continue;
+
+ if( !uh_interpreter_add(line, col1) )
+ {
+ fprintf(stderr,
+ "Unable to add interpreter %s for extension %s: "
+ "Out of memory\n", col1, line
+ );
+ }
+ }
+#endif
}
fclose(c);
@@ -162,11 +178,7 @@ static int uh_socket_bind(
/* add listener to global list */
if( ! (l = uh_listener_add(sock, conf)) )
{
- fprintf(stderr,
- "uh_listener_add(): Can not create more than "
- "%i listen sockets\n", UH_LIMIT_LISTENERS
- );
-
+ fprintf(stderr, "uh_listener_add(): Failed to allocate memory\n");
goto error;
}
@@ -397,6 +409,7 @@ static struct http_request * uh_http_header_recv(struct client *cl)
return NULL;
}
+#if defined(HAVE_LUA) || defined(HAVE_CGI)
static int uh_path_match(const char *prefix, const char *url)
{
if( (strstr(url, prefix) == url) &&
@@ -409,23 +422,193 @@ static int uh_path_match(const char *prefix, const char *url)
return 0;
}
+#endif
+static void uh_dispatch_request(
+ struct client *cl, struct http_request *req, struct path_info *pin
+) {
+#ifdef HAVE_CGI
+ struct interpreter *ipr = NULL;
-int main (int argc, char **argv)
+ if( uh_path_match(cl->server->conf->cgi_prefix, pin->name) ||
+ (ipr = uh_interpreter_lookup(pin->phys)) )
+ {
+ uh_cgi_request(cl, req, pin, ipr);
+ }
+ else
+#endif
+ {
+ uh_file_request(cl, req, pin);
+ }
+}
+
+static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
{
+ /* master file descriptor list */
+ fd_set used_fds, read_fds;
+
+ /* working structs */
+ struct http_request *req;
+ struct path_info *pin;
+ struct client *cl;
+
+ /* maximum file descriptor number */
+ int new_fd, cur_fd = 0;
+
+ /* clear the master and temp sets */
+ FD_ZERO(&used_fds);
+ FD_ZERO(&read_fds);
+
+ /* backup server descriptor set */
+ used_fds = serv_fds;
+
+ /* loop */
+ while(run)
+ {
+ /* create a working copy of the used fd set */
+ read_fds = used_fds;
+
+ /* sleep until socket activity */
+ if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 )
+ {
+ perror("select()");
+ exit(1);
+ }
+
+ /* run through the existing connections looking for data to be read */
+ for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ )
+ {
+ /* is a socket managed by us */
+ if( FD_ISSET(cur_fd, &read_fds) )
+ {
+ /* is one of our listen sockets */
+ if( FD_ISSET(cur_fd, &serv_fds) )
+ {
+ /* handle new connections */
+ if( (new_fd = accept(cur_fd, NULL, 0)) != -1 )
+ {
+ /* add to global client list */
+ if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL )
+ {
+#ifdef HAVE_TLS
+ /* setup client tls context */
+ if( conf->tls )
+ conf->tls_accept(cl);
+#endif
+
+ /* add client socket to global fdset */
+ FD_SET(new_fd, &used_fds);
+ fd_cloexec(new_fd);
+ max_fd = max(max_fd, new_fd);
+ }
+
+ /* insufficient resources */
+ else
+ {
+ fprintf(stderr,
+ "uh_client_add(): Cannot allocate memory\n");
+
+ close(new_fd);
+ }
+ }
+ }
+
+ /* is a client socket */
+ else
+ {
+ if( ! (cl = uh_client_lookup(cur_fd)) )
+ {
+ /* this should not happen! */
+ fprintf(stderr,
+ "uh_client_lookup(): No entry for fd %i!\n",
+ cur_fd);
+
+ goto cleanup;
+ }
+
+ /* parse message header */
+ if( (req = uh_http_header_recv(cl)) != NULL )
+ {
+ /* RFC1918 filtering required? */
+ if( conf->rfc1918_filter &&
+ sa_rfc1918(&cl->peeraddr) &&
+ !sa_rfc1918(&cl->servaddr) )
+ {
+ uh_http_sendhf(cl, 403, "Forbidden",
+ "Rejected request from RFC1918 IP "
+ "to public server address");
+ }
+ else
#ifdef HAVE_LUA
- /* Lua runtime */
- lua_State *L = NULL;
+ /* Lua request? */
+ if( conf->lua_state &&
+ uh_path_match(conf->lua_prefix, req->url) )
+ {
+ conf->lua_request(cl, req, conf->lua_state);
+ }
+ else
#endif
+ /* dispatch request */
+ if( (pin = uh_path_lookup(cl, req->url)) != NULL )
+ {
+ /* auth ok? */
+ if( uh_auth_check(cl, req, pin) )
+ uh_dispatch_request(cl, req, pin);
+ }
+ /* 404 */
+ else
+ {
+ /* Try to invoke an error handler */
+ pin = uh_path_lookup(cl, conf->error_handler);
+
+ if( pin && uh_auth_check(cl, req, pin) )
+ {
+ req->redirect_status = 404;
+ uh_dispatch_request(cl, req, pin);
+ }
+ else
+ {
+ uh_http_sendhf(cl, 404, "Not Found",
+ "No such file or directory");
+ }
+ }
+ }
+
+#ifdef HAVE_TLS
+ /* free client tls context */
+ if( conf->tls )
+ conf->tls_close(cl);
+#endif
+
+ cleanup:
+
+ /* close client socket */
+ close(cur_fd);
+ FD_CLR(cur_fd, &used_fds);
+
+ /* remove from global client list */
+ uh_client_remove(cur_fd);
+ }
+ }
+ }
+ }
+
+#ifdef HAVE_LUA
+ /* destroy the Lua state */
+ if( conf->lua_state != NULL )
+ conf->lua_close(conf->lua_state);
+#endif
+}
+
+
+int main (int argc, char **argv)
+{
/* master file descriptor list */
fd_set used_fds, serv_fds, read_fds;
/* working structs */
struct addrinfo hints;
- struct http_request *req;
- struct path_info *pin;
- struct client *cl;
struct sigaction sa;
struct config conf;
@@ -433,7 +616,7 @@ int main (int argc, char **argv)
sigset_t ss;
/* maximum file descriptor number */
- int new_fd, cur_fd, max_fd = 0;
+ int cur_fd, max_fd = 0;
#ifdef HAVE_TLS
int tls = 0;
@@ -525,7 +708,7 @@ int main (int argc, char **argv)
#endif
while( (opt = getopt(argc, argv,
- "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:t:T:")) > 0
+ "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:i:t:T:")) > 0
) {
switch(opt)
{
@@ -658,6 +841,21 @@ int main (int argc, char **argv)
case 'x':
conf.cgi_prefix = optarg;
break;
+
+ /* interpreter */
+ case 'i':
+ if( (optarg[0] == '.') && (port = strchr(optarg, '=')) )
+ {
+ *port++ = 0;
+ uh_interpreter_add(optarg, port);
+ }
+ else
+ {
+ fprintf(stderr, "Error: Invalid interpreter: %s\n",
+ optarg);
+ exit(1);
+ }
+ break;
#endif
#ifdef HAVE_LUA
@@ -740,6 +938,7 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_CGI
" -x string URL prefix for CGI handler, default is '/cgi-bin'\n"
+ " -i .ext=path Use interpreter at path for files with the given extension\n"
#endif
#if defined(HAVE_CGI) || defined(HAVE_LUA)
" -t seconds CGI and Lua script timeout in seconds, default is 60\n"
@@ -830,7 +1029,7 @@ int main (int argc, char **argv)
if( ! conf.lua_prefix )
conf.lua_prefix = "/lua";
- L = conf.lua_init(conf.lua_handler);
+ conf.lua_state = conf.lua_init(conf.lua_handler);
}
}
#endif
@@ -865,166 +1064,13 @@ int main (int argc, char **argv)
}
}
- /* backup server descriptor set */
- used_fds = serv_fds;
-
- /* loop */
- while(run)
- {
- /* create a working copy of the used fd set */
- read_fds = used_fds;
-
- /* sleep until socket activity */
- if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 )
- {
- perror("select()");
- exit(1);
- }
-
- /* run through the existing connections looking for data to be read */
- for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ )
- {
- /* is a socket managed by us */
- if( FD_ISSET(cur_fd, &read_fds) )
- {
- /* is one of our listen sockets */
- if( FD_ISSET(cur_fd, &serv_fds) )
- {
- /* handle new connections */
- if( (new_fd = accept(cur_fd, NULL, 0)) != -1 )
- {
- /* add to global client list */
- if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL )
- {
-#ifdef HAVE_TLS
- /* setup client tls context */
- if( conf.tls )
- conf.tls_accept(cl);
-#endif
-
- /* add client socket to global fdset */
- FD_SET(new_fd, &used_fds);
- fd_cloexec(new_fd);
- max_fd = max(max_fd, new_fd);
- }
-
- /* insufficient resources */
- else
- {
- fprintf(stderr,
- "uh_client_add(): Can not manage more than "
- "%i client sockets, connection dropped\n",
- UH_LIMIT_CLIENTS
- );
-
- close(new_fd);
- }
- }
- }
-
- /* is a client socket */
- else
- {
- if( ! (cl = uh_client_lookup(cur_fd)) )
- {
- /* this should not happen! */
- fprintf(stderr,
- "uh_client_lookup(): No entry for fd %i!\n",
- cur_fd);
-
- goto cleanup;
- }
-
- /* parse message header */
- if( (req = uh_http_header_recv(cl)) != NULL )
- {
- /* RFC1918 filtering required? */
- if( conf.rfc1918_filter && sa_rfc1918(&cl->peeraddr) &&
- !sa_rfc1918(&cl->servaddr) )
- {
- uh_http_sendhf(cl, 403, "Forbidden",
- "Rejected request from RFC1918 IP to public server address");
- }
- else
-#ifdef HAVE_LUA
- /* Lua request? */
- if( L && uh_path_match(conf.lua_prefix, req->url) )
- {
- conf.lua_request(cl, req, L);
- }
- else
-#endif
- /* dispatch request */
- if( (pin = uh_path_lookup(cl, req->url)) != NULL )
- {
- /* auth ok? */
- if( uh_auth_check(cl, req, pin) )
- {
-#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);
- }
- }
- }
-
- /* 404 */
- else
- {
- /* Try to invoke an error handler */
- 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");
- }
- }
- }
-
-#ifdef HAVE_TLS
- /* free client tls context */
- if( conf.tls )
- conf.tls_close(cl);
-#endif
-
- cleanup:
-
- /* close client socket */
- close(cur_fd);
- FD_CLR(cur_fd, &used_fds);
-
- /* remove from global client list */
- uh_client_remove(cur_fd);
- }
- }
- }
- }
+ /* server main loop */
+ uh_mainloop(&conf, serv_fds, max_fd);
#ifdef HAVE_LUA
/* destroy the Lua state */
- if( L != NULL )
- conf.lua_close(L);
+ if( conf.lua_state != NULL )
+ conf.lua_close(conf.lua_state);
#endif
return 0;
diff --git a/package/uhttpd/src/uhttpd.h b/package/uhttpd/src/uhttpd.h
index fd2176ebdd..78cca7b3b2 100644
--- a/package/uhttpd/src/uhttpd.h
+++ b/package/uhttpd/src/uhttpd.h
@@ -48,9 +48,7 @@
#define UH_LIMIT_MSGHEAD 4096
#define UH_LIMIT_HEADERS 64
-#define UH_LIMIT_LISTENERS 16
#define UH_LIMIT_CLIENTS 64
-#define UH_LIMIT_AUTHREALMS 8
#define UH_HTTP_MSG_GET 0
#define UH_HTTP_MSG_HEAD 1
@@ -58,6 +56,7 @@
struct listener;
struct client;
+struct interpreter;
struct http_request;
struct config {
@@ -76,6 +75,7 @@ struct config {
#ifdef HAVE_LUA
char *lua_prefix;
char *lua_handler;
+ lua_State *lua_state;
lua_State * (*lua_init) (const char *handler);
void (*lua_close) (lua_State *L);
void (*lua_request) (struct client *cl, struct http_request *req, lua_State *L);
@@ -105,6 +105,7 @@ struct listener {
#ifdef HAVE_TLS
SSL_CTX *tls;
#endif
+ struct listener *next;
};
struct client {
@@ -117,12 +118,14 @@ struct client {
#ifdef HAVE_TLS
SSL *tls;
#endif
+ struct client *next;
};
struct auth_realm {
char path[PATH_MAX];
char user[32];
char pass[128];
+ struct auth_realm *next;
};
struct http_request {
@@ -140,5 +143,13 @@ struct http_response {
char *headers[UH_LIMIT_HEADERS];
};
+#ifdef HAVE_CGI
+struct interpreter {
+ char path[PATH_MAX];
+ char extn[32];
+ struct interpreter *next;
+};
+#endif
+
#endif