uhttpd: display errors in init script, code formatting changes, bump package version

SVN-Revision: 31572
This commit is contained in:
Jo-Philipp Wich 2012-05-03 17:19:22 +00:00
parent 54b34ccbc5
commit 8e9d914343
7 changed files with 535 additions and 496 deletions

View file

@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_NAME:=uhttpd PKG_NAME:=uhttpd
PKG_RELEASE:=31 PKG_RELEASE:=32
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
PKG_CONFIG_DEPENDS := \ PKG_CONFIG_DEPENDS := \

View file

@ -108,6 +108,11 @@ start_instance()
SERVICE_PID_FILE=/var/run/uhttpd_${cfg}.pid SERVICE_PID_FILE=/var/run/uhttpd_${cfg}.pid
service_start $UHTTPD_BIN -f $UHTTPD_ARGS service_start $UHTTPD_BIN -f $UHTTPD_ARGS
# Check if daemon is running, if not then
# re-execute in foreground to display error.
sleep 1 && service_check $UHTTPD_BIN || \
$UHTTPD_BIN -f $UHTTPD_ARGS
} }
stop_instance() stop_instance()

View file

@ -30,9 +30,9 @@ static struct http_response * uh_cgi_header_parse(char *buf, int len, int *off)
static struct http_response res; static struct http_response res;
if( ((bufptr = strfind(buf, len, "\r\n\r\n", 4)) != NULL) || if (((bufptr = strfind(buf, len, "\r\n\r\n", 4)) != NULL) ||
((bufptr = strfind(buf, len, "\n\n", 2)) != NULL) ((bufptr = strfind(buf, len, "\n\n", 2)) != NULL))
) { {
*off = (int)(bufptr - buf) + ((bufptr[0] == '\r') ? 4 : 2); *off = (int)(bufptr - buf) + ((bufptr[0] == '\r') ? 4 : 2);
memset(&res, 0, sizeof(res)); memset(&res, 0, sizeof(res));
@ -42,45 +42,48 @@ static struct http_response * uh_cgi_header_parse(char *buf, int len, int *off)
bufptr = &buf[0]; bufptr = &buf[0];
for( pos = 0; pos < *off; pos++ ) for (pos = 0; pos < *off; pos++)
{ {
if( !hdrname && (buf[pos] == ':') ) if (!hdrname && (buf[pos] == ':'))
{ {
buf[pos++] = 0; buf[pos++] = 0;
if( (pos < len) && (buf[pos] == ' ') ) if ((pos < len) && (buf[pos] == ' '))
pos++; pos++;
if( pos < len ) if (pos < len)
{ {
hdrname = bufptr; hdrname = bufptr;
bufptr = &buf[pos]; bufptr = &buf[pos];
} }
} }
else if( (buf[pos] == '\r') || (buf[pos] == '\n') ) else if ((buf[pos] == '\r') || (buf[pos] == '\n'))
{ {
if( ! hdrname ) if (! hdrname)
break; break;
buf[pos++] = 0; buf[pos++] = 0;
if( (pos < len) && (buf[pos] == '\n') ) if ((pos < len) && (buf[pos] == '\n'))
pos++; pos++;
if( pos <= len ) if (pos <= len)
{ {
if( (hdrcount + 1) < array_size(res.headers) ) if ((hdrcount + 1) < array_size(res.headers))
{ {
if( ! strcasecmp(hdrname, "Status") ) if (!strcasecmp(hdrname, "Status"))
{ {
res.statuscode = atoi(bufptr); res.statuscode = atoi(bufptr);
if( res.statuscode < 100 ) if (res.statuscode < 100)
res.statuscode = 200; res.statuscode = 200;
if( ((bufptr = strchr(bufptr, ' ')) != NULL) && (&bufptr[1] != 0) ) if (((bufptr = strchr(bufptr, ' ')) != NULL) &&
(&bufptr[1] != 0))
{
res.statusmsg = &bufptr[1]; res.statusmsg = &bufptr[1];
}
} }
else else
{ {
@ -105,29 +108,30 @@ static struct http_response * uh_cgi_header_parse(char *buf, int len, int *off)
return NULL; return NULL;
} }
static char * uh_cgi_header_lookup(struct http_response *res, const char *hdrname) static char * uh_cgi_header_lookup(struct http_response *res,
const char *hdrname)
{ {
int i; int i;
foreach_header(i, res->headers) foreach_header(i, res->headers)
{ {
if( ! strcasecmp(res->headers[i], hdrname) ) if (!strcasecmp(res->headers[i], hdrname))
return res->headers[i+1]; return res->headers[i+1];
} }
return NULL; return NULL;
} }
static int uh_cgi_error_500(struct client *cl, struct http_request *req, const char *message) static int uh_cgi_error_500(struct client *cl, struct http_request *req,
const char *message)
{ {
if( uh_http_sendf(cl, NULL, if (uh_http_sendf(cl, NULL,
"HTTP/%.1f 500 Internal Server Error\r\n" "HTTP/%.1f 500 Internal Server Error\r\n"
"Content-Type: text/plain\r\n%s\r\n", "Content-Type: text/plain\r\n%s\r\n",
req->version, req->version,
(req->version > 1.0) (req->version > 1.0)
? "Transfer-Encoding: chunked\r\n" : "" ? "Transfer-Encoding: chunked\r\n" : "") >= 0)
) >= 0 {
) {
return uh_http_send(cl, req, message, -1); return uh_http_send(cl, req, message, -1);
} }
@ -135,10 +139,9 @@ static int uh_cgi_error_500(struct client *cl, struct http_request *req, const c
} }
void uh_cgi_request( void uh_cgi_request(struct client *cl, struct http_request *req,
struct client *cl, struct http_request *req, struct path_info *pi, struct interpreter *ip)
struct path_info *pi, struct interpreter *ip {
) {
int i, hdroff, bufoff, rv; int i, hdroff, bufoff, rv;
int hdrlen = 0; int hdrlen = 0;
int buflen = 0; int buflen = 0;
@ -165,26 +168,26 @@ void uh_cgi_request(
/* spawn pipes for me->child, child->me */ /* spawn pipes for me->child, child->me */
if( (pipe(rfd) < 0) || (pipe(wfd) < 0) ) if ((pipe(rfd) < 0) || (pipe(wfd) < 0))
{ {
uh_http_sendhf(cl, 500, "Internal Server Error", uh_http_sendhf(cl, 500, "Internal Server Error",
"Failed to create pipe: %s", strerror(errno)); "Failed to create pipe: %s", strerror(errno));
if( rfd[0] > 0 ) close(rfd[0]); if (rfd[0] > 0) close(rfd[0]);
if( rfd[1] > 0 ) close(rfd[1]); if (rfd[1] > 0) close(rfd[1]);
if( wfd[0] > 0 ) close(wfd[0]); if (wfd[0] > 0) close(wfd[0]);
if( wfd[1] > 0 ) close(wfd[1]); if (wfd[1] > 0) close(wfd[1]);
return; return;
} }
/* fork off child process */ /* fork off child process */
switch( (child = fork()) ) switch ((child = fork()))
{ {
/* oops */ /* oops */
case -1: case -1:
uh_http_sendhf(cl, 500, "Internal Server Error", uh_http_sendhf(cl, 500, "Internal Server Error",
"Failed to fork child: %s", strerror(errno)); "Failed to fork child: %s", strerror(errno));
return; return;
/* exec child */ /* exec child */
@ -212,9 +215,9 @@ void uh_cgi_request(
fd_cloexec(wfd[0]); fd_cloexec(wfd[0]);
/* check for regular, world-executable file _or_ interpreter */ /* check for regular, world-executable file _or_ interpreter */
if( ((pi->stat.st_mode & S_IFREG) && if (((pi->stat.st_mode & S_IFREG) &&
(pi->stat.st_mode & S_IXOTH)) || (ip != NULL) (pi->stat.st_mode & S_IXOTH)) || (ip != NULL))
) { {
/* build environment */ /* build environment */
clearenv(); clearenv();
@ -225,7 +228,7 @@ void uh_cgi_request(
#ifdef HAVE_TLS #ifdef HAVE_TLS
/* https? */ /* https? */
if( cl->tls ) if (cl->tls)
setenv("HTTPS", "on", 1); setenv("HTTPS", "on", 1);
#endif #endif
@ -243,11 +246,11 @@ void uh_cgi_request(
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);
/* REDIRECT_STATUS, php-cgi wants it */ /* REDIRECT_STATUS, php-cgi wants it */
switch( req->redirect_status ) switch (req->redirect_status)
{ {
case 404: case 404:
setenv("REDIRECT_STATUS", "404", 1); setenv("REDIRECT_STATUS", "404", 1);
@ -259,13 +262,13 @@ void uh_cgi_request(
} }
/* 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 else
setenv("SERVER_PROTOCOL", "HTTP/1.0", 1); setenv("SERVER_PROTOCOL", "HTTP/1.0", 1);
/* request method */ /* request method */
switch( req->method ) switch (req->method)
{ {
case UH_HTTP_MSG_GET: case UH_HTTP_MSG_GET:
setenv("REQUEST_METHOD", "GET", 1); setenv("REQUEST_METHOD", "GET", 1);
@ -284,75 +287,71 @@ void uh_cgi_request(
setenv("REQUEST_URI", req->url, 1); setenv("REQUEST_URI", req->url, 1);
/* remote user */ /* remote user */
if( req->realm ) if (req->realm)
setenv("REMOTE_USER", req->realm->user, 1); setenv("REMOTE_USER", req->realm->user, 1);
/* request message headers */ /* request message headers */
foreach_header(i, req->headers) foreach_header(i, req->headers)
{ {
if( ! strcasecmp(req->headers[i], "Accept") ) if (!strcasecmp(req->headers[i], "Accept"))
setenv("HTTP_ACCEPT", req->headers[i+1], 1); setenv("HTTP_ACCEPT", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Accept-Charset") ) else if (!strcasecmp(req->headers[i], "Accept-Charset"))
setenv("HTTP_ACCEPT_CHARSET", req->headers[i+1], 1); setenv("HTTP_ACCEPT_CHARSET", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Accept-Encoding") ) else if (!strcasecmp(req->headers[i], "Accept-Encoding"))
setenv("HTTP_ACCEPT_ENCODING", req->headers[i+1], 1); setenv("HTTP_ACCEPT_ENCODING", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Accept-Language") ) else if (!strcasecmp(req->headers[i], "Accept-Language"))
setenv("HTTP_ACCEPT_LANGUAGE", req->headers[i+1], 1); setenv("HTTP_ACCEPT_LANGUAGE", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Authorization") ) else if (!strcasecmp(req->headers[i], "Authorization"))
setenv("HTTP_AUTHORIZATION", req->headers[i+1], 1); setenv("HTTP_AUTHORIZATION", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Connection") ) else if (!strcasecmp(req->headers[i], "Connection"))
setenv("HTTP_CONNECTION", req->headers[i+1], 1); setenv("HTTP_CONNECTION", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Cookie") ) else if (!strcasecmp(req->headers[i], "Cookie"))
setenv("HTTP_COOKIE", req->headers[i+1], 1); setenv("HTTP_COOKIE", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Host") ) else if (!strcasecmp(req->headers[i], "Host"))
setenv("HTTP_HOST", req->headers[i+1], 1); setenv("HTTP_HOST", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Referer") ) else if (!strcasecmp(req->headers[i], "Referer"))
setenv("HTTP_REFERER", req->headers[i+1], 1); setenv("HTTP_REFERER", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "User-Agent") ) else if (!strcasecmp(req->headers[i], "User-Agent"))
setenv("HTTP_USER_AGENT", req->headers[i+1], 1); setenv("HTTP_USER_AGENT", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Content-Type") ) else if (!strcasecmp(req->headers[i], "Content-Type"))
setenv("CONTENT_TYPE", req->headers[i+1], 1); setenv("CONTENT_TYPE", req->headers[i+1], 1);
else if( ! strcasecmp(req->headers[i], "Content-Length") ) else if (!strcasecmp(req->headers[i], "Content-Length"))
setenv("CONTENT_LENGTH", req->headers[i+1], 1); setenv("CONTENT_LENGTH", req->headers[i+1], 1);
} }
/* execute child code ... */ /* execute child code ... */
if( chdir(pi->root) ) if (chdir(pi->root))
perror("chdir()"); perror("chdir()");
if( ip != NULL ) if (ip != NULL)
execl(ip->path, ip->path, pi->phys, NULL); execl(ip->path, ip->path, pi->phys, NULL);
else else
execl(pi->phys, pi->phys, NULL); execl(pi->phys, pi->phys, NULL);
/* in case it fails ... */ /* in case it fails ... */
printf( printf("Status: 500 Internal Server Error\r\n\r\n"
"Status: 500 Internal Server Error\r\n\r\n" "Unable to launch the requested CGI program:\n"
"Unable to launch the requested CGI program:\n" " %s: %s\n",
" %s: %s\n", ip ? ip->path : pi->phys, strerror(errno));
ip ? ip->path : pi->phys, strerror(errno)
);
} }
/* 403 */ /* 403 */
else else
{ {
printf( printf("Status: 403 Forbidden\r\n\r\n"
"Status: 403 Forbidden\r\n\r\n" "Access to this resource is forbidden\n");
"Access to this resource is forbidden\n"
);
} }
close(wfd[0]); close(wfd[0]);
@ -371,11 +370,11 @@ void uh_cgi_request(
fd_max = max(rfd[0], wfd[1]) + 1; fd_max = max(rfd[0], wfd[1]) + 1;
/* find content length */ /* find content length */
if( req->method == UH_HTTP_MSG_POST ) if (req->method == UH_HTTP_MSG_POST)
{ {
foreach_header(i, req->headers) foreach_header(i, req->headers)
{ {
if( ! strcasecmp(req->headers[i], "Content-Length") ) if (!strcasecmp(req->headers[i], "Content-Length"))
{ {
content_length = atoi(req->headers[i+1]); content_length = atoi(req->headers[i+1]);
break; break;
@ -387,7 +386,7 @@ void uh_cgi_request(
memset(hdr, 0, sizeof(hdr)); memset(hdr, 0, sizeof(hdr));
/* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */ /* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */
while( 1 ) while (1)
{ {
FD_ZERO(&reader); FD_ZERO(&reader);
FD_ZERO(&writer); FD_ZERO(&writer);
@ -399,31 +398,33 @@ void uh_cgi_request(
timeout.tv_usec = 0; timeout.tv_usec = 0;
ensure_out(rv = select_intr(fd_max, &reader, ensure_out(rv = select_intr(fd_max, &reader,
(content_length > -1) ? &writer : NULL, NULL, &timeout)); (content_length > -1)
? &writer : NULL,
NULL, &timeout));
/* timeout */ /* timeout */
if( rv == 0 ) if (rv == 0)
{ {
ensure_out(kill(child, 0)); ensure_out(kill(child, 0));
} }
/* wait until we can read or write or both */ /* wait until we can read or write or both */
else if( rv > 0 ) else if (rv > 0)
{ {
/* ready to write to cgi program */ /* ready to write to cgi program */
if( FD_ISSET(wfd[1], &writer) ) if (FD_ISSET(wfd[1], &writer))
{ {
/* there is unread post data waiting */ /* there is unread post data waiting */
if( content_length > 0 ) if (content_length > 0)
{ {
/* read it from socket ... */ /* read it from socket ... */
ensure_out(buflen = uh_tcp_recv(cl, buf, ensure_out(buflen = uh_tcp_recv(cl, buf,
min(content_length, sizeof(buf)))); min(content_length, sizeof(buf))));
if( buflen > 0 ) if (buflen > 0)
{ {
/* ... and write it to child's stdin */ /* ... and write it to child's stdin */
if( write(wfd[1], buf, buflen) < 0 ) if (write(wfd[1], buf, buflen) < 0)
perror("write()"); perror("write()");
content_length -= buflen; content_length -= buflen;
@ -432,7 +433,7 @@ void uh_cgi_request(
/* unexpected eof! */ /* unexpected eof! */
else else
{ {
if( write(wfd[1], "", 0) < 0 ) if (write(wfd[1], "", 0) < 0)
perror("write()"); perror("write()");
content_length = 0; content_length = 0;
@ -440,7 +441,7 @@ void uh_cgi_request(
} }
/* there is no more post data, close pipe to child's stdin */ /* there is no more post data, close pipe to child's stdin */
else if( content_length > -1 ) else if (content_length > -1)
{ {
close(wfd[1]); close(wfd[1]);
content_length = -1; content_length = -1;
@ -448,16 +449,16 @@ void uh_cgi_request(
} }
/* ready to read from cgi program */ /* ready to read from cgi program */
if( FD_ISSET(rfd[0], &reader) ) if (FD_ISSET(rfd[0], &reader))
{ {
/* read data from child ... */ /* read data from child ... */
if( (buflen = read(rfd[0], buf, sizeof(buf))) > 0 ) if ((buflen = read(rfd[0], buf, sizeof(buf))) > 0)
{ {
/* we have not pushed out headers yet, parse input */ /* we have not pushed out headers yet, parse input */
if( ! header_sent ) if (!header_sent)
{ {
/* head buffer not full and no end yet */ /* head buffer not full and no end yet */
if( hdrlen < sizeof(hdr) ) if (hdrlen < sizeof(hdr))
{ {
bufoff = min(buflen, sizeof(hdr) - hdrlen); bufoff = min(buflen, sizeof(hdr) - hdrlen);
memcpy(&hdr[hdrlen], buf, bufoff); memcpy(&hdr[hdrlen], buf, bufoff);
@ -470,7 +471,7 @@ void uh_cgi_request(
/* try to parse header ... */ /* try to parse header ... */
if( (res = uh_cgi_header_parse(hdr, hdrlen, &hdroff)) != NULL ) if ((res = uh_cgi_header_parse(hdr, hdrlen, &hdroff)) != NULL)
{ {
/* write status */ /* write status */
ensure_out(uh_http_sendf(cl, NULL, ensure_out(uh_http_sendf(cl, NULL,
@ -506,12 +507,12 @@ void uh_cgi_request(
ensure_out(uh_http_send(cl, NULL, "\r\n", -1)); ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
/* push out remaining head buffer */ /* push out remaining head buffer */
if( hdroff < hdrlen ) if (hdroff < hdrlen)
ensure_out(uh_http_send(cl, req, &hdr[hdroff], hdrlen - hdroff)); ensure_out(uh_http_send(cl, req, &hdr[hdroff], hdrlen - hdroff));
} }
/* ... failed and head buffer exceeded */ /* ... failed and head buffer exceeded */
else if( hdrlen >= sizeof(hdr) ) else if (hdrlen >= sizeof(hdr))
{ {
ensure_out(uh_cgi_error_500(cl, req, ensure_out(uh_cgi_error_500(cl, req,
"The CGI program generated an invalid response:\n\n")); "The CGI program generated an invalid response:\n\n"));
@ -526,7 +527,7 @@ void uh_cgi_request(
} }
/* push out remaining read buffer */ /* push out remaining read buffer */
if( bufoff < buflen ) if (bufoff < buflen)
ensure_out(uh_http_send(cl, req, &buf[bufoff], buflen - bufoff)); ensure_out(uh_http_send(cl, req, &buf[bufoff], buflen - bufoff));
header_sent = 1; header_sent = 1;
@ -542,7 +543,7 @@ void uh_cgi_request(
else else
{ {
/* cgi script did not output useful stuff at all */ /* cgi script did not output useful stuff at all */
if( ! header_sent ) if (!header_sent)
{ {
/* I would do this ... /* I would do this ...
* *
@ -576,7 +577,7 @@ void uh_cgi_request(
/* timeout exceeded or interrupted by SIGCHLD */ /* timeout exceeded or interrupted by SIGCHLD */
else else
{ {
if( (errno != EINTR) && ! header_sent ) if ((errno != EINTR) && ! header_sent)
{ {
ensure_out(uh_http_sendhf(cl, 504, "Gateway Timeout", ensure_out(uh_http_sendhf(cl, 504, "Gateway Timeout",
"The CGI script took too long to produce " "The CGI script took too long to produce "
@ -594,7 +595,7 @@ void uh_cgi_request(
close(rfd[0]); close(rfd[0]);
close(wfd[1]); close(wfd[1]);
if( !kill(child, 0) ) if (!kill(child, 0))
{ {
kill(child, SIGTERM); kill(child, SIGTERM);
waitpid(child, NULL, 0); waitpid(child, NULL, 0);
@ -603,4 +604,3 @@ void uh_cgi_request(
break; break;
} }
} }

View file

@ -31,13 +31,13 @@ static const char * uh_file_mime_lookup(const char *path)
struct mimetype *m = &uh_mime_types[0]; struct mimetype *m = &uh_mime_types[0];
const char *e; const char *e;
while( m->extn ) while (m->extn)
{ {
e = &path[strlen(path)-1]; e = &path[strlen(path)-1];
while( e >= path ) while (e >= path)
{ {
if( (*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn) ) if ((*e == '.' || *e == '/') && !strcasecmp(&e[1], m->extn))
return m->mime; return m->mime;
e--; e--;
@ -54,10 +54,9 @@ static const char * uh_file_mktag(struct stat *s)
static char tag[128]; static char tag[128];
snprintf(tag, sizeof(tag), "\"%x-%x-%x\"", snprintf(tag, sizeof(tag), "\"%x-%x-%x\"",
(unsigned int) s->st_ino, (unsigned int) s->st_ino,
(unsigned int) s->st_size, (unsigned int) s->st_size,
(unsigned int) s->st_mtime (unsigned int) s->st_mtime);
);
return tag; return tag;
} }
@ -68,7 +67,7 @@ static time_t uh_file_date2unix(const char *date)
memset(&t, 0, sizeof(t)); memset(&t, 0, sizeof(t));
if( strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) != NULL ) if (strptime(date, "%a, %d %b %Y %H:%M:%S %Z", &t) != NULL)
return timegm(&t); return timegm(&t);
return 0; return 0;
@ -90,7 +89,7 @@ static char * uh_file_header_lookup(struct http_request *req, const char *name)
foreach_header(i, req->headers) foreach_header(i, req->headers)
{ {
if( ! strcasecmp(req->headers[i], name) ) if (!strcasecmp(req->headers[i], name))
return req->headers[i+1]; return req->headers[i+1];
} }
@ -98,26 +97,30 @@ static char * uh_file_header_lookup(struct http_request *req, const char *name)
} }
static int 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")); ensure_ret(uh_http_sendf(cl, NULL, "Connection: close\r\n"));
if( s ) if (s)
{ {
ensure_ret(uh_http_sendf(cl, NULL, "ETag: %s\r\n", uh_file_mktag(s))); ensure_ret(uh_http_sendf(cl, NULL, "ETag: %s\r\n", uh_file_mktag(s)));
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, "Last-Modified: %s\r\n",
uh_file_unix2date(s->st_mtime)));
} }
return 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 int 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)); ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 200 OK\r\n", req->version));
return uh_file_response_ok_hdrs(cl, req, s); return uh_file_response_ok_hdrs(cl, req, s);
} }
static int 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)); ensure_ret(uh_http_sendf(cl, NULL, "HTTP/%.1f 304 Not Modified\r\n", req->version));
return uh_file_response_ok_hdrs(cl, req, s); return uh_file_response_ok_hdrs(cl, req, s);
@ -130,25 +133,26 @@ static int uh_file_response_412(struct client *cl, struct http_request *req)
"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, int *ok) static int uh_file_if_match(struct client *cl, struct http_request *req,
struct stat *s, int *ok)
{ {
const char *tag = uh_file_mktag(s); const char *tag = uh_file_mktag(s);
char *hdr = uh_file_header_lookup(req, "If-Match"); char *hdr = uh_file_header_lookup(req, "If-Match");
char *p; char *p;
int i; int i;
if( hdr ) if (hdr)
{ {
p = &hdr[0]; p = &hdr[0];
for( i = 0; i < strlen(hdr); i++ ) for (i = 0; i < strlen(hdr); i++)
{ {
if( (hdr[i] == ' ') || (hdr[i] == ',') ) if ((hdr[i] == ' ') || (hdr[i] == ','))
{ {
hdr[i++] = 0; hdr[i++] = 0;
p = &hdr[i]; p = &hdr[i];
} }
else if( !strcmp(p, "*") || !strcmp(p, tag) ) else if (!strcmp(p, "*") || !strcmp(p, tag))
{ {
*ok = 1; *ok = 1;
return *ok; return *ok;
@ -164,14 +168,16 @@ static int uh_file_if_match(struct client *cl, struct http_request *req, struct
return *ok; return *ok;
} }
static int uh_file_if_modified_since(struct client *cl, struct http_request *req, struct stat *s, int *ok) static int uh_file_if_modified_since(struct client *cl,
struct http_request *req, struct stat *s,
int *ok)
{ {
char *hdr = uh_file_header_lookup(req, "If-Modified-Since"); char *hdr = uh_file_header_lookup(req, "If-Modified-Since");
*ok = 1; *ok = 1;
if( hdr ) if (hdr)
{ {
if( uh_file_date2unix(hdr) >= s->st_mtime ) if (uh_file_date2unix(hdr) >= s->st_mtime)
{ {
*ok = 0; *ok = 0;
ensure_ret(uh_file_response_304(cl, req, s)); ensure_ret(uh_file_response_304(cl, req, s));
@ -181,7 +187,8 @@ static int uh_file_if_modified_since(struct client *cl, struct http_request *req
return *ok; return *ok;
} }
static int uh_file_if_none_match(struct client *cl, struct http_request *req, struct stat *s, int *ok) static int uh_file_if_none_match(struct client *cl, struct http_request *req,
struct stat *s, int *ok)
{ {
const char *tag = uh_file_mktag(s); const char *tag = uh_file_mktag(s);
char *hdr = uh_file_header_lookup(req, "If-None-Match"); char *hdr = uh_file_header_lookup(req, "If-None-Match");
@ -189,26 +196,30 @@ static int uh_file_if_none_match(struct client *cl, struct http_request *req, st
int i; int i;
*ok = 1; *ok = 1;
if( hdr ) if (hdr)
{ {
p = &hdr[0]; p = &hdr[0];
for( i = 0; i < strlen(hdr); i++ ) for (i = 0; i < strlen(hdr); i++)
{ {
if( (hdr[i] == ' ') || (hdr[i] == ',') ) if ((hdr[i] == ' ') || (hdr[i] == ','))
{ {
hdr[i++] = 0; hdr[i++] = 0;
p = &hdr[i]; p = &hdr[i];
} }
else if( !strcmp(p, "*") || !strcmp(p, tag) ) else if (!strcmp(p, "*") || !strcmp(p, tag))
{ {
*ok = 0; *ok = 0;
if( (req->method == UH_HTTP_MSG_GET) || if ((req->method == UH_HTTP_MSG_GET) ||
(req->method == UH_HTTP_MSG_HEAD) ) (req->method == UH_HTTP_MSG_HEAD))
{
ensure_ret(uh_file_response_304(cl, req, s)); ensure_ret(uh_file_response_304(cl, req, s));
}
else else
{
ensure_ret(uh_file_response_412(cl, req)); ensure_ret(uh_file_response_412(cl, req));
}
break; break;
} }
@ -218,12 +229,13 @@ static int uh_file_if_none_match(struct client *cl, struct http_request *req, st
return *ok; return *ok;
} }
static int uh_file_if_range(struct client *cl, struct http_request *req, struct stat *s, int *ok) static int uh_file_if_range(struct client *cl, struct http_request *req,
struct stat *s, int *ok)
{ {
char *hdr = uh_file_header_lookup(req, "If-Range"); char *hdr = uh_file_header_lookup(req, "If-Range");
*ok = 1; *ok = 1;
if( hdr ) if (hdr)
{ {
*ok = 0; *ok = 0;
ensure_ret(uh_file_response_412(cl, req)); ensure_ret(uh_file_response_412(cl, req));
@ -232,14 +244,16 @@ static int uh_file_if_range(struct client *cl, struct http_request *req, struct
return *ok; return *ok;
} }
static int uh_file_if_unmodified_since(struct client *cl, struct http_request *req, struct stat *s, int *ok) static int uh_file_if_unmodified_since(struct client *cl,
struct http_request *req, struct stat *s,
int *ok)
{ {
char *hdr = uh_file_header_lookup(req, "If-Unmodified-Since"); char *hdr = uh_file_header_lookup(req, "If-Unmodified-Since");
*ok = 1; *ok = 1;
if( hdr ) if (hdr)
{ {
if( uh_file_date2unix(hdr) <= s->st_mtime ) if (uh_file_date2unix(hdr) <= s->st_mtime)
{ {
*ok = 0; *ok = 0;
ensure_ret(uh_file_response_412(cl, req)); ensure_ret(uh_file_response_412(cl, req));
@ -255,7 +269,8 @@ static int uh_file_scandir_filter_dir(const struct dirent *e)
return strcmp(e->d_name, ".") ? 1 : 0; return strcmp(e->d_name, ".") ? 1 : 0;
} }
static void uh_file_dirlist(struct client *cl, struct http_request *req, struct path_info *pi) static void uh_file_dirlist(struct client *cl, struct http_request *req,
struct path_info *pi)
{ {
int i; int i;
int count = 0; int count = 0;
@ -265,54 +280,60 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct
struct stat s; struct stat s;
ensure_out(uh_http_sendf(cl, req, ensure_out(uh_http_sendf(cl, req,
"<html><head><title>Index of %s</title></head>" "<html><head><title>Index of %s</title></head>"
"<body><h1>Index of %s</h1><hr /><ol>", "<body><h1>Index of %s</h1><hr /><ol>",
pi->name, pi->name pi->name, pi->name));
));
if( (count = scandir(pi->phys, &files, uh_file_scandir_filter_dir, alphasort)) > 0 ) if ((count = scandir(pi->phys, &files, uh_file_scandir_filter_dir,
alphasort)) > 0)
{ {
memset(filename, 0, sizeof(filename)); memset(filename, 0, sizeof(filename));
memcpy(filename, pi->phys, sizeof(filename)); memcpy(filename, pi->phys, sizeof(filename));
pathptr = &filename[strlen(filename)]; pathptr = &filename[strlen(filename)];
/* list subdirs */ /* list subdirs */
for( i = 0; i < count; i++ ) for (i = 0; i < count; i++)
{ {
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) && if (!stat(filename, &s) &&
(s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH) (s.st_mode & S_IFDIR) && (s.st_mode & S_IXOTH))
) {
ensure_out(uh_http_sendf(cl, req, ensure_out(uh_http_sendf(cl, req,
"<li><strong><a href='%s%s'>%s</a>/</strong><br />" "<li><strong><a href='%s%s'>%s</a>/"
"<small>modified: %s<br />directory - %.02f kbyte" "</strong><br /><small>modified: %s"
"<br /><br /></small></li>", "<br />directory - %.02f kbyte<br />"
pi->name, files[i]->d_name, files[i]->d_name, "<br /></small></li>",
uh_file_unix2date(s.st_mtime), s.st_size / 1024.0 pi->name, files[i]->d_name,
)); files[i]->d_name,
uh_file_unix2date(s.st_mtime),
s.st_size / 1024.0));
}
*pathptr = 0; *pathptr = 0;
} }
/* list files */ /* list files */
for( i = 0; i < count; i++ ) for (i = 0; i < count; i++)
{ {
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) && if (!stat(filename, &s) &&
!(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH) !(s.st_mode & S_IFDIR) && (s.st_mode & S_IROTH))
) {
ensure_out(uh_http_sendf(cl, req, ensure_out(uh_http_sendf(cl, req,
"<li><strong><a href='%s%s'>%s</a></strong><br />" "<li><strong><a href='%s%s'>%s</a>"
"<small>modified: %s<br />%s - %.02f kbyte<br />" "</strong><br /><small>modified: %s"
"<br /></small></li>", "<br />%s - %.02f kbyte<br />"
pi->name, files[i]->d_name, files[i]->d_name, "<br /></small></li>",
uh_file_unix2date(s.st_mtime), pi->name, files[i]->d_name,
uh_file_mime_lookup(filename), s.st_size / 1024.0 files[i]->d_name,
)); uh_file_unix2date(s.st_mtime),
uh_file_mime_lookup(filename),
s.st_size / 1024.0));
}
*pathptr = 0; *pathptr = 0;
} }
@ -322,9 +343,9 @@ static void uh_file_dirlist(struct client *cl, struct http_request *req, struct
ensure_out(uh_http_sendf(cl, req, "")); ensure_out(uh_http_sendf(cl, req, ""));
out: out:
if( files ) if (files)
{ {
for( i = 0; i < count; i++ ) for (i = 0; i < count; i++)
free(files[i]); free(files[i]);
free(files); free(files);
@ -340,16 +361,16 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in
char buf[UH_LIMIT_MSGHEAD]; char buf[UH_LIMIT_MSGHEAD];
/* we have a file */ /* we have a file */
if( (pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0) ) if ((pi->stat.st_mode & S_IFREG) && ((fd = open(pi->phys, O_RDONLY)) > 0))
{ {
/* test preconditions */ /* test preconditions */
if(ok) ensure_out(uh_file_if_modified_since(cl, req, &pi->stat, &ok)); if (ok) ensure_out(uh_file_if_modified_since(cl, req, &pi->stat, &ok));
if(ok) ensure_out(uh_file_if_match(cl, req, &pi->stat, &ok)); if (ok) ensure_out(uh_file_if_match(cl, req, &pi->stat, &ok));
if(ok) ensure_out(uh_file_if_range(cl, req, &pi->stat, &ok)); if (ok) ensure_out(uh_file_if_range(cl, req, &pi->stat, &ok));
if(ok) ensure_out(uh_file_if_unmodified_since(cl, req, &pi->stat, &ok)); if (ok) ensure_out(uh_file_if_unmodified_since(cl, req, &pi->stat, &ok));
if(ok) ensure_out(uh_file_if_none_match(cl, req, &pi->stat, &ok)); if (ok) ensure_out(uh_file_if_none_match(cl, req, &pi->stat, &ok));
if( ok > 0 ) if (ok > 0)
{ {
/* write status */ /* write status */
ensure_out(uh_file_response_200(cl, req, &pi->stat)); ensure_out(uh_file_response_200(cl, req, &pi->stat));
@ -358,17 +379,17 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in
ensure_out(uh_http_sendf(cl, NULL, "Content-Length: %i\r\n", pi->stat.st_size)); ensure_out(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) && (req->method != UH_HTTP_MSG_HEAD) ) if ((req->version > 1.0) && (req->method != UH_HTTP_MSG_HEAD))
ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1));
/* close header */ /* close header */
ensure_out(uh_http_send(cl, NULL, "\r\n", -1)); ensure_out(uh_http_send(cl, NULL, "\r\n", -1));
/* send body */ /* send body */
if( req->method != UH_HTTP_MSG_HEAD ) 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)
ensure_out(uh_http_send(cl, req, buf, rlen)); ensure_out(uh_http_send(cl, req, buf, rlen));
/* send trailer in chunked mode */ /* send trailer in chunked mode */
@ -384,12 +405,12 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in
} }
/* directory */ /* directory */
else if( (pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists ) else if ((pi->stat.st_mode & S_IFDIR) && !cl->server->conf->no_dirlists)
{ {
/* write status */ /* write status */
ensure_out(uh_file_response_200(cl, req, NULL)); ensure_out(uh_file_response_200(cl, req, NULL));
if( req->version > 1.0 ) if (req->version > 1.0)
ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1)); ensure_out(uh_http_send(cl, NULL, "Transfer-Encoding: chunked\r\n", -1));
ensure_out(uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1)); ensure_out(uh_http_send(cl, NULL, "Content-Type: text/html\r\n\r\n", -1));
@ -406,7 +427,6 @@ void uh_file_request(struct client *cl, struct http_request *req, struct path_in
} }
out: out:
if( fd > -1 ) if (fd > -1)
close(fd); close(fd);
} }

View file

@ -31,7 +31,7 @@ static int uh_lua_recv(lua_State *L)
length = luaL_checknumber(L, 1); length = luaL_checknumber(L, 1);
if( (length > 0) && (length <= sizeof(buffer)) ) if ((length > 0) && (length <= sizeof(buffer)))
{ {
FD_ZERO(&reader); FD_ZERO(&reader);
FD_SET(fileno(stdin), &reader); FD_SET(fileno(stdin), &reader);
@ -41,13 +41,13 @@ static int uh_lua_recv(lua_State *L)
timeout.tv_usec = 100000; timeout.tv_usec = 100000;
/* check whether fd is readable */ /* check whether fd is readable */
if( select(fileno(stdin) + 1, &reader, NULL, NULL, &timeout) > 0 ) if (select(fileno(stdin) + 1, &reader, NULL, NULL, &timeout) > 0)
{ {
/* receive data */ /* receive data */
rlen = read(fileno(stdin), buffer, length); rlen = read(fileno(stdin), buffer, length);
lua_pushnumber(L, rlen); lua_pushnumber(L, rlen);
if( rlen > 0 ) if (rlen > 0)
{ {
lua_pushlstring(L, buffer, rlen); lua_pushlstring(L, buffer, rlen);
return 2; return 2;
@ -75,9 +75,9 @@ static int uh_lua_send_common(lua_State *L, int chunked)
buffer = luaL_checklstring(L, 1, &length); buffer = luaL_checklstring(L, 1, &length);
if( chunked ) if (chunked)
{ {
if( length > 0 ) if (length > 0)
{ {
snprintf(chunk, sizeof(chunk), "%X\r\n", length); snprintf(chunk, sizeof(chunk), "%X\r\n", length);
slen = write(fileno(stdout), chunk, strlen(chunk)); slen = write(fileno(stdout), chunk, strlen(chunk));
@ -117,7 +117,7 @@ static int uh_lua_str2str(lua_State *L, int (*xlate_func) (char *, int, const ch
inbuf = luaL_checklstring(L, 1, &inlen); inbuf = luaL_checklstring(L, 1, &inlen);
outlen = (* xlate_func)(outbuf, sizeof(outbuf), inbuf, inlen); outlen = (* xlate_func)(outbuf, sizeof(outbuf), inbuf, inlen);
if( outlen < 0 ) if (outlen < 0)
luaL_error( L, "%s on URL-encode codec", luaL_error( L, "%s on URL-encode codec",
(outlen==-1) ? "buffer overflow" : "malformed string" ); (outlen==-1) ? "buffer overflow" : "malformed string" );
@ -177,7 +177,7 @@ lua_State * uh_lua_init(const struct config *conf)
/* load Lua handler */ /* load Lua handler */
switch( luaL_loadfile(L, conf->lua_handler) ) switch (luaL_loadfile(L, conf->lua_handler))
{ {
case LUA_ERRSYNTAX: case LUA_ERRSYNTAX:
fprintf(stderr, fprintf(stderr,
@ -196,7 +196,7 @@ lua_State * uh_lua_init(const struct config *conf)
default: default:
/* compile Lua handler */ /* compile Lua handler */
switch( lua_pcall(L, 0, 0, 0) ) switch (lua_pcall(L, 0, 0, 0))
{ {
case LUA_ERRRUN: case LUA_ERRRUN:
err_str = luaL_checkstring(L, -1); err_str = luaL_checkstring(L, -1);
@ -218,7 +218,7 @@ lua_State * uh_lua_init(const struct config *conf)
/* test handler function */ /* test handler function */
lua_getglobal(L, UH_LUA_CALLBACK); lua_getglobal(L, UH_LUA_CALLBACK);
if( ! lua_isfunction(L, -1) ) if (! lua_isfunction(L, -1))
{ {
fprintf(stderr, fprintf(stderr,
"Lua handler provides no " UH_LUA_CALLBACK "(), unable to continue\n"); "Lua handler provides no " UH_LUA_CALLBACK "(), unable to continue\n");
@ -260,21 +260,21 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
/* spawn pipes for me->child, child->me */ /* spawn pipes for me->child, child->me */
if( (pipe(rfd) < 0) || (pipe(wfd) < 0) ) if ((pipe(rfd) < 0) || (pipe(wfd) < 0))
{ {
uh_http_sendhf(cl, 500, "Internal Server Error", uh_http_sendhf(cl, 500, "Internal Server Error",
"Failed to create pipe: %s", strerror(errno)); "Failed to create pipe: %s", strerror(errno));
if( rfd[0] > 0 ) close(rfd[0]); if (rfd[0] > 0) close(rfd[0]);
if( rfd[1] > 0 ) close(rfd[1]); if (rfd[1] > 0) close(rfd[1]);
if( wfd[0] > 0 ) close(wfd[0]); if (wfd[0] > 0) close(wfd[0]);
if( wfd[1] > 0 ) close(wfd[1]); if (wfd[1] > 0) close(wfd[1]);
return; return;
} }
switch( (child = fork()) ) switch ((child = fork()))
{ {
case -1: case -1:
uh_http_sendhf(cl, 500, "Internal Server Error", uh_http_sendhf(cl, 500, "Internal Server Error",
@ -329,12 +329,12 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
lua_setfield(L, -2, "SCRIPT_NAME"); lua_setfield(L, -2, "SCRIPT_NAME");
/* query string, path info */ /* query string, path info */
if( (query_string = strchr(req->url, '?')) != NULL ) if ((query_string = strchr(req->url, '?')) != NULL)
{ {
lua_pushstring(L, query_string + 1); lua_pushstring(L, query_string + 1);
lua_setfield(L, -2, "QUERY_STRING"); lua_setfield(L, -2, "QUERY_STRING");
if( (int)(query_string - req->url) > strlen(prefix) ) if ((int)(query_string - req->url) > strlen(prefix))
{ {
lua_pushlstring(L, lua_pushlstring(L,
&req->url[strlen(prefix)], &req->url[strlen(prefix)],
@ -344,7 +344,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
lua_setfield(L, -2, "PATH_INFO"); lua_setfield(L, -2, "PATH_INFO");
} }
} }
else if( strlen(req->url) > strlen(prefix) ) else if (strlen(req->url) > strlen(prefix))
{ {
lua_pushstring(L, &req->url[strlen(prefix)]); lua_pushstring(L, &req->url[strlen(prefix)]);
lua_setfield(L, -2, "PATH_INFO"); lua_setfield(L, -2, "PATH_INFO");
@ -354,7 +354,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
lua_pushnumber(L, floor(req->version * 10) / 10); lua_pushnumber(L, floor(req->version * 10) / 10);
lua_setfield(L, -2, "HTTP_VERSION"); lua_setfield(L, -2, "HTTP_VERSION");
if( req->version > 1.0 ) if (req->version > 1.0)
lua_pushstring(L, "HTTP/1.1"); lua_pushstring(L, "HTTP/1.1");
else else
lua_pushstring(L, "HTTP/1.0"); lua_pushstring(L, "HTTP/1.0");
@ -378,12 +378,12 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
/* essential env vars */ /* essential env vars */
foreach_header(i, req->headers) foreach_header(i, req->headers)
{ {
if( !strcasecmp(req->headers[i], "Content-Length") ) if (!strcasecmp(req->headers[i], "Content-Length"))
{ {
lua_pushnumber(L, atoi(req->headers[i+1])); lua_pushnumber(L, atoi(req->headers[i+1]));
lua_setfield(L, -2, "CONTENT_LENGTH"); lua_setfield(L, -2, "CONTENT_LENGTH");
} }
else if( !strcasecmp(req->headers[i], "Content-Type") ) else if (!strcasecmp(req->headers[i], "Content-Type"))
{ {
lua_pushstring(L, req->headers[i+1]); lua_pushstring(L, req->headers[i+1]);
lua_setfield(L, -2, "CONTENT_TYPE"); lua_setfield(L, -2, "CONTENT_TYPE");
@ -407,13 +407,13 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
/* call */ /* call */
switch( lua_pcall(L, 1, 0, 0) ) switch (lua_pcall(L, 1, 0, 0))
{ {
case LUA_ERRMEM: case LUA_ERRMEM:
case LUA_ERRRUN: case LUA_ERRRUN:
err_str = luaL_checkstring(L, -1); err_str = luaL_checkstring(L, -1);
if( ! err_str ) if (! err_str)
err_str = "Unknown error"; err_str = "Unknown error";
printf( printf(
@ -447,11 +447,11 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
fd_max = max(rfd[0], wfd[1]) + 1; fd_max = max(rfd[0], wfd[1]) + 1;
/* find content length */ /* find content length */
if( req->method == UH_HTTP_MSG_POST ) if (req->method == UH_HTTP_MSG_POST)
{ {
foreach_header(i, req->headers) foreach_header(i, req->headers)
{ {
if( ! strcasecmp(req->headers[i], "Content-Length") ) if (! strcasecmp(req->headers[i], "Content-Length"))
{ {
content_length = atoi(req->headers[i+1]); content_length = atoi(req->headers[i+1]);
break; break;
@ -461,7 +461,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
#define ensure(x) \ #define ensure(x) \
do { if( x < 0 ) goto out; } while(0) do { if (x < 0) goto out; } while(0)
data_sent = 0; data_sent = 0;
@ -469,7 +469,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
timeout.tv_usec = 0; timeout.tv_usec = 0;
/* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */ /* I/O loop, watch our pipe ends and dispatch child reads/writes from/to socket */
while( 1 ) while (1)
{ {
FD_ZERO(&reader); FD_ZERO(&reader);
FD_ZERO(&writer); FD_ZERO(&writer);
@ -478,21 +478,22 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
FD_SET(wfd[1], &writer); FD_SET(wfd[1], &writer);
/* wait until we can read or write or both */ /* wait until we can read or write or both */
if( select_intr(fd_max, &reader, if (select_intr(fd_max, &reader,
(content_length > -1) ? &writer : NULL, NULL, (content_length > -1) ? &writer : NULL,
(data_sent < 1) ? &timeout : NULL) > 0 NULL,
) { (data_sent < 1) ? &timeout : NULL) > 0)
{
/* ready to write to Lua child */ /* ready to write to Lua child */
if( FD_ISSET(wfd[1], &writer) ) if (FD_ISSET(wfd[1], &writer))
{ {
/* there is unread post data waiting */ /* there is unread post data waiting */
if( content_length > 0 ) if (content_length > 0)
{ {
/* read it from socket ... */ /* read it from socket ... */
if( (buflen = uh_tcp_recv(cl, buf, min(content_length, sizeof(buf)))) > 0 ) if ((buflen = uh_tcp_recv(cl, buf, min(content_length, sizeof(buf)))) > 0)
{ {
/* ... and write it to child's stdin */ /* ... and write it to child's stdin */
if( write(wfd[1], buf, buflen) < 0 ) if (write(wfd[1], buf, buflen) < 0)
perror("write()"); perror("write()");
content_length -= buflen; content_length -= buflen;
@ -501,7 +502,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
/* unexpected eof! */ /* unexpected eof! */
else else
{ {
if( write(wfd[1], "", 0) < 0 ) if (write(wfd[1], "", 0) < 0)
perror("write()"); perror("write()");
content_length = 0; content_length = 0;
@ -509,7 +510,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
} }
/* there is no more post data, close pipe to child's stdin */ /* there is no more post data, close pipe to child's stdin */
else if( content_length > -1 ) else if (content_length > -1)
{ {
close(wfd[1]); close(wfd[1]);
content_length = -1; content_length = -1;
@ -517,10 +518,10 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
} }
/* ready to read from Lua child */ /* ready to read from Lua child */
if( FD_ISSET(rfd[0], &reader) ) if (FD_ISSET(rfd[0], &reader))
{ {
/* read data from child ... */ /* read data from child ... */
if( (buflen = read(rfd[0], buf, sizeof(buf))) > 0 ) if ((buflen = read(rfd[0], buf, sizeof(buf))) > 0)
{ {
/* pass through buffer to socket */ /* pass through buffer to socket */
ensure(uh_tcp_send(cl, buf, buflen)); ensure(uh_tcp_send(cl, buf, buflen));
@ -531,7 +532,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
else else
{ {
/* error? */ /* error? */
if( ! data_sent ) if (!data_sent)
uh_http_sendhf(cl, 500, "Internal Server Error", uh_http_sendhf(cl, 500, "Internal Server Error",
"The Lua child did not produce any response"); "The Lua child did not produce any response");
@ -543,7 +544,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
/* timeout exceeded or interrupted by SIGCHLD */ /* timeout exceeded or interrupted by SIGCHLD */
else else
{ {
if( (errno != EINTR) && ! data_sent ) if ((errno != EINTR) && ! data_sent)
{ {
ensure(uh_http_sendhf(cl, 504, "Gateway Timeout", ensure(uh_http_sendhf(cl, 504, "Gateway Timeout",
"The Lua script took too long to produce " "The Lua script took too long to produce "
@ -558,7 +559,7 @@ void uh_lua_request(struct client *cl, struct http_request *req, lua_State *L)
close(rfd[0]); close(rfd[0]);
close(wfd[1]); close(wfd[1]);
if( !kill(child, 0) ) if (!kill(child, 0))
{ {
kill(child, SIGTERM); kill(child, SIGTERM);
waitpid(child, NULL, 0); waitpid(child, NULL, 0);

View file

@ -41,7 +41,7 @@ const char * sa_straddr(void *sa)
struct sockaddr_in *v4 = (struct sockaddr_in *)sa; struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)sa; struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)sa;
if( v4->sin_family == AF_INET ) if (v4->sin_family == AF_INET)
return inet_ntop(AF_INET, &(v4->sin_addr), str, sizeof(str)); return inet_ntop(AF_INET, &(v4->sin_addr), str, sizeof(str));
else else
return inet_ntop(AF_INET6, &(v6->sin6_addr), str, sizeof(str)); return inet_ntop(AF_INET6, &(v6->sin6_addr), str, sizeof(str));
@ -64,7 +64,7 @@ int sa_rfc1918(void *sa)
struct sockaddr_in *v4 = (struct sockaddr_in *)sa; struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
unsigned long a = htonl(v4->sin_addr.s_addr); unsigned long a = htonl(v4->sin_addr.s_addr);
if( v4->sin_family == AF_INET ) if (v4->sin_family == AF_INET)
{ {
return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) || return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) ||
((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) || ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) ||
@ -80,22 +80,22 @@ char *strfind(char *haystack, int hslen, const char *needle, int ndlen)
int match = 0; int match = 0;
int i, j; int i, j;
for( i = 0; i < hslen; i++ ) for (i = 0; i < hslen; i++)
{ {
if( haystack[i] == needle[0] ) if (haystack[i] == needle[0])
{ {
match = ((ndlen == 1) || ((i + ndlen) <= hslen)); match = ((ndlen == 1) || ((i + ndlen) <= hslen));
for( j = 1; (j < ndlen) && ((i + j) < hslen); j++ ) for (j = 1; (j < ndlen) && ((i + j) < hslen); j++)
{ {
if( haystack[i+j] != needle[j] ) if (haystack[i+j] != needle[j])
{ {
match = 0; match = 0;
break; break;
} }
} }
if( match ) if (match)
return &haystack[i]; return &haystack[i];
} }
} }
@ -160,7 +160,7 @@ int uh_tcp_peek(struct client *cl, char *buf, int len)
int sz = uh_tcp_recv(cl, buf, len); int sz = uh_tcp_recv(cl, buf, len);
/* store received data in peek buffer */ /* store received data in peek buffer */
if( sz > 0 ) if (sz > 0)
{ {
cl->peeklen = sz; cl->peeklen = sz;
memcpy(cl->peekbuf, buf, sz); memcpy(cl->peekbuf, buf, sz);
@ -220,7 +220,8 @@ int uh_tcp_recv(struct client *cl, char *buf, int len)
} }
int uh_http_sendhf(struct client *cl, int code, const char *summary, const char *fmt, ...) int uh_http_sendhf(struct client *cl, int code, const char *summary,
const char *fmt, ...)
{ {
va_list ap; va_list ap;
@ -253,10 +254,10 @@ int uh_http_sendc(struct client *cl, const char *data, int len)
char chunk[8]; char chunk[8];
int clen; int clen;
if( len == -1 ) if (len == -1)
len = strlen(data); len = strlen(data);
if( len > 0 ) if (len > 0)
{ {
clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len); clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
ensure_ret(uh_tcp_send(cl, chunk, clen)); ensure_ret(uh_tcp_send(cl, chunk, clen));
@ -271,9 +272,9 @@ int uh_http_sendc(struct client *cl, const char *data, int len)
return 0; return 0;
} }
int uh_http_sendf( int uh_http_sendf(struct client *cl, struct http_request *req,
struct client *cl, struct http_request *req, const char *fmt, ... const char *fmt, ...)
) { {
va_list ap; va_list ap;
char buffer[UH_LIMIT_MSGHEAD]; char buffer[UH_LIMIT_MSGHEAD];
int len; int len;
@ -282,23 +283,23 @@ int uh_http_sendf(
len = vsnprintf(buffer, sizeof(buffer), fmt, ap); len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap); va_end(ap);
if( (req != NULL) && (req->version > 1.0) ) if ((req != NULL) && (req->version > 1.0))
ensure_ret(uh_http_sendc(cl, buffer, len)); ensure_ret(uh_http_sendc(cl, buffer, len));
else if( len > 0 ) else if (len > 0)
ensure_ret(uh_tcp_send(cl, buffer, len)); ensure_ret(uh_tcp_send(cl, buffer, len));
return 0; return 0;
} }
int uh_http_send( int uh_http_send(struct client *cl, struct http_request *req,
struct client *cl, struct http_request *req, const char *buf, int len const char *buf, int len)
) { {
if( len < 0 ) if (len < 0)
len = strlen(buf); len = strlen(buf);
if( (req != NULL) && (req->version > 1.0) ) if ((req != NULL) && (req->version > 1.0))
ensure_ret(uh_http_sendc(cl, buf, len)); ensure_ret(uh_http_sendc(cl, buf, len));
else if( len > 0 ) else if (len > 0)
ensure_ret(uh_tcp_send(cl, buf, len)); ensure_ret(uh_tcp_send(cl, buf, len));
return 0; return 0;
@ -318,11 +319,11 @@ int uh_urldecode(char *buf, int blen, const char *src, int slen)
(((x) <= 'F') ? ((x) - 'A' + 10) : \ (((x) <= 'F') ? ((x) - 'A' + 10) : \
((x) - 'a' + 10))) ((x) - 'a' + 10)))
for( i = 0; (i < slen) && (len < blen); i++ ) for (i = 0; (i < slen) && (len < blen); i++)
{ {
if( src[i] == '%' ) if (src[i] == '%')
{ {
if( ((i+2) < slen) && isxdigit(src[i+1]) && isxdigit(src[i+2]) ) if (((i+2) < slen) && isxdigit(src[i+1]) && isxdigit(src[i+2]))
{ {
buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2])); buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
i += 2; i += 2;
@ -358,14 +359,14 @@ int uh_urlencode(char *buf, int blen, const char *src, int slen)
int len = 0; int len = 0;
const char hex[] = "0123456789abcdef"; const char hex[] = "0123456789abcdef";
for( i = 0; (i < slen) && (len < blen); i++ ) for (i = 0; (i < slen) && (len < blen); i++)
{ {
if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') || if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
(src[i] == '.') || (src[i] == '~') ) (src[i] == '.') || (src[i] == '~') )
{ {
buf[len++] = src[i]; buf[len++] = src[i];
} }
else if( (len+3) <= blen ) else if ((len+3) <= blen)
{ {
buf[len++] = '%'; buf[len++] = '%';
buf[len++] = hex[(src[i] >> 4) & 15]; buf[len++] = hex[(src[i] >> 4) & 15];
@ -390,30 +391,30 @@ int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen)
unsigned int cout = 0; unsigned int cout = 0;
for( i = 0; (i <= slen) && (src[i] != 0); i++ ) for (i = 0; (i <= slen) && (src[i] != 0); i++)
{ {
cin = src[i]; cin = src[i];
if( (cin >= '0') && (cin <= '9') ) if ((cin >= '0') && (cin <= '9'))
cin = cin - '0' + 52; cin = cin - '0' + 52;
else if( (cin >= 'A') && (cin <= 'Z') ) else if ((cin >= 'A') && (cin <= 'Z'))
cin = cin - 'A'; cin = cin - 'A';
else if( (cin >= 'a') && (cin <= 'z') ) else if ((cin >= 'a') && (cin <= 'z'))
cin = cin - 'a' + 26; cin = cin - 'a' + 26;
else if( cin == '+' ) else if (cin == '+')
cin = 62; cin = 62;
else if( cin == '/' ) else if (cin == '/')
cin = 63; cin = 63;
else if( cin == '=' ) else if (cin == '=')
cin = 0; cin = 0;
else else
continue; continue;
cout = (cout << 6) | cin; cout = (cout << 6) | cin;
if( (i % 4) == 3 ) if ((i % 4) == 3)
{ {
if( (len + 3) < blen ) if ((len + 3) < blen)
{ {
buf[len++] = (char)(cout >> 16); buf[len++] = (char)(cout >> 16);
buf[len++] = (char)(cout >> 8); buf[len++] = (char)(cout >> 8);
@ -440,7 +441,7 @@ static char * canonpath(const char *path, char *path_resolved)
/* relative -> absolute */ /* relative -> absolute */
if( *path != '/' ) if (*path != '/')
{ {
getcwd(path_copy, PATH_MAX); getcwd(path_copy, PATH_MAX);
strncat(path_copy, "/", PATH_MAX - strlen(path_copy)); strncat(path_copy, "/", PATH_MAX - strlen(path_copy));
@ -452,32 +453,32 @@ static char * canonpath(const char *path, char *path_resolved)
} }
/* normalize */ /* normalize */
while( (*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)) ) while ((*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)))
{ {
if( *path_cpy == '/' ) if (*path_cpy == '/')
{ {
/* skip repeating / */ /* skip repeating / */
if( path_cpy[1] == '/' ) if (path_cpy[1] == '/')
{ {
path_cpy++; path_cpy++;
continue; continue;
} }
/* /./ or /../ */ /* /./ or /../ */
else if( path_cpy[1] == '.' ) else if (path_cpy[1] == '.')
{ {
/* skip /./ */ /* skip /./ */
if( (path_cpy[2] == '/') || (path_cpy[2] == '\0') ) if ((path_cpy[2] == '/') || (path_cpy[2] == '\0'))
{ {
path_cpy += 2; path_cpy += 2;
continue; continue;
} }
/* collapse /x/../ */ /* collapse /x/../ */
else if( (path_cpy[2] == '.') && else if ((path_cpy[2] == '.') &&
((path_cpy[3] == '/') || (path_cpy[3] == '\0')) ((path_cpy[3] == '/') || (path_cpy[3] == '\0')))
) { {
while( (path_res > path_resolved) && (*--path_res != '/') ) while ((path_res > path_resolved) && (*--path_res != '/'))
; ;
path_cpy += 3; path_cpy += 3;
@ -490,15 +491,15 @@ static char * canonpath(const char *path, char *path_resolved)
} }
/* remove trailing slash if not root / */ /* remove trailing slash if not root / */
if( (path_res > (path_resolved+1)) && (path_res[-1] == '/') ) if ((path_res > (path_resolved+1)) && (path_res[-1] == '/'))
path_res--; path_res--;
else if( path_res == path_resolved ) else if (path_res == path_resolved)
*path_res++ = '/'; *path_res++ = '/';
*path_res = '\0'; *path_res = '\0';
/* test access */ /* test access */
if( !stat(path_resolved, &s) && (s.st_mode & S_IROTH) ) if (!stat(path_resolved, &s) && (s.st_mode & S_IROTH))
return path_resolved; return path_resolved;
return NULL; return NULL;
@ -523,7 +524,7 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
struct stat s; struct stat s;
/* back out early if url is undefined */ /* back out early if url is undefined */
if ( url == NULL ) if (url == NULL)
return NULL; return NULL;
memset(path_phys, 0, sizeof(path_phys)); memset(path_phys, 0, sizeof(path_phys));
@ -533,46 +534,50 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
/* copy docroot */ /* copy docroot */
memcpy(buffer, docroot, memcpy(buffer, docroot,
min(strlen(docroot), sizeof(buffer) - 1)); min(strlen(docroot), sizeof(buffer) - 1));
/* separate query string from url */ /* 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)
if ( uh_urldecode( {
&buffer[strlen(docroot)], if (uh_urldecode(&buffer[strlen(docroot)],
sizeof(buffer) - strlen(docroot) - 1, sizeof(buffer) - strlen(docroot) - 1,
url, pathptr - url ) < 0 ) url, pathptr - url ) < 0)
{
return NULL; /* bad URL */ return NULL; /* bad URL */
}
}
} }
/* no query string, decode all of url */ /* no query string, decode all of url */
else else
{ {
if ( uh_urldecode( if (uh_urldecode(&buffer[strlen(docroot)],
&buffer[strlen(docroot)], sizeof(buffer) - strlen(docroot) - 1,
sizeof(buffer) - strlen(docroot) - 1, url, strlen(url) ) < 0)
url, strlen(url) ) < 0 ) {
return NULL; /* bad URL */ return NULL; /* bad URL */
}
} }
/* create canon path */ /* create canon path */
for( i = strlen(buffer), slash = (buffer[max(0, i-1)] == '/'); i >= 0; i-- ) for (i = strlen(buffer), slash = (buffer[max(0, i-1)] == '/'); i >= 0; i--)
{ {
if( (buffer[i] == 0) || (buffer[i] == '/') ) if ((buffer[i] == 0) || (buffer[i] == '/'))
{ {
memset(path_info, 0, sizeof(path_info)); memset(path_info, 0, sizeof(path_info));
memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1)); memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
if( no_sym ? realpath(path_info, path_phys) if (no_sym ? realpath(path_info, path_phys)
: canonpath(path_info, path_phys) : canonpath(path_info, path_phys))
) { {
memset(path_info, 0, sizeof(path_info)); memset(path_info, 0, sizeof(path_info));
memcpy(path_info, &buffer[i], memcpy(path_info, &buffer[i],
min(strlen(buffer) - i, sizeof(path_info) - 1)); min(strlen(buffer) - i, sizeof(path_info) - 1));
break; break;
} }
@ -580,18 +585,18 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
} }
/* check whether found path is within docroot */ /* check whether found path is within docroot */
if( strncmp(path_phys, docroot, strlen(docroot)) || if (strncmp(path_phys, docroot, strlen(docroot)) ||
((path_phys[strlen(docroot)] != 0) && ((path_phys[strlen(docroot)] != 0) &&
(path_phys[strlen(docroot)] != '/')) (path_phys[strlen(docroot)] != '/')))
) { {
return NULL; return NULL;
} }
/* test current path */ /* test current path */
if( ! stat(path_phys, &p.stat) ) if (!stat(path_phys, &p.stat))
{ {
/* is a regular file */ /* is a regular file */
if( p.stat.st_mode & S_IFREG ) if (p.stat.st_mode & S_IFREG)
{ {
p.root = docroot; p.root = docroot;
p.phys = path_phys; p.phys = path_phys;
@ -600,10 +605,10 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
} }
/* is a directory */ /* is a directory */
else if( (p.stat.st_mode & S_IFDIR) && !strlen(path_info) ) else if ((p.stat.st_mode & S_IFDIR) && !strlen(path_info))
{ {
/* ensure trailing slash */ /* ensure trailing slash */
if( path_phys[strlen(path_phys)-1] != '/' ) if (path_phys[strlen(path_phys)-1] != '/')
path_phys[strlen(path_phys)] = '/'; path_phys[strlen(path_phys)] = '/';
/* try to locate index file */ /* try to locate index file */
@ -614,7 +619,7 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
/* if requested url resolves to a directory and a trailing slash /* if requested url resolves to a directory and a trailing slash
is missing in the request url, redirect the client to the same is missing in the request url, redirect the client to the same
url with trailing slash appended */ url with trailing slash appended */
if( !slash ) if (!slash)
{ {
uh_http_sendf(cl, NULL, uh_http_sendf(cl, NULL,
"HTTP/1.1 302 Found\r\n" "HTTP/1.1 302 Found\r\n"
@ -627,11 +632,11 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
p.redirected = 1; p.redirected = 1;
} }
else if( cl->server->conf->index_file ) else if (cl->server->conf->index_file)
{ {
strncat(buffer, cl->server->conf->index_file, 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));
@ -639,11 +644,11 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url)
} }
else else
{ {
for( i = 0; i < array_size(uh_index_files); i++ ) for (i = 0; i < array_size(uh_index_files); i++)
{ {
strncat(buffer, uh_index_files[i], sizeof(buffer)); strncat(buffer, uh_index_files[i], 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));
@ -680,31 +685,31 @@ struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
memset(new, 0, sizeof(struct auth_realm)); memset(new, 0, sizeof(struct auth_realm));
memcpy(new->path, path, memcpy(new->path, path,
min(strlen(path), sizeof(new->path) - 1)); min(strlen(path), sizeof(new->path) - 1));
memcpy(new->user, user, memcpy(new->user, user,
min(strlen(user), sizeof(new->user) - 1)); min(strlen(user), sizeof(new->user) - 1));
/* given password refers to a passwd entry */ /* given password refers to a passwd entry */
if( (strlen(pass) > 3) && !strncmp(pass, "$p$", 3) ) if ((strlen(pass) > 3) && !strncmp(pass, "$p$", 3))
{ {
#ifdef HAVE_SHADOW #ifdef HAVE_SHADOW
/* try to resolve shadow entry */ /* try to resolve shadow entry */
if( ((spwd = getspnam(&pass[3])) != NULL) && spwd->sp_pwdp ) if (((spwd = getspnam(&pass[3])) != NULL) && spwd->sp_pwdp)
{ {
memcpy(new->pass, spwd->sp_pwdp, memcpy(new->pass, spwd->sp_pwdp,
min(strlen(spwd->sp_pwdp), sizeof(new->pass) - 1)); min(strlen(spwd->sp_pwdp), sizeof(new->pass) - 1));
} }
else else
#endif #endif
/* try to resolve passwd entry */ /* try to resolve passwd entry */
if( ((pwd = getpwnam(&pass[3])) != NULL) && pwd->pw_passwd && if (((pwd = getpwnam(&pass[3])) != NULL) && pwd->pw_passwd &&
(pwd->pw_passwd[0] != '!') && (pwd->pw_passwd[0] != 0) (pwd->pw_passwd[0] != '!') && (pwd->pw_passwd[0] != 0))
) { {
memcpy(new->pass, pwd->pw_passwd, memcpy(new->pass, pwd->pw_passwd,
min(strlen(pwd->pw_passwd), sizeof(new->pass) - 1)); min(strlen(pwd->pw_passwd), sizeof(new->pass) - 1));
} }
} }
@ -715,7 +720,7 @@ struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
min(strlen(pass), sizeof(new->pass) - 1)); min(strlen(pass), sizeof(new->pass) - 1));
} }
if( new->pass[0] ) if (new->pass[0])
{ {
new->next = uh_realms; new->next = uh_realms;
uh_realms = new; uh_realms = new;
@ -729,9 +734,9 @@ struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
return NULL; return NULL;
} }
int uh_auth_check( int uh_auth_check(struct client *cl, struct http_request *req,
struct client *cl, struct http_request *req, struct path_info *pi struct path_info *pi)
) { {
int i, plen, rlen, protected; int i, plen, rlen, protected;
char buffer[UH_LIMIT_MSGHEAD]; char buffer[UH_LIMIT_MSGHEAD];
char *user = NULL; char *user = NULL;
@ -743,11 +748,11 @@ int uh_auth_check(
protected = 0; protected = 0;
/* check whether at least one realm covers the requested url */ /* check whether at least one realm covers the requested url */
for( realm = uh_realms; realm; realm = realm->next ) for (realm = uh_realms; realm; realm = realm->next)
{ {
rlen = strlen(realm->path); rlen = strlen(realm->path);
if( (plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen) ) if ((plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen))
{ {
req->realm = realm; req->realm = realm;
protected = 1; protected = 1;
@ -756,21 +761,21 @@ int uh_auth_check(
} }
/* requested resource is covered by a realm */ /* requested resource is covered by a realm */
if( protected ) if (protected)
{ {
/* try to get client auth info */ /* try to get client auth info */
foreach_header(i, req->headers) foreach_header(i, req->headers)
{ {
if( !strcasecmp(req->headers[i], "Authorization") && if (!strcasecmp(req->headers[i], "Authorization") &&
(strlen(req->headers[i+1]) > 6) && (strlen(req->headers[i+1]) > 6) &&
!strncasecmp(req->headers[i+1], "Basic ", 6) !strncasecmp(req->headers[i+1], "Basic ", 6))
) { {
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
uh_b64decode(buffer, sizeof(buffer) - 1, uh_b64decode(buffer, sizeof(buffer) - 1,
(unsigned char *) &req->headers[i+1][6], (unsigned char *) &req->headers[i+1][6],
strlen(req->headers[i+1]) - 6); strlen(req->headers[i+1]) - 6);
if( (pass = strchr(buffer, ':')) != NULL ) if ((pass = strchr(buffer, ':')) != NULL)
{ {
user = buffer; user = buffer;
*pass++ = 0; *pass++ = 0;
@ -781,24 +786,24 @@ int uh_auth_check(
} }
/* have client auth */ /* have client auth */
if( user && pass ) if (user && pass)
{ {
/* find matching realm */ /* find matching realm */
for( realm = uh_realms; realm; realm = realm->next ) for (realm = uh_realms; realm; realm = realm->next)
{ {
rlen = strlen(realm->path); rlen = strlen(realm->path);
if( (plen >= rlen) && if ((plen >= rlen) &&
!strncasecmp(pi->name, realm->path, rlen) && !strncasecmp(pi->name, realm->path, rlen) &&
!strcmp(user, realm->user) !strcmp(user, realm->user))
) { {
req->realm = realm; req->realm = realm;
break; break;
} }
} }
/* found a realm matching the username */ /* found a realm matching the username */
if( realm ) if (realm)
{ {
/* check user pass */ /* check user pass */
if (!strcmp(pass, realm->pass) || if (!strcmp(pass, realm->pass) ||
@ -832,7 +837,7 @@ struct listener * uh_listener_add(int sock, struct config *conf)
struct listener *new = NULL; struct listener *new = NULL;
socklen_t sl; socklen_t sl;
if( (new = (struct listener *)malloc(sizeof(struct listener))) != NULL ) if ((new = (struct listener *)malloc(sizeof(struct listener))) != NULL)
{ {
memset(new, 0, sizeof(struct listener)); memset(new, 0, sizeof(struct listener));
@ -857,8 +862,8 @@ struct listener * uh_listener_lookup(int sock)
{ {
struct listener *cur = NULL; struct listener *cur = NULL;
for( cur = uh_listeners; cur; cur = cur->next ) for (cur = uh_listeners; cur; cur = cur->next)
if( cur->socket == sock ) if (cur->socket == sock)
return cur; return cur;
return NULL; return NULL;
@ -870,7 +875,7 @@ struct client * uh_client_add(int sock, struct listener *serv)
struct client *new = NULL; struct client *new = NULL;
socklen_t sl; socklen_t sl;
if( (new = (struct client *)malloc(sizeof(struct client))) != NULL ) if ((new = (struct client *)malloc(sizeof(struct client))) != NULL)
{ {
memset(new, 0, sizeof(struct client)); memset(new, 0, sizeof(struct client));
@ -898,8 +903,8 @@ struct client * uh_client_lookup(int sock)
{ {
struct client *cur = NULL; struct client *cur = NULL;
for( cur = uh_clients; cur; cur = cur->next ) for (cur = uh_clients; cur; cur = cur->next)
if( cur->socket == sock ) if (cur->socket == sock)
return cur; return cur;
return NULL; return NULL;
@ -910,11 +915,11 @@ void uh_client_remove(int sock)
struct client *cur = NULL; struct client *cur = NULL;
struct client *prv = NULL; struct client *prv = NULL;
for( cur = uh_clients; cur; prv = cur, cur = cur->next ) for (cur = uh_clients; cur; prv = cur, cur = cur->next)
{ {
if( cur->socket == sock ) if (cur->socket == sock)
{ {
if( prv ) if (prv)
prv->next = cur->next; prv->next = cur->next;
else else
uh_clients = cur->next; uh_clients = cur->next;
@ -933,8 +938,7 @@ struct interpreter * uh_interpreter_add(const char *extn, const char *path)
{ {
struct interpreter *new = NULL; struct interpreter *new = NULL;
if( (new = (struct interpreter *) if ((new = (struct interpreter *)malloc(sizeof(struct interpreter))) != NULL)
malloc(sizeof(struct interpreter))) != NULL )
{ {
memset(new, 0, sizeof(struct interpreter)); memset(new, 0, sizeof(struct interpreter));
@ -955,11 +959,11 @@ struct interpreter * uh_interpreter_lookup(const char *path)
struct interpreter *cur = NULL; struct interpreter *cur = NULL;
const char *e; const char *e;
for( cur = uh_interpreters; cur; cur = cur->next ) for (cur = uh_interpreters; cur; cur = cur->next)
{ {
e = &path[max(strlen(path) - strlen(cur->extn), 0)]; e = &path[max(strlen(path) - strlen(cur->extn), 0)];
if( !strcmp(e, cur->extn) ) if (!strcmp(e, cur->extn))
return cur; return cur;
} }

View file

@ -44,7 +44,7 @@ static void uh_sigterm(int sig)
static void uh_sigchld(int sig) static void uh_sigchld(int sig)
{ {
while( waitpid(-1, NULL, WNOHANG) > 0 ) { } while (waitpid(-1, NULL, WNOHANG) > 0) { }
} }
static void uh_config_parse(struct config *conf) static void uh_config_parse(struct config *conf)
@ -58,56 +58,64 @@ static void uh_config_parse(struct config *conf)
const char *path = conf->file ? conf->file : "/etc/httpd.conf"; const char *path = conf->file ? conf->file : "/etc/httpd.conf";
if( (c = fopen(path, "r")) != NULL ) if ((c = fopen(path, "r")) != NULL)
{ {
memset(line, 0, sizeof(line)); memset(line, 0, sizeof(line));
while( fgets(line, sizeof(line) - 1, c) ) while (fgets(line, sizeof(line) - 1, c))
{ {
if( (line[0] == '/') && (strchr(line, ':') != NULL) ) if ((line[0] == '/') && (strchr(line, ':') != NULL))
{ {
if( !(col1 = strchr(line, ':')) || (*col1++ = 0) || if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
!(col2 = strchr(col1, ':')) || (*col2++ = 0) || !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
!(eol = strchr(col2, '\n')) || (*eol++ = 0) ) !(eol = strchr(col2, '\n')) || (*eol++ = 0))
continue; {
continue;
}
if( !uh_auth_add(line, col1, col2) ) if (!uh_auth_add(line, col1, col2))
{ {
fprintf(stderr, fprintf(stderr,
"Notice: No password set for user %s, ignoring " "Notice: No password set for user %s, ignoring "
"authentication on %s\n", col1, line "authentication on %s\n", col1, line
); );
} }
} }
else if( !strncmp(line, "I:", 2) ) else if (!strncmp(line, "I:", 2))
{ {
if( !(col1 = strchr(line, ':')) || (*col1++ = 0) || if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
!(eol = strchr(col1, '\n')) || (*eol++ = 0) ) !(eol = strchr(col1, '\n')) || (*eol++ = 0))
continue; {
continue;
}
conf->index_file = strdup(col1); conf->index_file = strdup(col1);
} }
else if( !strncmp(line, "E404:", 5) ) else if (!strncmp(line, "E404:", 5))
{ {
if( !(col1 = strchr(line, ':')) || (*col1++ = 0) || if (!(col1 = strchr(line, ':')) || (*col1++ = 0) ||
!(eol = strchr(col1, '\n')) || (*eol++ = 0) ) !(eol = strchr(col1, '\n')) || (*eol++ = 0))
continue; {
continue;
}
conf->error_handler = strdup(col1); conf->error_handler = strdup(col1);
} }
#ifdef HAVE_CGI #ifdef HAVE_CGI
else if( (line[0] == '*') && (strchr(line, ':') != NULL) ) else if ((line[0] == '*') && (strchr(line, ':') != NULL))
{ {
if( !(col1 = strchr(line, '*')) || (*col1++ = 0) || if (!(col1 = strchr(line, '*')) || (*col1++ = 0) ||
!(col2 = strchr(col1, ':')) || (*col2++ = 0) || !(col2 = strchr(col1, ':')) || (*col2++ = 0) ||
!(eol = strchr(col2, '\n')) || (*eol++ = 0) ) !(eol = strchr(col2, '\n')) || (*eol++ = 0))
continue; {
continue;
}
if( !uh_interpreter_add(col1, col2) ) if (!uh_interpreter_add(col1, col2))
{ {
fprintf(stderr, fprintf(stderr,
"Unable to add interpreter %s for extension %s: " "Unable to add interpreter %s for extension %s: "
"Out of memory\n", col2, col1 "Out of memory\n", col2, col1
); );
} }
} }
@ -118,10 +126,11 @@ static void uh_config_parse(struct config *conf)
} }
} }
static int uh_socket_bind( static int uh_socket_bind(fd_set *serv_fds, int *max_fd,
fd_set *serv_fds, int *max_fd, const char *host, const char *port, const char *host, const char *port,
struct addrinfo *hints, int do_tls, struct config *conf struct addrinfo *hints, int do_tls,
) { struct config *conf)
{
int sock = -1; int sock = -1;
int yes = 1; int yes = 1;
int status; int status;
@ -132,39 +141,39 @@ static int uh_socket_bind(
struct listener *l = NULL; struct listener *l = NULL;
struct addrinfo *addrs = NULL, *p = NULL; struct addrinfo *addrs = NULL, *p = NULL;
if( (status = getaddrinfo(host, port, hints, &addrs)) != 0 ) if ((status = getaddrinfo(host, port, hints, &addrs)) != 0)
{ {
fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status)); fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(status));
} }
/* try to bind a new socket to each found address */ /* try to bind a new socket to each found address */
for( p = addrs; p; p = p->ai_next ) for (p = addrs; p; p = p->ai_next)
{ {
/* get the socket */ /* get the socket */
if( (sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1 ) if ((sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{ {
perror("socket()"); perror("socket()");
goto error; goto error;
} }
/* "address already in use" */ /* "address already in use" */
if( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) ) if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
{ {
perror("setsockopt()"); perror("setsockopt()");
goto error; goto error;
} }
/* TCP keep-alive */ /* TCP keep-alive */
if( conf->tcp_keepalive > 0 ) if (conf->tcp_keepalive > 0)
{ {
tcp_ka_idl = 1; tcp_ka_idl = 1;
tcp_ka_cnt = 3; tcp_ka_cnt = 3;
tcp_ka_int = conf->tcp_keepalive; tcp_ka_int = conf->tcp_keepalive;
if( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) || if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof(yes)) ||
setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &tcp_ka_idl, sizeof(tcp_ka_idl)) || setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &tcp_ka_idl, sizeof(tcp_ka_idl)) ||
setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) || setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &tcp_ka_int, sizeof(tcp_ka_int)) ||
setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &tcp_ka_cnt, sizeof(tcp_ka_cnt)) ) setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &tcp_ka_cnt, sizeof(tcp_ka_cnt)))
{ {
fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n", fprintf(stderr, "Notice: Unable to enable TCP keep-alive: %s\n",
strerror(errno)); strerror(errno));
@ -172,9 +181,9 @@ static int uh_socket_bind(
} }
/* required to get parallel v4 + v6 working */ /* required to get parallel v4 + v6 working */
if( p->ai_family == AF_INET6 ) if (p->ai_family == AF_INET6)
{ {
if( setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1 ) if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1)
{ {
perror("setsockopt()"); perror("setsockopt()");
goto error; goto error;
@ -182,21 +191,21 @@ static int uh_socket_bind(
} }
/* bind */ /* bind */
if( bind(sock, p->ai_addr, p->ai_addrlen) == -1 ) if (bind(sock, p->ai_addr, p->ai_addrlen) == -1)
{ {
perror("bind()"); perror("bind()");
goto error; goto error;
} }
/* listen */ /* listen */
if( listen(sock, UH_LIMIT_CLIENTS) == -1 ) if (listen(sock, UH_LIMIT_CLIENTS) == -1)
{ {
perror("listen()"); perror("listen()");
goto error; goto error;
} }
/* add listener to global list */ /* add listener to global list */
if( ! (l = uh_listener_add(sock, conf)) ) if (!(l = uh_listener_add(sock, conf)))
{ {
fprintf(stderr, "uh_listener_add(): Failed to allocate memory\n"); fprintf(stderr, "uh_listener_add(): Failed to allocate memory\n");
goto error; goto error;
@ -216,7 +225,7 @@ static int uh_socket_bind(
continue; continue;
error: error:
if( sock > 0 ) if (sock > 0)
close(sock); close(sock);
} }
@ -225,7 +234,8 @@ static int uh_socket_bind(
return bound; return bound;
} }
static struct http_request * uh_http_header_parse(struct client *cl, char *buffer, int buflen) static struct http_request * uh_http_header_parse(struct client *cl,
char *buffer, int buflen)
{ {
char *method = &buffer[0]; char *method = &buffer[0];
char *path = NULL; char *path = NULL;
@ -244,7 +254,7 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
/* terminate initial header line */ /* terminate initial header line */
if( (headers = strfind(buffer, buflen, "\r\n", 2)) != NULL ) if ((headers = strfind(buffer, buflen, "\r\n", 2)) != NULL)
{ {
buffer[buflen-1] = 0; buffer[buflen-1] = 0;
@ -252,16 +262,16 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
*headers++ = 0; *headers++ = 0;
/* find request path */ /* find request path */
if( (path = strchr(buffer, ' ')) != NULL ) if ((path = strchr(buffer, ' ')) != NULL)
*path++ = 0; *path++ = 0;
/* find http version */ /* find http version */
if( (path != NULL) && ((version = strchr(path, ' ')) != NULL) ) if ((path != NULL) && ((version = strchr(path, ' ')) != NULL))
*version++ = 0; *version++ = 0;
/* check method */ /* check method */
if( strcmp(method, "GET") && strcmp(method, "HEAD") && strcmp(method, "POST") ) if (strcmp(method, "GET") && strcmp(method, "HEAD") && strcmp(method, "POST"))
{ {
/* invalid method */ /* invalid method */
uh_http_response(cl, 405, "Method Not Allowed"); uh_http_response(cl, 405, "Method Not Allowed");
@ -286,7 +296,7 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
} }
/* check path */ /* check path */
if( !path || !strlen(path) ) if (!path || !strlen(path))
{ {
/* malformed request */ /* malformed request */
uh_http_response(cl, 400, "Bad Request"); uh_http_response(cl, 400, "Bad Request");
@ -298,8 +308,8 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
} }
/* check version */ /* check version */
if( (version == NULL) || (strcmp(version, "HTTP/0.9") && if ((version == NULL) || (strcmp(version, "HTTP/0.9") &&
strcmp(version, "HTTP/1.0") && strcmp(version, "HTTP/1.1")) ) strcmp(version, "HTTP/1.0") && strcmp(version, "HTTP/1.1")))
{ {
/* unsupported version */ /* unsupported version */
uh_http_response(cl, 400, "Bad Request"); uh_http_response(cl, 400, "Bad Request");
@ -312,15 +322,15 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
/* process header fields */ /* process header fields */
for( i = (int)(headers - buffer); i < buflen; i++ ) for (i = (int)(headers - buffer); i < buflen; i++)
{ {
/* found eol and have name + value, push out header tuple */ /* found eol and have name + value, push out header tuple */
if( hdrname && hdrdata && (buffer[i] == '\r' || buffer[i] == '\n') ) if (hdrname && hdrdata && (buffer[i] == '\r' || buffer[i] == '\n'))
{ {
buffer[i] = 0; buffer[i] = 0;
/* store */ /* store */
if( (hdrcount + 1) < array_size(req.headers) ) if ((hdrcount + 1) < array_size(req.headers))
{ {
req.headers[hdrcount++] = hdrname; req.headers[hdrcount++] = hdrname;
req.headers[hdrcount++] = hdrdata; req.headers[hdrcount++] = hdrdata;
@ -337,9 +347,9 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
} }
/* have name but no value and found a colon, start of value */ /* have name but no value and found a colon, start of value */
else if( hdrname && !hdrdata && else if (hdrname && !hdrdata &&
((i+1) < buflen) && (buffer[i] == ':') ((i+1) < buflen) && (buffer[i] == ':'))
) { {
buffer[i] = 0; buffer[i] = 0;
hdrdata = &buffer[i+1]; hdrdata = &buffer[i+1];
@ -348,7 +358,7 @@ static struct http_request * uh_http_header_parse(struct client *cl, char *buffe
} }
/* have no name and found [A-Za-z], start of name */ /* have no name and found [A-Za-z], start of name */
else if( !hdrname && isalpha(buffer[i]) ) else if (!hdrname && isalpha(buffer[i]))
{ {
hdrname = &buffer[i]; hdrname = &buffer[i];
} }
@ -380,7 +390,7 @@ static struct http_request * uh_http_header_recv(struct client *cl)
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
while( blen > 0 ) while (blen > 0)
{ {
FD_ZERO(&reader); FD_ZERO(&reader);
FD_SET(cl->socket, &reader); FD_SET(cl->socket, &reader);
@ -390,12 +400,12 @@ static struct http_request * uh_http_header_recv(struct client *cl)
timeout.tv_usec = 100000; timeout.tv_usec = 100000;
/* check whether fd is readable */ /* check whether fd is readable */
if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 ) if (select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0)
{ {
/* receive data */ /* receive data */
ensure_out(rlen = uh_tcp_peek(cl, bufptr, blen)); ensure_out(rlen = uh_tcp_peek(cl, bufptr, blen));
if( (idxptr = strfind(buffer, sizeof(buffer), "\r\n\r\n", 4)) ) if ((idxptr = strfind(buffer, sizeof(buffer), "\r\n\r\n", 4)))
{ {
ensure_out(rlen = uh_tcp_recv(cl, bufptr, ensure_out(rlen = uh_tcp_recv(cl, bufptr,
(int)(idxptr - bufptr) + 4)); (int)(idxptr - bufptr) + 4));
@ -410,7 +420,7 @@ static struct http_request * uh_http_header_recv(struct client *cl)
ensure_out(rlen = uh_tcp_recv(cl, bufptr, rlen)); ensure_out(rlen = uh_tcp_recv(cl, bufptr, rlen));
/* unexpected eof - #7904 */ /* unexpected eof - #7904 */
if( rlen == 0 ) if (rlen == 0)
return NULL; return NULL;
blen -= rlen; blen -= rlen;
@ -434,11 +444,11 @@ out:
#if defined(HAVE_LUA) || defined(HAVE_CGI) #if defined(HAVE_LUA) || defined(HAVE_CGI)
static int uh_path_match(const char *prefix, const char *url) static int uh_path_match(const char *prefix, const char *url)
{ {
if( (strstr(url, prefix) == url) && if ((strstr(url, prefix) == url) &&
((prefix[strlen(prefix)-1] == '/') || ((prefix[strlen(prefix)-1] == '/') ||
(strlen(url) == strlen(prefix)) || (strlen(url) == strlen(prefix)) ||
(url[strlen(prefix)] == '/')) (url[strlen(prefix)] == '/')))
) { {
return 1; return 1;
} }
@ -446,14 +456,14 @@ static int uh_path_match(const char *prefix, const char *url)
} }
#endif #endif
static void uh_dispatch_request( static void uh_dispatch_request(struct client *cl, struct http_request *req,
struct client *cl, struct http_request *req, struct path_info *pin struct path_info *pin)
) { {
#ifdef HAVE_CGI #ifdef HAVE_CGI
struct interpreter *ipr = NULL; struct interpreter *ipr = NULL;
if( uh_path_match(cl->server->conf->cgi_prefix, pin->name) || if (uh_path_match(cl->server->conf->cgi_prefix, pin->name) ||
(ipr = uh_interpreter_lookup(pin->phys)) ) (ipr = uh_interpreter_lookup(pin->phys)))
{ {
uh_cgi_request(cl, req, pin, ipr); uh_cgi_request(cl, req, pin, ipr);
} }
@ -485,42 +495,42 @@ static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
used_fds = serv_fds; used_fds = serv_fds;
/* loop */ /* loop */
while(run) while (run)
{ {
/* create a working copy of the used fd set */ /* create a working copy of the used fd set */
read_fds = used_fds; read_fds = used_fds;
/* sleep until socket activity */ /* sleep until socket activity */
if( select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1 ) if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) == -1)
{ {
perror("select()"); perror("select()");
exit(1); exit(1);
} }
/* run through the existing connections looking for data to be read */ /* run through the existing connections looking for data to be read */
for( cur_fd = 0; cur_fd <= max_fd; cur_fd++ ) for (cur_fd = 0; cur_fd <= max_fd; cur_fd++)
{ {
/* is a socket managed by us */ /* is a socket managed by us */
if( FD_ISSET(cur_fd, &read_fds) ) if (FD_ISSET(cur_fd, &read_fds))
{ {
/* is one of our listen sockets */ /* is one of our listen sockets */
if( FD_ISSET(cur_fd, &serv_fds) ) if (FD_ISSET(cur_fd, &serv_fds))
{ {
/* handle new connections */ /* handle new connections */
if( (new_fd = accept(cur_fd, NULL, 0)) != -1 ) if ((new_fd = accept(cur_fd, NULL, 0)) != -1)
{ {
/* add to global client list */ /* add to global client list */
if( (cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL ) if ((cl = uh_client_add(new_fd, uh_listener_lookup(cur_fd))) != NULL)
{ {
#ifdef HAVE_TLS #ifdef HAVE_TLS
/* setup client tls context */ /* setup client tls context */
if( conf->tls ) if (conf->tls)
{ {
if( conf->tls_accept(cl) < 1 ) if (conf->tls_accept(cl) < 1)
{ {
fprintf(stderr, fprintf(stderr,
"tls_accept failed, " "tls_accept failed, "
"connection dropped\n"); "connection dropped\n");
/* close client socket */ /* close client socket */
close(new_fd); close(new_fd);
@ -543,7 +553,8 @@ static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
else else
{ {
fprintf(stderr, fprintf(stderr,
"uh_client_add(): Cannot allocate memory\n"); "uh_client_add(): "
"Cannot allocate memory\n");
close(new_fd); close(new_fd);
} }
@ -553,43 +564,43 @@ static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
/* is a client socket */ /* is a client socket */
else else
{ {
if( ! (cl = uh_client_lookup(cur_fd)) ) if (!(cl = uh_client_lookup(cur_fd)))
{ {
/* this should not happen! */ /* this should not happen! */
fprintf(stderr, fprintf(stderr,
"uh_client_lookup(): No entry for fd %i!\n", "uh_client_lookup(): No entry for fd %i!\n",
cur_fd); cur_fd);
goto cleanup; goto cleanup;
} }
/* parse message header */ /* parse message header */
if( (req = uh_http_header_recv(cl)) != NULL ) if ((req = uh_http_header_recv(cl)) != NULL)
{ {
/* RFC1918 filtering required? */ /* RFC1918 filtering required? */
if( conf->rfc1918_filter && if (conf->rfc1918_filter &&
sa_rfc1918(&cl->peeraddr) && sa_rfc1918(&cl->peeraddr) &&
!sa_rfc1918(&cl->servaddr) ) !sa_rfc1918(&cl->servaddr))
{ {
uh_http_sendhf(cl, 403, "Forbidden", uh_http_sendhf(cl, 403, "Forbidden",
"Rejected request from RFC1918 IP " "Rejected request from RFC1918 IP "
"to public server address"); "to public server address");
} }
else else
#ifdef HAVE_LUA #ifdef HAVE_LUA
/* Lua request? */ /* Lua request? */
if( conf->lua_state && if (conf->lua_state &&
uh_path_match(conf->lua_prefix, req->url) ) uh_path_match(conf->lua_prefix, req->url))
{ {
conf->lua_request(cl, req, conf->lua_state); conf->lua_request(cl, req, conf->lua_state);
} }
else else
#endif #endif
/* dispatch request */ /* dispatch request */
if( (pin = uh_path_lookup(cl, req->url)) != NULL ) if ((pin = uh_path_lookup(cl, req->url)) != NULL)
{ {
/* auth ok? */ /* auth ok? */
if( !pin->redirected && uh_auth_check(cl, req, pin) ) if (!pin->redirected && uh_auth_check(cl, req, pin))
uh_dispatch_request(cl, req, pin); uh_dispatch_request(cl, req, pin);
} }
@ -599,7 +610,7 @@ static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
/* Try to invoke an error handler */ /* Try to invoke an error handler */
pin = uh_path_lookup(cl, conf->error_handler); pin = uh_path_lookup(cl, conf->error_handler);
if( pin && uh_auth_check(cl, req, pin) ) if (pin && uh_auth_check(cl, req, pin))
{ {
req->redirect_status = 404; req->redirect_status = 404;
uh_dispatch_request(cl, req, pin); uh_dispatch_request(cl, req, pin);
@ -614,7 +625,7 @@ static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
#ifdef HAVE_TLS #ifdef HAVE_TLS
/* free client tls context */ /* free client tls context */
if( conf->tls ) if (conf->tls)
conf->tls_close(cl); conf->tls_close(cl);
#endif #endif
@ -633,7 +644,7 @@ static void uh_mainloop(struct config *conf, fd_set serv_fds, int max_fd)
#ifdef HAVE_LUA #ifdef HAVE_LUA
/* destroy the Lua state */ /* destroy the Lua state */
if( conf->lua_state != NULL ) if (conf->lua_state != NULL)
conf->lua_close(conf->lua_state); conf->lua_close(conf->lua_state);
#endif #endif
} }
@ -645,15 +656,15 @@ static inline int uh_inittls(struct config *conf)
void *lib; void *lib;
/* already loaded */ /* already loaded */
if( conf->tls != NULL ) if (conf->tls != NULL)
return 0; return 0;
/* load TLS plugin */ /* load TLS plugin */
if( ! (lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)) ) if (!(lib = dlopen("uhttpd_tls.so", RTLD_LAZY | RTLD_GLOBAL)))
{ {
fprintf(stderr, fprintf(stderr,
"Notice: Unable to load TLS plugin - disabling SSL support! " "Notice: Unable to load TLS plugin - disabling SSL support! "
"(Reason: %s)\n", dlerror() "(Reason: %s)\n", dlerror()
); );
return 1; return 1;
@ -661,24 +672,24 @@ static inline int uh_inittls(struct config *conf)
else else
{ {
/* resolve functions */ /* resolve functions */
if( !(conf->tls_init = dlsym(lib, "uh_tls_ctx_init")) || if (!(conf->tls_init = dlsym(lib, "uh_tls_ctx_init")) ||
!(conf->tls_cert = dlsym(lib, "uh_tls_ctx_cert")) || !(conf->tls_cert = dlsym(lib, "uh_tls_ctx_cert")) ||
!(conf->tls_key = dlsym(lib, "uh_tls_ctx_key")) || !(conf->tls_key = dlsym(lib, "uh_tls_ctx_key")) ||
!(conf->tls_free = dlsym(lib, "uh_tls_ctx_free")) || !(conf->tls_free = dlsym(lib, "uh_tls_ctx_free")) ||
!(conf->tls_accept = dlsym(lib, "uh_tls_client_accept")) || !(conf->tls_accept = dlsym(lib, "uh_tls_client_accept")) ||
!(conf->tls_close = dlsym(lib, "uh_tls_client_close")) || !(conf->tls_close = dlsym(lib, "uh_tls_client_close")) ||
!(conf->tls_recv = dlsym(lib, "uh_tls_client_recv")) || !(conf->tls_recv = dlsym(lib, "uh_tls_client_recv")) ||
!(conf->tls_send = dlsym(lib, "uh_tls_client_send")) !(conf->tls_send = dlsym(lib, "uh_tls_client_send")))
) { {
fprintf(stderr, fprintf(stderr,
"Error: Failed to lookup required symbols " "Error: Failed to lookup required symbols "
"in TLS plugin: %s\n", dlerror() "in TLS plugin: %s\n", dlerror()
); );
exit(1); exit(1);
} }
/* init SSL context */ /* init SSL context */
if( ! (conf->tls = conf->tls_init()) ) if (!(conf->tls = conf->tls_init()))
{ {
fprintf(stderr, "Error: Failed to initalize SSL context\n"); fprintf(stderr, "Error: Failed to initalize SSL context\n");
exit(1); exit(1);
@ -755,17 +766,17 @@ int main (int argc, char **argv)
memset(bind, 0, sizeof(bind)); memset(bind, 0, sizeof(bind));
while( (opt = getopt(argc, argv, while ((opt = getopt(argc, argv,
"fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:i:t:T:A:")) > 0 "fSDRC:K:E:I:p:s:h:c:l:L:d:r:m:x:i:t:T:A:")) > 0)
) { {
switch(opt) switch(opt)
{ {
/* [addr:]port */ /* [addr:]port */
case 'p': case 'p':
case 's': case 's':
if( (port = strrchr(optarg, ':')) != NULL ) if ((port = strrchr(optarg, ':')) != NULL)
{ {
if( (optarg[0] == '[') && (port > optarg) && (port[-1] == ']') ) if ((optarg[0] == '[') && (port > optarg) && (port[-1] == ']'))
memcpy(bind, optarg + 1, memcpy(bind, optarg + 1,
min(sizeof(bind), (int)(port - optarg) - 2)); min(sizeof(bind), (int)(port - optarg) - 2));
else else
@ -780,9 +791,9 @@ int main (int argc, char **argv)
} }
#ifdef HAVE_TLS #ifdef HAVE_TLS
if( opt == 's' ) if (opt == 's')
{ {
if( uh_inittls(&conf) ) if (uh_inittls(&conf))
{ {
fprintf(stderr, fprintf(stderr,
"Notice: TLS support is disabled, " "Notice: TLS support is disabled, "
@ -796,10 +807,9 @@ int main (int argc, char **argv)
#endif #endif
/* bind sockets */ /* bind sockets */
bound += uh_socket_bind( bound += uh_socket_bind(&serv_fds, &max_fd,
&serv_fds, &max_fd, bind[0] ? bind : NULL, port, bind[0] ? bind : NULL,
&hints, (opt == 's'), &conf port, &hints, (opt == 's'), &conf);
);
memset(bind, 0, sizeof(bind)); memset(bind, 0, sizeof(bind));
break; break;
@ -807,12 +817,12 @@ int main (int argc, char **argv)
#ifdef HAVE_TLS #ifdef HAVE_TLS
/* certificate */ /* certificate */
case 'C': case 'C':
if( !uh_inittls(&conf) ) if (!uh_inittls(&conf))
{ {
if( conf.tls_cert(conf.tls, optarg) < 1 ) if (conf.tls_cert(conf.tls, optarg) < 1)
{ {
fprintf(stderr, fprintf(stderr,
"Error: Invalid certificate file given\n"); "Error: Invalid certificate file given\n");
exit(1); exit(1);
} }
@ -823,12 +833,12 @@ int main (int argc, char **argv)
/* key */ /* key */
case 'K': case 'K':
if( !uh_inittls(&conf) ) if (!uh_inittls(&conf))
{ {
if( conf.tls_key(conf.tls, optarg) < 1 ) if (conf.tls_key(conf.tls, optarg) < 1)
{ {
fprintf(stderr, fprintf(stderr,
"Error: Invalid private key file given\n"); "Error: Invalid private key file given\n");
exit(1); exit(1);
} }
@ -840,20 +850,20 @@ int main (int argc, char **argv)
/* docroot */ /* docroot */
case 'h': case 'h':
if( ! realpath(optarg, conf.docroot) ) if (! realpath(optarg, conf.docroot))
{ {
fprintf(stderr, "Error: Invalid directory %s: %s\n", fprintf(stderr, "Error: Invalid directory %s: %s\n",
optarg, strerror(errno)); optarg, strerror(errno));
exit(1); exit(1);
} }
break; break;
/* error handler */ /* error handler */
case 'E': case 'E':
if( (strlen(optarg) == 0) || (optarg[0] != '/') ) if ((strlen(optarg) == 0) || (optarg[0] != '/'))
{ {
fprintf(stderr, "Error: Invalid error handler: %s\n", fprintf(stderr, "Error: Invalid error handler: %s\n",
optarg); optarg);
exit(1); exit(1);
} }
conf.error_handler = optarg; conf.error_handler = optarg;
@ -861,10 +871,10 @@ int main (int argc, char **argv)
/* index file */ /* index file */
case 'I': case 'I':
if( (strlen(optarg) == 0) || (optarg[0] == '/') ) if ((strlen(optarg) == 0) || (optarg[0] == '/'))
{ {
fprintf(stderr, "Error: Invalid index page: %s\n", fprintf(stderr, "Error: Invalid index page: %s\n",
optarg); optarg);
exit(1); exit(1);
} }
conf.index_file = optarg; conf.index_file = optarg;
@ -892,7 +902,7 @@ int main (int argc, char **argv)
/* interpreter */ /* interpreter */
case 'i': case 'i':
if( (optarg[0] == '.') && (port = strchr(optarg, '=')) ) if ((optarg[0] == '.') && (port = strchr(optarg, '=')))
{ {
*port++ = 0; *port++ = 0;
uh_interpreter_add(optarg, port); uh_interpreter_add(optarg, port);
@ -900,7 +910,7 @@ int main (int argc, char **argv)
else else
{ {
fprintf(stderr, "Error: Invalid interpreter: %s\n", fprintf(stderr, "Error: Invalid interpreter: %s\n",
optarg); optarg);
exit(1); exit(1);
} }
break; break;
@ -942,7 +952,7 @@ int main (int argc, char **argv)
/* urldecode */ /* urldecode */
case 'd': case 'd':
if( (port = malloc(strlen(optarg)+1)) != NULL ) if ((port = malloc(strlen(optarg)+1)) != NULL)
{ {
/* "decode" plus to space to retain compat */ /* "decode" plus to space to retain compat */
for (opt = 0; optarg[opt]; opt++) for (opt = 0; optarg[opt]; opt++)
@ -951,7 +961,7 @@ int main (int argc, char **argv)
/* opt now contains strlen(optarg) -- no need to re-scan */ /* opt now contains strlen(optarg) -- no need to re-scan */
memset(port, 0, opt+1); memset(port, 0, opt+1);
if (uh_urldecode(port, opt, optarg, opt) < 0) if (uh_urldecode(port, opt, optarg, opt) < 0)
fprintf( stderr, "uhttpd: invalid encoding\n" ); fprintf(stderr, "uhttpd: invalid encoding\n");
printf("%s", port); printf("%s", port);
free(port); free(port);
@ -1015,21 +1025,21 @@ int main (int argc, char **argv)
} }
#ifdef HAVE_TLS #ifdef HAVE_TLS
if( (tls == 1) && (keys < 2) ) if ((tls == 1) && (keys < 2))
{ {
fprintf(stderr, "Error: Missing private key or certificate file\n"); fprintf(stderr, "Error: Missing private key or certificate file\n");
exit(1); exit(1);
} }
#endif #endif
if( bound < 1 ) if (bound < 1)
{ {
fprintf(stderr, "Error: No sockets bound, unable to continue\n"); fprintf(stderr, "Error: No sockets bound, unable to continue\n");
exit(1); exit(1);
} }
/* default docroot */ /* default docroot */
if( !conf.docroot[0] && !realpath(".", conf.docroot) ) if (!conf.docroot[0] && !realpath(".", conf.docroot))
{ {
fprintf(stderr, "Error: Can not determine default document root: %s\n", fprintf(stderr, "Error: Can not determine default document root: %s\n",
strerror(errno)); strerror(errno));
@ -1037,56 +1047,55 @@ int main (int argc, char **argv)
} }
/* default realm */ /* default realm */
if( ! conf.realm ) if (!conf.realm)
conf.realm = "Protected Area"; conf.realm = "Protected Area";
/* config file */ /* config file */
uh_config_parse(&conf); uh_config_parse(&conf);
/* default network timeout */ /* default network timeout */
if( conf.network_timeout <= 0 ) if (conf.network_timeout <= 0)
conf.network_timeout = 30; conf.network_timeout = 30;
#if defined(HAVE_CGI) || defined(HAVE_LUA) #if defined(HAVE_CGI) || defined(HAVE_LUA)
/* default script timeout */ /* default script timeout */
if( conf.script_timeout <= 0 ) if (conf.script_timeout <= 0)
conf.script_timeout = 60; conf.script_timeout = 60;
#endif #endif
#ifdef HAVE_CGI #ifdef HAVE_CGI
/* default cgi prefix */ /* default cgi prefix */
if( ! conf.cgi_prefix ) if (!conf.cgi_prefix)
conf.cgi_prefix = "/cgi-bin"; conf.cgi_prefix = "/cgi-bin";
#endif #endif
#ifdef HAVE_LUA #ifdef HAVE_LUA
/* load Lua plugin */ /* load Lua plugin */
if( ! (lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)) ) if (!(lib = dlopen("uhttpd_lua.so", RTLD_LAZY | RTLD_GLOBAL)))
{ {
fprintf(stderr, fprintf(stderr,
"Notice: Unable to load Lua plugin - disabling Lua support! " "Notice: Unable to load Lua plugin - disabling Lua support! "
"(Reason: %s)\n", dlerror() "(Reason: %s)\n", dlerror());
);
} }
else else
{ {
/* resolve functions */ /* resolve functions */
if( !(conf.lua_init = dlsym(lib, "uh_lua_init")) || if (!(conf.lua_init = dlsym(lib, "uh_lua_init")) ||
!(conf.lua_close = dlsym(lib, "uh_lua_close")) || !(conf.lua_close = dlsym(lib, "uh_lua_close")) ||
!(conf.lua_request = dlsym(lib, "uh_lua_request")) !(conf.lua_request = dlsym(lib, "uh_lua_request")))
) { {
fprintf(stderr, fprintf(stderr,
"Error: Failed to lookup required symbols " "Error: Failed to lookup required symbols "
"in Lua plugin: %s\n", dlerror() "in Lua plugin: %s\n", dlerror()
); );
exit(1); exit(1);
} }
/* init Lua runtime if handler is specified */ /* init Lua runtime if handler is specified */
if( conf.lua_handler ) if (conf.lua_handler)
{ {
/* default lua prefix */ /* default lua prefix */
if( ! conf.lua_prefix ) if (!conf.lua_prefix)
conf.lua_prefix = "/lua"; conf.lua_prefix = "/lua";
conf.lua_state = conf.lua_init(&conf); conf.lua_state = conf.lua_init(&conf);
@ -1095,9 +1104,9 @@ int main (int argc, char **argv)
#endif #endif
/* fork (if not disabled) */ /* fork (if not disabled) */
if( ! nofork ) if (!nofork)
{ {
switch( fork() ) switch (fork())
{ {
case -1: case -1:
perror("fork()"); perror("fork()");
@ -1105,16 +1114,16 @@ int main (int argc, char **argv)
case 0: case 0:
/* daemon setup */ /* daemon setup */
if( chdir("/") ) if (chdir("/"))
perror("chdir()"); perror("chdir()");
if( (cur_fd = open("/dev/null", O_WRONLY)) > -1 ) if ((cur_fd = open("/dev/null", O_WRONLY)) > -1)
dup2(cur_fd, 0); dup2(cur_fd, 0);
if( (cur_fd = open("/dev/null", O_RDONLY)) > -1 ) if ((cur_fd = open("/dev/null", O_RDONLY)) > -1)
dup2(cur_fd, 1); dup2(cur_fd, 1);
if( (cur_fd = open("/dev/null", O_RDONLY)) > -1 ) if ((cur_fd = open("/dev/null", O_RDONLY)) > -1)
dup2(cur_fd, 2); dup2(cur_fd, 2);
break; break;
@ -1129,7 +1138,7 @@ int main (int argc, char **argv)
#ifdef HAVE_LUA #ifdef HAVE_LUA
/* destroy the Lua state */ /* destroy the Lua state */
if( conf.lua_state != NULL ) if (conf.lua_state != NULL)
conf.lua_close(conf.lua_state); conf.lua_close(conf.lua_state);
#endif #endif