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:
parent
5a6c7cf08e
commit
0d755c3618
@ -15,6 +15,7 @@
|
||||
* x Log to file.
|
||||
* . Partial content.
|
||||
* x If-Modified-Since.
|
||||
* . Test If-Mod-Since with IE, Phoenix, lynx, links
|
||||
* . Keep-alive connections.
|
||||
* . Chroot, set{uid|gid}.
|
||||
* . Port to Win32.
|
||||
@ -132,6 +133,7 @@ static const char *default_extension_map[] = {
|
||||
"image/jpeg jpeg jpe jpg",
|
||||
"image/gif gif",
|
||||
"audio/mpeg mp2 mp3 mpga",
|
||||
"application/ogg ogg",
|
||||
"text/css css",
|
||||
"text/plain txt asc",
|
||||
"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]
|
||||
*/
|
||||
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);
|
||||
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)
|
||||
{
|
||||
char **elements, **reassembly, *out;
|
||||
int slashes, i, elem, reasm, urilen;
|
||||
unsigned int slashes, elem, reasm, urilen, i, j;
|
||||
|
||||
if (uri[0] != '/') return NULL;
|
||||
urilen = strlen(uri);
|
||||
@ -217,8 +248,6 @@ static char *make_safe_uri(const char *uri)
|
||||
elem = i = 0;
|
||||
while (i < urilen) /* i is the left bound */
|
||||
{
|
||||
int j;
|
||||
|
||||
/* look for a non-slash */
|
||||
for (; uri[i] == '/'; i++);
|
||||
|
||||
@ -244,7 +273,6 @@ static char *make_safe_uri(const char *uri)
|
||||
if (reasm == 0)
|
||||
{
|
||||
/* user walked out of wwwroot! unsafe uri! */
|
||||
int j;
|
||||
for (j=0; j<elem; j++)
|
||||
if (elements[j] != NULL) free(elements[j]);
|
||||
free(elements);
|
||||
@ -284,7 +312,7 @@ static char *make_safe_uri(const char *uri)
|
||||
*/
|
||||
static void parse_mimetype_line(const char *line)
|
||||
{
|
||||
int pad, bound1, lbound, rbound;
|
||||
unsigned int pad, bound1, lbound, rbound;
|
||||
|
||||
/* parse mimetype */
|
||||
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)
|
||||
{
|
||||
@ -514,8 +542,7 @@ static char *expand_tilde(const char *path)
|
||||
|
||||
if (home == NULL) errx(1, "can't expand `~'");
|
||||
|
||||
asprintf(&tmp, "%s%s", home, path+1);
|
||||
if (tmp == NULL) errx(1, "out of memory in asprintf()");
|
||||
xasprintf(&tmp, "%s%s", home, path+1);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@ -682,9 +709,9 @@ static void free_connection(struct connection *conn)
|
||||
/* ---------------------------------------------------------------------------
|
||||
* 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++)
|
||||
str[i] = toupper(str[i]);
|
||||
}
|
||||
@ -724,7 +751,7 @@ static char *rfc1123_date(const time_t when)
|
||||
*/
|
||||
static char *urldecode(const char *url)
|
||||
{
|
||||
int len = strlen(url);
|
||||
size_t len = strlen(url);
|
||||
char *out = (char*)xmalloc(len+1);
|
||||
int i, pos;
|
||||
|
||||
@ -769,31 +796,29 @@ static void default_reply(struct connection *conn,
|
||||
va_list va;
|
||||
|
||||
va_start(va, format);
|
||||
vasprintf(&reason, format, va);
|
||||
xvasprintf(&reason, format, va);
|
||||
va_end(va);
|
||||
if (reason == NULL) errx(1, "out of memory in vasprintf()");
|
||||
|
||||
conn->reply_length = asprintf(&(conn->reply),
|
||||
"<html><head><title>%d %s</title></head><body>\n"
|
||||
"<h1>%s</h1>\n" /* errname */
|
||||
"%s\n" /* reason */
|
||||
"<hr>\n"
|
||||
"Generated by %s on %s\n"
|
||||
"</body></html>\n",
|
||||
errcode, errname, errname, reason, pkgname, rfc1123_date(time(NULL)));
|
||||
conn->reply_length = xasprintf(&(conn->reply),
|
||||
"<html><head><title>%d %s</title></head><body>\n"
|
||||
"<h1>%s</h1>\n" /* errname */
|
||||
"%s\n" /* reason */
|
||||
"<hr>\n"
|
||||
"Generated by %s on %s\n"
|
||||
"</body></html>\n",
|
||||
errcode, errname, errname, reason, pkgname, rfc1123_date(time(NULL)));
|
||||
free(reason);
|
||||
if (conn->reply == NULL) errx(1, "out of memory in asprintf()");
|
||||
|
||||
conn->header_length = asprintf(&(conn->header),
|
||||
"HTTP/1.1 %d %s\r\n"
|
||||
"Date: %s\r\n"
|
||||
"Server: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"\r\n",
|
||||
errcode, errname, rfc1123_date(time(NULL)), pkgname, conn->reply_length);
|
||||
if (conn->header == NULL) errx(1, "out of memory in asprintf()");
|
||||
conn->header_length = xasprintf(&(conn->header),
|
||||
"HTTP/1.1 %d %s\r\n"
|
||||
"Date: %s\r\n"
|
||||
"Server: %s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"\r\n",
|
||||
errcode, errname, rfc1123_date(time(NULL)), pkgname,
|
||||
conn->reply_length);
|
||||
|
||||
conn->reply_type = REPLY_GENERATED;
|
||||
conn->http_code = errcode;
|
||||
@ -873,33 +898,31 @@ static void process_get(struct connection *conn)
|
||||
|
||||
/* make sure it's safe */
|
||||
safe_url = make_safe_uri(decoded_url);
|
||||
free(decoded_url); decoded_url = NULL;
|
||||
if (safe_url == NULL)
|
||||
{
|
||||
default_reply(conn, 400, "Bad Request",
|
||||
"You requested an invalid URI: %s", conn->uri);
|
||||
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] == '/')
|
||||
{
|
||||
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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
free(safe_url);
|
||||
safe_url = NULL;
|
||||
free(safe_url); safe_url = NULL;
|
||||
|
||||
debugf("uri=%s, target=%s, content-type=%s\n",
|
||||
conn->uri, target, mimetype);
|
||||
conn->reply_file = fopen(target, "rb");
|
||||
free(target);
|
||||
target = NULL;
|
||||
free(target); target = NULL;
|
||||
|
||||
if (conn->reply_file == NULL)
|
||||
{
|
||||
@ -939,7 +962,7 @@ static void process_get(struct connection *conn)
|
||||
return;
|
||||
}
|
||||
|
||||
conn->header_length = asprintf(&(conn->header),
|
||||
conn->header_length = xasprintf(&(conn->header),
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Date: %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,
|
||||
mimetype, conn->lastmod
|
||||
);
|
||||
if (conn->header == NULL) errx(1, "out of memory in asprintf()");
|
||||
conn->http_code = 200;
|
||||
}
|
||||
|
||||
@ -966,7 +988,9 @@ static void process_request(struct connection *conn)
|
||||
parse_request(conn);
|
||||
|
||||
if (strcmp(conn->method, "GET") == 0)
|
||||
{
|
||||
process_get(conn);
|
||||
}
|
||||
else if (strcmp(conn->method, "HEAD") == 0)
|
||||
{
|
||||
process_get(conn);
|
||||
@ -978,19 +1002,22 @@ static void process_request(struct connection *conn)
|
||||
strcmp(conn->method, "DELETE") == 0 ||
|
||||
strcmp(conn->method, "TRACE") == 0 ||
|
||||
strcmp(conn->method, "CONNECT") == 0)
|
||||
{
|
||||
default_reply(conn, 501, "Not Implemented",
|
||||
"The method you specified (%s) is not implemented.",
|
||||
conn->method);
|
||||
}
|
||||
else
|
||||
{
|
||||
default_reply(conn, 400, "Bad Request",
|
||||
"%s is not a valid HTTP/1.1 method.", conn->method);
|
||||
}
|
||||
|
||||
/* advance state */
|
||||
conn->state = SEND_HEADER;
|
||||
|
||||
/* request not needed anymore */
|
||||
free(conn->request);
|
||||
conn->request = NULL;
|
||||
free(conn->request); conn->request = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -1017,7 +1044,7 @@ static void poll_recv_request(struct connection *conn)
|
||||
|
||||
/* append to conn->request */
|
||||
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[conn->request_length] = 0;
|
||||
|
||||
@ -1093,10 +1120,10 @@ static void poll_send_reply(struct connection *conn)
|
||||
/* from file! */
|
||||
#define BUFSIZE 65000
|
||||
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
|
||||
|
||||
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);
|
||||
|
||||
if (fread(buf, amount, 1, conn->reply_file) != 1)
|
||||
@ -1228,18 +1255,15 @@ static void httpd_poll(void)
|
||||
switch (conn->state)
|
||||
{
|
||||
case RECV_REQUEST:
|
||||
if (FD_ISSET(conn->socket, &recv_set))
|
||||
poll_recv_request(conn);
|
||||
if (FD_ISSET(conn->socket, &recv_set)) poll_recv_request(conn);
|
||||
break;
|
||||
|
||||
case SEND_HEADER:
|
||||
if (FD_ISSET(conn->socket, &send_set))
|
||||
poll_send_header(conn);
|
||||
if (FD_ISSET(conn->socket, &send_set)) poll_send_header(conn);
|
||||
break;
|
||||
|
||||
case SEND_REPLY:
|
||||
if (FD_ISSET(conn->socket, &send_set))
|
||||
poll_send_reply(conn);
|
||||
if (FD_ISSET(conn->socket, &send_set)) poll_send_reply(conn);
|
||||
break;
|
||||
|
||||
default: errx(1, "invalid state");
|
||||
@ -1258,6 +1282,9 @@ static void ignore_signal(int signum)
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
* Execution starts here.
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
signal(SIGPIPE, ignore_signal);
|
||||
if (signal(SIGPIPE, ignore_signal) == SIG_ERR)
|
||||
err(1, "signal(SIG_PIPE)");
|
||||
|
||||
for (;;) httpd_poll();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user