Browse Source

[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
personal/stbuehler/mod-csrf
Glenn Strauss 4 years ago
parent
commit
0cc7556aec
  1. 20
      src/mod_dirlisting.c
  2. 20
      src/mod_webdav.c
  3. 56
      src/stat_cache.c
  4. 1
      src/stat_cache.h

20
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

20
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("<D:getcontenttype>httpd/unix-directory</D:getcontenttype>"));
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("<D:getcontenttype>"));
buffer_append_string_buffer(b, ds->value);
buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));
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("<D:getcontenttype>"));
buffer_append_string_buffer(b, type);
buffer_append_string_len(b, CONST_STR_LEN("</D:getcontenttype>"));
found = 1;
}
}
} else if (0 == strcmp(prop_name, "creationdate")) {

56
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);

1
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);

Loading…
Cancel
Save