. 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
1 changed files with 84 additions and 56 deletions

View File

@ -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();