. 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:
Emil Mikulic
2003-06-04 14:29:28 +00:00
parent 5a6c7cf08e
commit 0d755c3618

View File

@@ -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,11 +796,10 @@ 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 */
@@ -782,9 +808,8 @@ static void default_reply(struct connection *conn,
"</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"
@@ -792,8 +817,8 @@ static void default_reply(struct connection *conn,
"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();