the upcoming 2.0 version
https://redmine.lighttpd.net/projects/lighttpd2
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
3.5 KiB
133 lines
3.5 KiB
|
|
#include <lighttpd/base.h> |
|
#include <lighttpd/plugin_core.h> |
|
|
|
#include <assert.h> |
|
|
|
#define MIME_COUNT_CHILDREN(x) (x->cmin == 0 ? 0 : ((guint)x->cmax - x->cmin + 1)) |
|
#define MIME_MARK_NODE(x) ((gpointer)((uintptr_t)x | 1)) |
|
#define MIME_UNMARK_NODE(x) ((gpointer)((uintptr_t)x & (~1))) |
|
#define MIME_IS_NODE(x) (1 == ((uintptr_t)x & 1)) |
|
|
|
liMimetypeNode *li_mimetype_node_new(void) { |
|
return g_slice_new0(liMimetypeNode); |
|
} |
|
|
|
void li_mimetype_node_free(liMimetypeNode *node) { |
|
guint i; |
|
gpointer ptr; |
|
|
|
if (node->mimetype) |
|
g_string_free(node->mimetype, TRUE); |
|
|
|
for (i = 0; i < MIME_COUNT_CHILDREN(node); i++) { |
|
ptr = node->children[i]; |
|
|
|
if (NULL == ptr) |
|
continue; |
|
|
|
if (!MIME_IS_NODE(ptr)) { |
|
g_string_free(ptr, TRUE); |
|
} else { |
|
li_mimetype_node_free(MIME_UNMARK_NODE(ptr)); |
|
} |
|
} |
|
|
|
if (node->children) |
|
g_free(node->children); |
|
|
|
g_slice_free(liMimetypeNode, node); |
|
} |
|
|
|
static void mimetype_insert(liMimetypeNode *node, GString *suffix, GString *mimetype, guint depth) { |
|
guchar c, cdiff; |
|
gpointer ptr; |
|
liMimetypeNode *next_node; |
|
assert(!MIME_IS_NODE(mimetype)); |
|
|
|
/* start of suffix reached */ |
|
if (depth == suffix->len) { |
|
if (node->mimetype) |
|
g_string_free(node->mimetype, TRUE); |
|
|
|
node->mimetype = mimetype; |
|
return; |
|
} |
|
|
|
c = (guchar) suffix->str[suffix->len - depth - 1]; |
|
assert(c != '\0'); |
|
|
|
if (NULL == node->children) { |
|
node->cmin = node->cmax = c; |
|
node->children = g_malloc(sizeof(gpointer)); |
|
node->children[0] = NULL; |
|
} else if (c < node->cmin) { |
|
cdiff = node->cmin - c; /* how much space we need in front */ |
|
node->children = g_realloc(node->children, sizeof(gpointer) * (MIME_COUNT_CHILDREN(node) + cdiff)); /* make room for more children */ |
|
memmove(&node->children[(guint)cdiff], node->children, sizeof(gpointer) * MIME_COUNT_CHILDREN(node)); /* move existing children to the back */ |
|
memset(node->children, 0, cdiff * sizeof(gpointer)); |
|
node->cmin = c; |
|
} else if (c > node->cmax) { |
|
cdiff = c - node->cmax; |
|
node->children = g_realloc(node->children, sizeof(gpointer) * (MIME_COUNT_CHILDREN(node) + cdiff)); /* make room for more children */ |
|
memset(&node->children[MIME_COUNT_CHILDREN(node)], 0, cdiff * sizeof(gpointer)); |
|
node->cmax = c; |
|
} |
|
|
|
ptr = node->children[c - node->cmin]; |
|
|
|
if (NULL != ptr && MIME_IS_NODE(ptr)) { |
|
/* slot contains another node */ |
|
next_node = MIME_UNMARK_NODE(ptr); |
|
} else { |
|
/* slot not used yet or contains a mimetype, split into node */ |
|
next_node = g_slice_new(liMimetypeNode); |
|
next_node->mimetype = ptr; |
|
next_node->cmax = next_node->cmin = 0; |
|
next_node->children = NULL; |
|
node->children[c - node->cmin] = MIME_MARK_NODE(next_node); |
|
} |
|
|
|
mimetype_insert(next_node, suffix, mimetype, depth+1); |
|
} |
|
|
|
void li_mimetype_insert(liMimetypeNode *node, GString *suffix, GString *mimetype) { |
|
mimetype_insert(node, suffix, mimetype, 0); |
|
} |
|
|
|
GString *li_mimetype_get(liVRequest *vr, GString *filename) { |
|
/* search in mime_types option for the longest suffix match */ |
|
GString *mimetype; |
|
liMimetypeNode *node; |
|
guchar *c, *s; |
|
gpointer ptr; |
|
|
|
if (!vr || !filename || !filename->len) |
|
return NULL; |
|
|
|
node = CORE_OPTIONPTR(LI_CORE_OPTION_MIME_TYPES).ptr; |
|
|
|
mimetype = node->mimetype; |
|
|
|
for (s = (guchar*) filename->str, c = (guchar*) filename->str + filename->len; c-- > s; ) { |
|
if (*c < node->cmin || *c > node->cmax) |
|
return mimetype; |
|
|
|
ptr = node->children[*c - node->cmin]; |
|
if (NULL == ptr) { |
|
return mimetype; |
|
} |
|
|
|
if (!MIME_IS_NODE(ptr)) { |
|
return ptr; |
|
} |
|
|
|
node = MIME_UNMARK_NODE(ptr); |
|
|
|
if (NULL != node->mimetype) { |
|
mimetype = node->mimetype; |
|
} |
|
} |
|
|
|
return mimetype; |
|
}
|
|
|