diff --git a/trunk/darkhttpd.c b/trunk/darkhttpd.c index 5d8a29d..7dbf0be 100644 --- a/trunk/darkhttpd.c +++ b/trunk/darkhttpd.c @@ -106,7 +106,6 @@ struct { \ (elm)->field.le_prev; \ *(elm)->field.le_prev = LIST_NEXT((elm), field); \ } while (0) - /* ------------------------------------------------------------------------ */ @@ -152,16 +151,15 @@ struct connection -LIST_HEAD(mime_map_head, mime_mapping) mime_map = - LIST_HEAD_INITIALIZER(mime_map_head); - struct mime_mapping { - LIST_ENTRY(mime_mapping) entries; - char *extension, *mimetype; }; +struct mime_mapping *mime_map = NULL; +size_t mime_map_size = 0; +size_t longest_ext = 0; + /* If a connection is idle for IDLETIME seconds or more, it gets closed and @@ -179,7 +177,7 @@ struct mime_mapping /* Defaults can be overridden on the command-line */ static in_addr_t bindaddr = INADDR_ANY; -static uint16_t bindport = 80; +static u_int16_t bindport = 80; static int max_connections = -1; /* kern.ipc.somaxconn */ static const char *index_name = "index.html"; @@ -393,6 +391,61 @@ static char *make_safe_uri(const char *uri) +/* --------------------------------------------------------------------------- + * Associates an extension with a mimetype in the mime_map. Entries are in + * unsorted order. Makes copies of extension and mimetype strings. + */ +static void add_mime_mapping(const char *extension, const char *mimetype) +{ + size_t i; + + assert(strlen(extension) > 0); + assert(strlen(mimetype) > 0); + debugf("mapping *.%s \t-> %s\n", extension, mimetype); + + /* update longest_ext */ + i = strlen(extension); + if (i > longest_ext) longest_ext = i; + + /* look through list and replace an existing entry if possible */ + for (i=0; iextension, + ((const struct mime_mapping *)b)->extension + ); +} + +static void sort_mime_map(void) +{ + qsort(mime_map, mime_map_size, sizeof(struct mime_mapping), + mime_mapping_cmp); +} + + + /* --------------------------------------------------------------------------- * Parses a mime.types line and adds the parsed data to the mime_map. */ @@ -417,7 +470,7 @@ static void parse_mimetype_line(const char *line) lbound = bound1; for (;;) { - struct mime_mapping *mapping; + char *mimetype, *extension; /* find beginning of extension */ for (; line[lbound] == ' ' || line[lbound] == '\t'; lbound++); @@ -430,17 +483,11 @@ static void parse_mimetype_line(const char *line) line[rbound] != '\0'; rbound++); - mapping = (struct mime_mapping *) - xmalloc(sizeof(struct mime_mapping)); - mapping->mimetype = split_string(line, pad, bound1); - mapping->extension = split_string(line, lbound, rbound); - - assert(strlen(mapping->mimetype) > 0); - assert(strlen(mapping->extension) > 0); - - debugf("*.%s \t-> %s\n", mapping->extension, mapping->mimetype); - - LIST_INSERT_HEAD(&mime_map, mapping, entries); + mimetype = split_string(line, pad, bound1); + extension = split_string(line, lbound, rbound); + add_mime_mapping(extension, mimetype); + free(mimetype); + free(extension); if (line[rbound] == 0) return; /* end of line */ else lbound = rbound+1; @@ -512,23 +559,40 @@ static void parse_extension_map_file(const char *filename) /* --------------------------------------------------------------------------- - * Uses the mime_map to determine a Content-Type: for a requested URI. + * Uses the mime_map to determine a Content-Type: for a requested URI. This + * bsearch()es mime_map, so make sure it's sorted first. */ +static int mime_mapping_cmp_str(const void *a, const void *b) +{ + return strcmp( + (const char *)a, + ((const struct mime_mapping *)b)->extension + ); +} + static const char *uri_content_type(const char *uri) { - struct mime_mapping *mapping; - size_t urilen = strlen(uri); + size_t period, urilen = strlen(uri); - LIST_FOREACH(mapping, &mime_map, entries) + for (period=urilen-1; + period > 0 && uri[period] != '.' && + (urilen-period-1) <= longest_ext; + period--) + ; + + if (uri[period] == '.') { - size_t extlen = strlen(mapping->extension); - if (urilen >= extlen+3) /* "/a." + "ext" */ + struct mime_mapping *result = + bsearch((uri+period+1), mime_map, mime_map_size, + sizeof(struct mime_mapping), mime_mapping_cmp_str); + + if (result != NULL) { - if (uri[urilen-1-extlen] == '.' && - strcmp(uri+urilen-extlen, mapping->extension) == 0) - return mapping->mimetype; + assert(strcmp(uri+period+1, result->extension) == 0); + return result->mimetype; } } + /* else no period found in the string */ return default_mimetype; } @@ -1550,16 +1614,32 @@ static void httpd_poll(void) static void exit_quickly(int sig) { struct connection *conn; + int i; - printf("caught %s, cleaning up...", strsignal(sig)); fflush(stdout); - LIST_FOREACH(conn, &connlist, entries) + printf("\ncaught %s, cleaning up...", strsignal(sig)); fflush(stdout); + /* close connections */ + conn = LIST_FIRST(&connlist); + while (conn != NULL) { + struct connection *next = LIST_NEXT(conn, entries); LIST_REMOVE(conn, entries); log_connection(conn); free_connection(conn); + free(conn); + conn = next; } close(sockin); if (logfile != NULL) fclose(logfile); + + /* free mime_map */ + for (i=0; i