. 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:
parent
f56dcd2b76
commit
6bb5b5af42
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue