From 0cc7556aec6ae6da4270e82a72d0bfce52ff1d8c Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 14 Apr 2017 04:03:59 -0400 Subject: [PATCH] [core] perf: stat_cache_mimetype_by_ext() shared code to get mimetype string via longest extension match (attempts to match file basename, then longest ext, then "") Note: this is a behavior change from simple suffix match if there are 16 or more entries in mimetypes.assign --- src/mod_dirlisting.c | 20 ++-------------- src/mod_webdav.c | 20 +++++----------- src/stat_cache.c | 56 ++++++++++++++++++++++++++++++-------------- src/stat_cache.h | 1 + 4 files changed, 48 insertions(+), 49 deletions(-) diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c index dd93aaed..3dacf16d 100644 --- a/src/mod_dirlisting.c +++ b/src/mod_dirlisting.c @@ -875,7 +875,6 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf dirls_entry_t *tmp; char sizebuf[sizeof("999.9K")]; char datebuf[sizeof("2005-Jan-01 22:23:24")]; - size_t k; const char *content_type; long name_max; #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) @@ -1067,23 +1066,8 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf #endif if (content_type == NULL) { - content_type = "application/octet-stream"; - for (k = 0; k < con->conf.mimetypes->used; k++) { - data_string *ds = (data_string *)con->conf.mimetypes->data[k]; - size_t ct_len; - - if (buffer_is_empty(ds->key)) - continue; - - ct_len = buffer_string_length(ds->key); - if (tmp->namelen < ct_len) - continue; - - if (0 == strncasecmp(DIRLIST_ENT_NAME(tmp) + tmp->namelen - ct_len, ds->key->ptr, ct_len)) { - content_type = ds->value->ptr; - break; - } - } + const buffer *type = stat_cache_mimetype_by_ext(con, DIRLIST_ENT_NAME(tmp), tmp->namelen); + content_type = NULL != type ? type->ptr : "application/octet-stream"; } #ifdef HAVE_LOCALTIME_R diff --git a/src/mod_webdav.c b/src/mod_webdav.c index e298d826..d575ade8 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -932,7 +932,6 @@ static int webdav_get_live_property(server *srv, connection *con, handler_ctx *h if (HANDLER_ERROR != (stat_cache_get_entry(srv, con, dst->path, &sce))) { char ctime_buf[] = "2005-08-18T07:27:16Z"; char mtime_buf[] = "Thu, 18 Aug 2005 07:27:16 GMT"; - size_t k; if (0 == strcmp(prop_name, "resourcetype")) { if (S_ISDIR(sce->st.st_mode)) { @@ -946,19 +945,12 @@ static int webdav_get_live_property(server *srv, connection *con, handler_ctx *h buffer_append_string_len(b, CONST_STR_LEN("httpd/unix-directory")); found = 1; } else if(S_ISREG(sce->st.st_mode)) { - for (k = 0; k < con->conf.mimetypes->used; k++) { - data_string *ds = (data_string *)con->conf.mimetypes->data[k]; - - if (buffer_is_empty(ds->key)) continue; - - if (buffer_is_equal_right_len(dst->path, ds->key, buffer_string_length(ds->key))) { - buffer_append_string_len(b,CONST_STR_LEN("")); - buffer_append_string_buffer(b, ds->value); - buffer_append_string_len(b, CONST_STR_LEN("")); - found = 1; - - break; - } + const buffer *type = stat_cache_mimetype_by_ext(con, CONST_BUF_LEN(dst->path)); + if (NULL != type) { + buffer_append_string_len(b, CONST_STR_LEN("")); + buffer_append_string_buffer(b, type); + buffer_append_string_len(b, CONST_STR_LEN("")); + found = 1; } } } else if (0 == strcmp(prop_name, "creationdate")) { diff --git a/src/stat_cache.c b/src/stat_cache.c index c08d2dd7..7215fdf9 100644 --- a/src/stat_cache.c +++ b/src/stat_cache.c @@ -268,6 +268,42 @@ static int stat_cache_attr_get(buffer *buf, char *name, char *xattrname) { } #endif +const buffer * stat_cache_mimetype_by_ext(const connection *con, const char *name, size_t nlen) +{ + const char *end = name + nlen; /*(end of string)*/ + const size_t used = con->conf.mimetypes->used; + if (used < 16) { + for (size_t i = 0; i < used; ++i) { + /* suffix match */ + const data_string *ds = (data_string *)con->conf.mimetypes->data[i]; + const size_t klen = buffer_string_length(ds->key); + if (klen <= nlen && 0 == strncasecmp(end-klen, ds->key->ptr, klen)) + return ds->value; + } + } + else { + const char *s; + const data_string *ds; + if (nlen) { + for (s = end-1; s != name && *s != '/'; --s) ; /*(like memrchr())*/ + if (*s == '/') ++s; + } + else { + s = name; + } + /* search for basename, then longest .ext2.ext1, then .ext1, then "" */ + ds = (data_string *)array_get_element(con->conf.mimetypes, s); + if (NULL != ds) return ds->value; + while (++s < end) { + while (*s != '.' && ++s != end) ; + ds = (data_string *)array_get_element(con->conf.mimetypes, s); + if (NULL != ds) return ds->value; + } + } + + return NULL; +} + /* the famous DJB hash function for strings */ static uint32_t hashme(buffer *str) { uint32_t hash = 5381; @@ -400,7 +436,6 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ stat_cache_entry *sce = NULL; stat_cache *sc; struct stat st; - size_t k; int fd; struct stat lst; #ifdef DEBUG_STAT_CACHE @@ -635,22 +670,9 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ #endif /* xattr did not set a content-type. ask the config */ if (buffer_string_is_empty(sce->content_type)) { - size_t namelen = buffer_string_length(name); - - for (k = 0; k < con->conf.mimetypes->used; k++) { - data_string *ds = (data_string *)con->conf.mimetypes->data[k]; - buffer *type = ds->key; - size_t typelen = buffer_string_length(type); - - if (buffer_is_empty(type)) continue; - - /* check if the right side is the same */ - if (typelen > namelen) continue; - - if (0 == strncasecmp(name->ptr + namelen - typelen, type->ptr, typelen)) { - buffer_copy_buffer(sce->content_type, ds->value); - break; - } + const buffer *type = stat_cache_mimetype_by_ext(con, CONST_BUF_LEN(name)); + if (NULL != type) { + buffer_copy_buffer(sce->content_type, type); } } etag_create(sce->etag, &(sce->st), con->etag_flags); diff --git a/src/stat_cache.h b/src/stat_cache.h index 8610fa9b..72298630 100644 --- a/src/stat_cache.h +++ b/src/stat_cache.h @@ -9,6 +9,7 @@ struct stat_cache; /* declaration */ struct stat_cache *stat_cache_init(server *srv); void stat_cache_free(struct stat_cache *fc); +const buffer * stat_cache_mimetype_by_ext(const connection *con, const char *name, size_t nlen); handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_cache_entry **fce); int stat_cache_open_rdonly_fstat (server *srv, connection *con, buffer *name, struct stat *st);