diff --git a/trunk/darkhttpd.c b/trunk/darkhttpd.c index 8838ef1..dc9e2a6 100644 --- a/trunk/darkhttpd.c +++ b/trunk/darkhttpd.c @@ -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; jreply_length = asprintf(&(conn->reply), - "%d %s\n" - "

%s

\n" /* errname */ - "%s\n" /* reason */ - "
\n" - "Generated by %s on %s\n" - "\n", - errcode, errname, errname, reason, pkgname, rfc1123_date(time(NULL))); + conn->reply_length = xasprintf(&(conn->reply), + "%d %s\n" + "

%s

\n" /* errname */ + "%s\n" /* reason */ + "
\n" + "Generated by %s on %s\n" + "\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();