. Make mime_map a sorted array instead of a LIST_.

. Added add_mime_mapping() to add to mime_map in unsorted order.
. Added sort_mime_map() - uses qsort() and mime_mapping_cmp() to sort
  the mime_map.
. uri_content_type() uses bsearch() and mime_mapping_cmp_str() to search
  through the mime_map for an extension parsed out of a specified URI.
. Free mime_map in exit_quickly()
. Completely deallocate connlist in exit_quickly()
. In main(), parse_commandline() after parse_default_extension_map() so
  that a specified --mimetypes file will -override- the defaults.
This commit is contained in:
Emil Mikulic 2003-06-30 02:11:24 +00:00
parent f56dcd2b76
commit 6bb5b5af42
1 changed files with 115 additions and 31 deletions

View File

@ -106,7 +106,6 @@ struct { \
(elm)->field.le_prev; \ (elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \ *(elm)->field.le_prev = LIST_NEXT((elm), field); \
} while (0) } 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 struct mime_mapping
{ {
LIST_ENTRY(mime_mapping) entries;
char *extension, *mimetype; 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 /* 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 */ /* Defaults can be overridden on the command-line */
static in_addr_t bindaddr = INADDR_ANY; 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 int max_connections = -1; /* kern.ipc.somaxconn */
static const char *index_name = "index.html"; 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; i<mime_map_size; i++)
if (strcmp(mime_map[i].extension, extension) == 0)
{
free(mime_map[i].mimetype);
mime_map[i].mimetype = xstrdup(mimetype);
return;
}
/* no replacement - add a new entry */
mime_map_size++;
mime_map = (struct mime_mapping *)
xrealloc(mime_map, sizeof(struct mime_mapping) * mime_map_size);
mime_map[mime_map_size-1].extension = xstrdup(extension);
mime_map[mime_map_size-1].mimetype = xstrdup(mimetype);
}
/* ---------------------------------------------------------------------------
* qsort() the mime_map. The map must be sorted before it can be searched
* through.
*/
static int mime_mapping_cmp(const void *a, const void *b)
{
return strcmp(
((const struct mime_mapping *)a)->extension,
((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. * 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; lbound = bound1;
for (;;) for (;;)
{ {
struct mime_mapping *mapping; char *mimetype, *extension;
/* find beginning of extension */ /* find beginning of extension */
for (; line[lbound] == ' ' || line[lbound] == '\t'; lbound++); for (; line[lbound] == ' ' || line[lbound] == '\t'; lbound++);
@ -430,17 +483,11 @@ static void parse_mimetype_line(const char *line)
line[rbound] != '\0'; line[rbound] != '\0';
rbound++); rbound++);
mapping = (struct mime_mapping *) mimetype = split_string(line, pad, bound1);
xmalloc(sizeof(struct mime_mapping)); extension = split_string(line, lbound, rbound);
mapping->mimetype = split_string(line, pad, bound1); add_mime_mapping(extension, mimetype);
mapping->extension = split_string(line, lbound, rbound); free(mimetype);
free(extension);
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);
if (line[rbound] == 0) return; /* end of line */ if (line[rbound] == 0) return; /* end of line */
else lbound = rbound+1; 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) static const char *uri_content_type(const char *uri)
{ {
struct mime_mapping *mapping; size_t period, urilen = strlen(uri);
size_t 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); struct mime_mapping *result =
if (urilen >= extlen+3) /* "/a." + "ext" */ 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] == '.' && assert(strcmp(uri+period+1, result->extension) == 0);
strcmp(uri+urilen-extlen, mapping->extension) == 0) return result->mimetype;
return mapping->mimetype;
} }
} }
/* else no period found in the string */
return default_mimetype; return default_mimetype;
} }
@ -1550,16 +1614,32 @@ static void httpd_poll(void)
static void exit_quickly(int sig) static void exit_quickly(int sig)
{ {
struct connection *conn; struct connection *conn;
int i;
printf("caught %s, cleaning up...", strsignal(sig)); fflush(stdout); printf("\ncaught %s, cleaning up...", strsignal(sig)); fflush(stdout);
LIST_FOREACH(conn, &connlist, entries) /* close connections */
conn = LIST_FIRST(&connlist);
while (conn != NULL)
{ {
struct connection *next = LIST_NEXT(conn, entries);
LIST_REMOVE(conn, entries); LIST_REMOVE(conn, entries);
log_connection(conn); log_connection(conn);
free_connection(conn); free_connection(conn);
free(conn);
conn = next;
} }
close(sockin); close(sockin);
if (logfile != NULL) fclose(logfile); if (logfile != NULL) fclose(logfile);
/* free mime_map */
for (i=0; i<mime_map_size; i++)
{
free(mime_map[i].extension);
free(mime_map[i].mimetype);
}
free(mime_map);
free(wwwroot);
printf("done!\n"); printf("done!\n");
/* According to: http://www.cons.org/cracauer/sigint.html /* According to: http://www.cons.org/cracauer/sigint.html
@ -1581,8 +1661,12 @@ static void exit_quickly(int sig)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
printf("%s, %s.\n", pkgname, copyright); printf("%s, %s.\n", pkgname, copyright);
parse_commandline(argc, argv);
parse_default_extension_map(); parse_default_extension_map();
parse_commandline(argc, argv);
/* parse_commandline() might override parts of the extension map by
* parsing a user-specified file.
*/
sort_mime_map();
init_sockin(); init_sockin();
/* open logfile */ /* open logfile */