mirror of
https://github.com/emikulic/darkhttpd.git
synced 2023-08-10 21:13:08 +03:00
. Added ogg mimetype
. Added xvasprintf() . Added xasprintf() . Some signed/unsigned clarifications . Simplified asprintf() error handling using xasprintf() . Check for failure of signal()
This commit is contained in:
@@ -15,6 +15,7 @@
|
|||||||
* x Log to file.
|
* x Log to file.
|
||||||
* . Partial content.
|
* . Partial content.
|
||||||
* x If-Modified-Since.
|
* x If-Modified-Since.
|
||||||
|
* . Test If-Mod-Since with IE, Phoenix, lynx, links
|
||||||
* . Keep-alive connections.
|
* . Keep-alive connections.
|
||||||
* . Chroot, set{uid|gid}.
|
* . Chroot, set{uid|gid}.
|
||||||
* . Port to Win32.
|
* . Port to Win32.
|
||||||
@@ -132,6 +133,7 @@ static const char *default_extension_map[] = {
|
|||||||
"image/jpeg jpeg jpe jpg",
|
"image/jpeg jpeg jpe jpg",
|
||||||
"image/gif gif",
|
"image/gif gif",
|
||||||
"audio/mpeg mp2 mp3 mpga",
|
"audio/mpeg mp2 mp3 mpga",
|
||||||
|
"application/ogg ogg",
|
||||||
"text/css css",
|
"text/css css",
|
||||||
"text/plain txt asc",
|
"text/plain txt asc",
|
||||||
"text/xml xml",
|
"text/xml xml",
|
||||||
@@ -180,10 +182,39 @@ static char *xstrdup(const char *src)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* asprintf() that errx()s if it fails.
|
||||||
|
*/
|
||||||
|
static unsigned int xvasprintf(char **ret, const char *format, va_list ap)
|
||||||
|
{
|
||||||
|
int len = vasprintf(ret, format, ap);
|
||||||
|
if (ret == NULL || len == -1) errx(1, "out of memory in vasprintf()");
|
||||||
|
return (unsigned int)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* asprintf() that errx()s if it fails.
|
||||||
|
*/
|
||||||
|
static unsigned int xasprintf(char **ret, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
va_start(va, format);
|
||||||
|
len = xvasprintf(ret, format, va);
|
||||||
|
va_end(va);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Split string out of src with range [left:right-1]
|
* Split string out of src with range [left:right-1]
|
||||||
*/
|
*/
|
||||||
static char *split_string(const char *src, const int left, const int right)
|
static char *split_string(const char *src,
|
||||||
|
const unsigned int left, const unsigned int right)
|
||||||
{
|
{
|
||||||
char *dest = (char*) xmalloc(right - left + 1);
|
char *dest = (char*) xmalloc(right - left + 1);
|
||||||
memcpy(dest, src+left, right-left);
|
memcpy(dest, src+left, right-left);
|
||||||
@@ -200,7 +231,7 @@ static char *split_string(const char *src, const int left, const int right)
|
|||||||
static char *make_safe_uri(const char *uri)
|
static char *make_safe_uri(const char *uri)
|
||||||
{
|
{
|
||||||
char **elements, **reassembly, *out;
|
char **elements, **reassembly, *out;
|
||||||
int slashes, i, elem, reasm, urilen;
|
unsigned int slashes, elem, reasm, urilen, i, j;
|
||||||
|
|
||||||
if (uri[0] != '/') return NULL;
|
if (uri[0] != '/') return NULL;
|
||||||
urilen = strlen(uri);
|
urilen = strlen(uri);
|
||||||
@@ -217,8 +248,6 @@ static char *make_safe_uri(const char *uri)
|
|||||||
elem = i = 0;
|
elem = i = 0;
|
||||||
while (i < urilen) /* i is the left bound */
|
while (i < urilen) /* i is the left bound */
|
||||||
{
|
{
|
||||||
int j;
|
|
||||||
|
|
||||||
/* look for a non-slash */
|
/* look for a non-slash */
|
||||||
for (; uri[i] == '/'; i++);
|
for (; uri[i] == '/'; i++);
|
||||||
|
|
||||||
@@ -244,7 +273,6 @@ static char *make_safe_uri(const char *uri)
|
|||||||
if (reasm == 0)
|
if (reasm == 0)
|
||||||
{
|
{
|
||||||
/* user walked out of wwwroot! unsafe uri! */
|
/* user walked out of wwwroot! unsafe uri! */
|
||||||
int j;
|
|
||||||
for (j=0; j<elem; j++)
|
for (j=0; j<elem; j++)
|
||||||
if (elements[j] != NULL) free(elements[j]);
|
if (elements[j] != NULL) free(elements[j]);
|
||||||
free(elements);
|
free(elements);
|
||||||
@@ -284,7 +312,7 @@ static char *make_safe_uri(const char *uri)
|
|||||||
*/
|
*/
|
||||||
static void parse_mimetype_line(const char *line)
|
static void parse_mimetype_line(const char *line)
|
||||||
{
|
{
|
||||||
int pad, bound1, lbound, rbound;
|
unsigned int pad, bound1, lbound, rbound;
|
||||||
|
|
||||||
/* parse mimetype */
|
/* parse mimetype */
|
||||||
for (pad=0; line[pad] == ' ' || line[pad] == '\t'; pad++);
|
for (pad=0; line[pad] == ' ' || line[pad] == '\t'; pad++);
|
||||||
@@ -398,7 +426,7 @@ static void parse_extension_map_file(const char *filename)
|
|||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Uses the mime_map to determines a Content-Type: for a requested URI.
|
* Uses the mime_map to determine a Content-Type: for a requested URI.
|
||||||
*/
|
*/
|
||||||
static const char *uri_content_type(const char *uri)
|
static const char *uri_content_type(const char *uri)
|
||||||
{
|
{
|
||||||
@@ -514,8 +542,7 @@ static char *expand_tilde(const char *path)
|
|||||||
|
|
||||||
if (home == NULL) errx(1, "can't expand `~'");
|
if (home == NULL) errx(1, "can't expand `~'");
|
||||||
|
|
||||||
asprintf(&tmp, "%s%s", home, path+1);
|
xasprintf(&tmp, "%s%s", home, path+1);
|
||||||
if (tmp == NULL) errx(1, "out of memory in asprintf()");
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -682,9 +709,9 @@ static void free_connection(struct connection *conn)
|
|||||||
/* ---------------------------------------------------------------------------
|
/* ---------------------------------------------------------------------------
|
||||||
* Uppercasify all characters in a string of given length.
|
* Uppercasify all characters in a string of given length.
|
||||||
*/
|
*/
|
||||||
static void strntoupper(char *str, const int length)
|
static void strntoupper(char *str, const size_t length)
|
||||||
{
|
{
|
||||||
int i;
|
size_t i;
|
||||||
for (i=0; i<length; i++)
|
for (i=0; i<length; i++)
|
||||||
str[i] = toupper(str[i]);
|
str[i] = toupper(str[i]);
|
||||||
}
|
}
|
||||||
@@ -724,7 +751,7 @@ static char *rfc1123_date(const time_t when)
|
|||||||
*/
|
*/
|
||||||
static char *urldecode(const char *url)
|
static char *urldecode(const char *url)
|
||||||
{
|
{
|
||||||
int len = strlen(url);
|
size_t len = strlen(url);
|
||||||
char *out = (char*)xmalloc(len+1);
|
char *out = (char*)xmalloc(len+1);
|
||||||
int i, pos;
|
int i, pos;
|
||||||
|
|
||||||
@@ -769,31 +796,29 @@ static void default_reply(struct connection *conn,
|
|||||||
va_list va;
|
va_list va;
|
||||||
|
|
||||||
va_start(va, format);
|
va_start(va, format);
|
||||||
vasprintf(&reason, format, va);
|
xvasprintf(&reason, format, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
if (reason == NULL) errx(1, "out of memory in vasprintf()");
|
|
||||||
|
|
||||||
conn->reply_length = asprintf(&(conn->reply),
|
conn->reply_length = xasprintf(&(conn->reply),
|
||||||
"<html><head><title>%d %s</title></head><body>\n"
|
"<html><head><title>%d %s</title></head><body>\n"
|
||||||
"<h1>%s</h1>\n" /* errname */
|
"<h1>%s</h1>\n" /* errname */
|
||||||
"%s\n" /* reason */
|
"%s\n" /* reason */
|
||||||
"<hr>\n"
|
"<hr>\n"
|
||||||
"Generated by %s on %s\n"
|
"Generated by %s on %s\n"
|
||||||
"</body></html>\n",
|
"</body></html>\n",
|
||||||
errcode, errname, errname, reason, pkgname, rfc1123_date(time(NULL)));
|
errcode, errname, errname, reason, pkgname, rfc1123_date(time(NULL)));
|
||||||
free(reason);
|
free(reason);
|
||||||
if (conn->reply == NULL) errx(1, "out of memory in asprintf()");
|
|
||||||
|
|
||||||
conn->header_length = asprintf(&(conn->header),
|
conn->header_length = xasprintf(&(conn->header),
|
||||||
"HTTP/1.1 %d %s\r\n"
|
"HTTP/1.1 %d %s\r\n"
|
||||||
"Date: %s\r\n"
|
"Date: %s\r\n"
|
||||||
"Server: %s\r\n"
|
"Server: %s\r\n"
|
||||||
"Connection: close\r\n"
|
"Connection: close\r\n"
|
||||||
"Content-Length: %d\r\n"
|
"Content-Length: %d\r\n"
|
||||||
"Content-Type: text/html\r\n"
|
"Content-Type: text/html\r\n"
|
||||||
"\r\n",
|
"\r\n",
|
||||||
errcode, errname, rfc1123_date(time(NULL)), pkgname, conn->reply_length);
|
errcode, errname, rfc1123_date(time(NULL)), pkgname,
|
||||||
if (conn->header == NULL) errx(1, "out of memory in asprintf()");
|
conn->reply_length);
|
||||||
|
|
||||||
conn->reply_type = REPLY_GENERATED;
|
conn->reply_type = REPLY_GENERATED;
|
||||||
conn->http_code = errcode;
|
conn->http_code = errcode;
|
||||||
@@ -873,33 +898,31 @@ static void process_get(struct connection *conn)
|
|||||||
|
|
||||||
/* make sure it's safe */
|
/* make sure it's safe */
|
||||||
safe_url = make_safe_uri(decoded_url);
|
safe_url = make_safe_uri(decoded_url);
|
||||||
|
free(decoded_url); decoded_url = NULL;
|
||||||
if (safe_url == NULL)
|
if (safe_url == NULL)
|
||||||
{
|
{
|
||||||
default_reply(conn, 400, "Bad Request",
|
default_reply(conn, 400, "Bad Request",
|
||||||
"You requested an invalid URI: %s", conn->uri);
|
"You requested an invalid URI: %s", conn->uri);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free(decoded_url);
|
|
||||||
decoded_url = NULL;
|
|
||||||
|
|
||||||
|
/* does it end in a slash? serve up url/index_name */
|
||||||
if (safe_url[strlen(safe_url)-1] == '/')
|
if (safe_url[strlen(safe_url)-1] == '/')
|
||||||
{
|
{
|
||||||
asprintf(&target, "%s%s%s", wwwroot, safe_url, index_name);
|
xasprintf(&target, "%s%s%s", wwwroot, safe_url, index_name);
|
||||||
mimetype = uri_content_type(index_name);
|
mimetype = uri_content_type(index_name);
|
||||||
}
|
}
|
||||||
else
|
else /* points to a file */
|
||||||
{
|
{
|
||||||
asprintf(&target, "%s%s", wwwroot, safe_url);
|
xasprintf(&target, "%s%s", wwwroot, safe_url);
|
||||||
mimetype = uri_content_type(safe_url);
|
mimetype = uri_content_type(safe_url);
|
||||||
}
|
}
|
||||||
free(safe_url);
|
free(safe_url); safe_url = NULL;
|
||||||
safe_url = NULL;
|
|
||||||
|
|
||||||
debugf("uri=%s, target=%s, content-type=%s\n",
|
debugf("uri=%s, target=%s, content-type=%s\n",
|
||||||
conn->uri, target, mimetype);
|
conn->uri, target, mimetype);
|
||||||
conn->reply_file = fopen(target, "rb");
|
conn->reply_file = fopen(target, "rb");
|
||||||
free(target);
|
free(target); target = NULL;
|
||||||
target = NULL;
|
|
||||||
|
|
||||||
if (conn->reply_file == NULL)
|
if (conn->reply_file == NULL)
|
||||||
{
|
{
|
||||||
@@ -939,7 +962,7 @@ static void process_get(struct connection *conn)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->header_length = asprintf(&(conn->header),
|
conn->header_length = xasprintf(&(conn->header),
|
||||||
"HTTP/1.1 200 OK\r\n"
|
"HTTP/1.1 200 OK\r\n"
|
||||||
"Date: %s\r\n"
|
"Date: %s\r\n"
|
||||||
"Server: %s\r\n"
|
"Server: %s\r\n"
|
||||||
@@ -952,7 +975,6 @@ static void process_get(struct connection *conn)
|
|||||||
rfc1123_date(time(NULL)), pkgname, conn->reply_length,
|
rfc1123_date(time(NULL)), pkgname, conn->reply_length,
|
||||||
mimetype, conn->lastmod
|
mimetype, conn->lastmod
|
||||||
);
|
);
|
||||||
if (conn->header == NULL) errx(1, "out of memory in asprintf()");
|
|
||||||
conn->http_code = 200;
|
conn->http_code = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -966,7 +988,9 @@ static void process_request(struct connection *conn)
|
|||||||
parse_request(conn);
|
parse_request(conn);
|
||||||
|
|
||||||
if (strcmp(conn->method, "GET") == 0)
|
if (strcmp(conn->method, "GET") == 0)
|
||||||
|
{
|
||||||
process_get(conn);
|
process_get(conn);
|
||||||
|
}
|
||||||
else if (strcmp(conn->method, "HEAD") == 0)
|
else if (strcmp(conn->method, "HEAD") == 0)
|
||||||
{
|
{
|
||||||
process_get(conn);
|
process_get(conn);
|
||||||
@@ -978,19 +1002,22 @@ static void process_request(struct connection *conn)
|
|||||||
strcmp(conn->method, "DELETE") == 0 ||
|
strcmp(conn->method, "DELETE") == 0 ||
|
||||||
strcmp(conn->method, "TRACE") == 0 ||
|
strcmp(conn->method, "TRACE") == 0 ||
|
||||||
strcmp(conn->method, "CONNECT") == 0)
|
strcmp(conn->method, "CONNECT") == 0)
|
||||||
|
{
|
||||||
default_reply(conn, 501, "Not Implemented",
|
default_reply(conn, 501, "Not Implemented",
|
||||||
"The method you specified (%s) is not implemented.",
|
"The method you specified (%s) is not implemented.",
|
||||||
conn->method);
|
conn->method);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
default_reply(conn, 400, "Bad Request",
|
default_reply(conn, 400, "Bad Request",
|
||||||
"%s is not a valid HTTP/1.1 method.", conn->method);
|
"%s is not a valid HTTP/1.1 method.", conn->method);
|
||||||
|
}
|
||||||
|
|
||||||
/* advance state */
|
/* advance state */
|
||||||
conn->state = SEND_HEADER;
|
conn->state = SEND_HEADER;
|
||||||
|
|
||||||
/* request not needed anymore */
|
/* request not needed anymore */
|
||||||
free(conn->request);
|
free(conn->request); conn->request = NULL;
|
||||||
conn->request = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1017,7 +1044,7 @@ static void poll_recv_request(struct connection *conn)
|
|||||||
|
|
||||||
/* append to conn->request */
|
/* append to conn->request */
|
||||||
conn->request = xrealloc(conn->request, conn->request_length+recvd+1);
|
conn->request = xrealloc(conn->request, conn->request_length+recvd+1);
|
||||||
memcpy(conn->request+conn->request_length, buf, recvd);
|
memcpy(conn->request+conn->request_length, buf, (size_t)recvd);
|
||||||
conn->request_length += recvd;
|
conn->request_length += recvd;
|
||||||
conn->request[conn->request_length] = 0;
|
conn->request[conn->request_length] = 0;
|
||||||
|
|
||||||
@@ -1093,10 +1120,10 @@ static void poll_send_reply(struct connection *conn)
|
|||||||
/* from file! */
|
/* from file! */
|
||||||
#define BUFSIZE 65000
|
#define BUFSIZE 65000
|
||||||
char buf[BUFSIZE];
|
char buf[BUFSIZE];
|
||||||
int amount = min(BUFSIZE, conn->reply_length - conn->reply_sent);
|
size_t amount = min(BUFSIZE, conn->reply_length - conn->reply_sent);
|
||||||
#undef BUFSIZE
|
#undef BUFSIZE
|
||||||
|
|
||||||
if (fseek(conn->reply_file, conn->reply_sent, SEEK_SET) == -1)
|
if (fseek(conn->reply_file, (long)conn->reply_sent, SEEK_SET) == -1)
|
||||||
err(1, "fseek(%d)", conn->reply_sent);
|
err(1, "fseek(%d)", conn->reply_sent);
|
||||||
|
|
||||||
if (fread(buf, amount, 1, conn->reply_file) != 1)
|
if (fread(buf, amount, 1, conn->reply_file) != 1)
|
||||||
@@ -1228,18 +1255,15 @@ static void httpd_poll(void)
|
|||||||
switch (conn->state)
|
switch (conn->state)
|
||||||
{
|
{
|
||||||
case RECV_REQUEST:
|
case RECV_REQUEST:
|
||||||
if (FD_ISSET(conn->socket, &recv_set))
|
if (FD_ISSET(conn->socket, &recv_set)) poll_recv_request(conn);
|
||||||
poll_recv_request(conn);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEND_HEADER:
|
case SEND_HEADER:
|
||||||
if (FD_ISSET(conn->socket, &send_set))
|
if (FD_ISSET(conn->socket, &send_set)) poll_send_header(conn);
|
||||||
poll_send_header(conn);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SEND_REPLY:
|
case SEND_REPLY:
|
||||||
if (FD_ISSET(conn->socket, &send_set))
|
if (FD_ISSET(conn->socket, &send_set)) poll_send_reply(conn);
|
||||||
poll_send_reply(conn);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: errx(1, "invalid state");
|
default: errx(1, "invalid state");
|
||||||
@@ -1258,6 +1282,9 @@ static void ignore_signal(int signum)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------
|
||||||
|
* Execution starts here.
|
||||||
|
*/
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
printf("%s, %s.\n", pkgname, copyright);
|
printf("%s, %s.\n", pkgname, copyright);
|
||||||
@@ -1272,7 +1299,8 @@ int main(int argc, char *argv[])
|
|||||||
if (logfile == NULL) err(1, "fopen(\"%s\")", logfile_name);
|
if (logfile == NULL) err(1, "fopen(\"%s\")", logfile_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
signal(SIGPIPE, ignore_signal);
|
if (signal(SIGPIPE, ignore_signal) == SIG_ERR)
|
||||||
|
err(1, "signal(SIG_PIPE)");
|
||||||
|
|
||||||
for (;;) httpd_poll();
|
for (;;) httpd_poll();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user