[multiple] stat_cache singleton

personal/stbuehler/ci-build
Glenn Strauss 2019-12-05 03:16:25 -05:00
parent b5775b9951
commit 68d8d4c532
28 changed files with 453 additions and 460 deletions

View File

@ -255,8 +255,6 @@ typedef struct {
typedef struct {
unsigned int max_request_field_size;
int stat_cache_engine;
const char *xattr_name;
unsigned int log_state_handling;
unsigned char log_request_header_on_error;
@ -321,7 +319,6 @@ typedef struct {
struct server {
void *plugin_slots;
struct stat_cache *stat_cache;
struct fdevents *ev;
int (* network_backend_write)(int fd, chunkqueue *cq, off_t max_bytes, log_error_st *errh);

View File

@ -588,9 +588,6 @@ static int config_insert_srvconf(server *srv) {
T_CONFIG_SCOPE_UNSET }
};
if (0 != stat_cache_choose_engine(srv, NULL)) /*(set initial default)*/
return HANDLER_ERROR;
int rc = 0;
plugin_data_base srvplug;
memset(&srvplug, 0, sizeof(srvplug));
@ -709,7 +706,7 @@ static int config_insert_srvconf(server *srv) {
rc = HANDLER_ERROR;
break;
case 29:/* mimetype.xattr-name */
srv->srvconf.xattr_name = cpv->v.b->ptr;
stat_cache_xattrname(cpv->v.b->ptr);
break;
case 30:/* ssl.engine */
ssl_enabled = (0 != cpv->v.u);
@ -1065,7 +1062,6 @@ void config_init(server *srv) {
srv->srvconf.high_precision_timestamps = 0;
srv->srvconf.max_request_field_size = 8192;
srv->srvconf.xattr_name = "Content-Type";
srv->srvconf.http_header_strict = 1;
srv->srvconf.http_host_strict = 1; /*(implies http_host_normalize)*/
srv->srvconf.http_host_normalize = 0;

View File

@ -284,14 +284,14 @@ static void connection_handle_errdoc(connection *con) {
buffer_append_int(con->physical.path, con->http_status);
buffer_append_string_len(con->physical.path, CONST_STR_LEN(".html"));
if (0 == http_chunk_append_file(con, con->physical.path)) {
stat_cache_entry *sce = NULL;
if (stat_cache_get_entry(con, con->physical.path, &sce)
!= HANDLER_ERROR) {
stat_cache_content_type_get(con, con->physical.path, sce);
stat_cache_entry *sce = stat_cache_get_entry(con->physical.path);
const buffer *content_type = (NULL != sce)
? stat_cache_content_type_get(con, sce)
: NULL;
if (content_type)
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE,
CONST_STR_LEN("Content-Type"),
CONST_BUF_LEN(sce->content_type));
}
CONST_BUF_LEN(content_type));
return;
}
}

View File

@ -172,7 +172,7 @@ int etag_create(buffer *etag, const struct stat *st, int flags) {
return 0;
}
int etag_mutate(buffer *mut, buffer *etag) {
int etag_mutate(buffer *mut, const buffer *etag) {
size_t i, len;
uint32_t h;

View File

@ -10,7 +10,7 @@ typedef enum { ETAG_USE_INODE = 1, ETAG_USE_MTIME = 2, ETAG_USE_SIZE = 4 } etag_
int etag_is_equal(const buffer *etag, const char *matches, int weak_ok);
int etag_create(buffer *etag, const struct stat *st, int flags);
int etag_mutate(buffer *mut, buffer *etag);
int etag_mutate(buffer *mut, const buffer *etag);
#endif

View File

@ -430,12 +430,12 @@ static int http_response_parse_range(connection *con, buffer *path, stat_cache_e
void http_response_send_file (connection *con, buffer *path) {
stat_cache_entry *sce = NULL;
stat_cache_entry * const sce = stat_cache_get_entry(path);
const buffer *mtime = NULL;
const buffer *vb;
int allow_caching = (0 == con->http_status || 200 == con->http_status);
if (HANDLER_ERROR == stat_cache_get_entry(con, path, &sce)) {
if (NULL == sce) {
con->http_status = (errno == ENOENT) ? 404 : 403;
log_error(con->conf.errh, __FILE__, __LINE__,
"not a regular file: %s -> %s", con->uri.path->ptr, path->ptr);
@ -443,7 +443,7 @@ void http_response_send_file (connection *con, buffer *path) {
}
if (!con->conf.follow_symlink
&& 0 != stat_cache_path_contains_symlink(con, path)) {
&& 0 != stat_cache_path_contains_symlink(path, con->conf.errh)) {
con->http_status = 403;
if (con->conf.log_request_handling) {
log_error(con->conf.errh, __FILE__, __LINE__,
@ -460,7 +460,7 @@ void http_response_send_file (connection *con, buffer *path) {
if (con->conf.log_file_not_found) {
log_error(con->conf.errh, __FILE__, __LINE__,
"not a regular file: %s -> %s",
con->uri.path->ptr, sce->name->ptr);
con->uri.path->ptr, path->ptr);
}
return;
}
@ -484,8 +484,8 @@ void http_response_send_file (connection *con, buffer *path) {
/* set response content-type, if not set already */
if (NULL == http_header_response_get(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"))) {
stat_cache_content_type_get(con, path, sce);
if (buffer_string_is_empty(sce->content_type)) {
const buffer *content_type = stat_cache_content_type_get(con, sce);
if (buffer_string_is_empty(content_type)) {
/* we are setting application/octet-stream, but also announce that
* this header field might change in the seconds few requests
*
@ -496,7 +496,7 @@ void http_response_send_file (connection *con, buffer *path) {
allow_caching = 0;
} else {
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(content_type));
}
}
@ -505,10 +505,13 @@ void http_response_send_file (connection *con, buffer *path) {
}
if (allow_caching) {
if (con->conf.etag_flags != 0 && !buffer_string_is_empty(stat_cache_etag_get(sce, con->conf.etag_flags))) {
const buffer *etag = (0 != con->conf.etag_flags)
? stat_cache_etag_get(sce, con->conf.etag_flags)
: NULL;
if (!buffer_string_is_empty(etag)) {
if (NULL == http_header_response_get(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"))) {
/* generate e-tag */
etag_mutate(con->physical.etag, sce->etag);
etag_mutate(con->physical.etag, etag);
http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
}
@ -722,7 +725,8 @@ static void http_response_xsendfile2(connection *con, const buffer *value, const
}
}
if (HANDLER_ERROR == stat_cache_get_entry(con, b, &sce)) {
sce = stat_cache_get_entry(b);
if (NULL == sce) {
log_error(con->conf.errh, __FILE__, __LINE__,
"send-file error: couldn't get stat_cache entry for "
"X-Sendfile2: %s", b->ptr);

View File

@ -56,7 +56,8 @@ static int http_chunk_len_append_tempfile(chunkqueue * const cq, uintmax_t len,
static int http_chunk_append_file_open_fstat(connection * const con, const buffer * const fn, struct stat * const st) {
return
(con->conf.follow_symlink || !stat_cache_path_contains_symlink(con, fn))
(con->conf.follow_symlink
|| !stat_cache_path_contains_symlink(fn, con->conf.errh))
? stat_cache_open_rdonly_fstat(fn, st, con->conf.follow_symlink)
: -1;
}

View File

@ -751,12 +751,10 @@ static int cgi_write_request(handler_ctx *hctx, int fd) {
return 0;
}
static struct stat * cgi_stat(connection *con, buffer *path) {
static const struct stat * cgi_stat(buffer *path) {
/* CGI might be executable even if it is not readable */
stat_cache_entry *sce;
return (HANDLER_ERROR != stat_cache_get_entry(con, path, &sce))
? &sce->st
: NULL;
const stat_cache_entry * const sce = stat_cache_get_entry(path);
return sce ? &sce->st : NULL;
}
static int cgi_create_env(connection *con, plugin_data *p, handler_ctx *hctx, buffer *cgi_handler) {
@ -767,7 +765,7 @@ static int cgi_create_env(connection *con, plugin_data *p, handler_ctx *hctx, bu
UNUSED(p);
if (!buffer_string_is_empty(cgi_handler)) {
if (NULL == cgi_stat(con, cgi_handler)) {
if (NULL == cgi_stat(cgi_handler)) {
log_perror(con->conf.errh, __FILE__, __LINE__,
"stat for cgi-handler %s", cgi_handler->ptr);
return -1;
@ -894,7 +892,7 @@ static int cgi_create_env(connection *con, plugin_data *p, handler_ctx *hctx, bu
URIHANDLER_FUNC(cgi_is_handled) {
plugin_data *p = p_d;
struct stat *st;
const struct stat *st;
data_string *ds;
if (con->mode != DIRECT) return HANDLER_GO_ON;
@ -906,7 +904,7 @@ URIHANDLER_FUNC(cgi_is_handled) {
ds = (data_string *)array_match_key_suffix(p->conf.cgi, con->physical.path);
if (NULL == ds) return HANDLER_GO_ON;
st = cgi_stat(con, con->physical.path);
st = cgi_stat(con->physical.path);
if (NULL == st) return HANDLER_GO_ON;
if (!S_ISREG(st->st_mode)) return HANDLER_GO_ON;

View File

@ -533,9 +533,11 @@ static int deflate_file_to_file(connection *con, plugin_data *p, int ifd, buffer
return -1;
}
buffer_append_string_buffer(p->ofn, sce->etag);
const buffer *etag = stat_cache_etag_get(sce, con->conf.etag_flags);
buffer_append_string_buffer(p->ofn, etag);
if (HANDLER_ERROR != stat_cache_get_entry(con, p->ofn, &sce_ofn)) {
sce_ofn = stat_cache_get_entry(p->ofn);
if (sce_ofn) {
if (0 == sce->st.st_size) return -1; /* cache file being created */
/* cache-entry exists */
#if 0
@ -791,7 +793,8 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
uint32_t m;
stat_cache_entry *sce = NULL;
const buffer *mtime = NULL;
buffer *content_type;
buffer *content_type_trunc;
const buffer *content_type;
if (con->mode != DIRECT || con->http_status) return HANDLER_GO_ON;
@ -816,7 +819,8 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
"-- handling file as static file");
}
if (HANDLER_ERROR == stat_cache_get_entry(con, con->physical.path, &sce)) {
sce = stat_cache_get_entry(con->physical.path);
if (NULL == sce) {
con->http_status = 403;
log_error(con->conf.errh, __FILE__, __LINE__,
"not a regular file: %s -> %s",
@ -840,28 +844,29 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
*/
if (sce->st.st_size < 128) return HANDLER_GO_ON;
stat_cache_etag_get(sce, con->conf.etag_flags);
const buffer *etag = stat_cache_etag_get(sce, con->conf.etag_flags);
if (buffer_string_is_empty(etag)) etag = NULL;
/* check if mimetype is in compress-config */
content_type = NULL;
stat_cache_content_type_get(con, con->physical.path, sce);
if (!buffer_is_empty(sce->content_type)) {
content_type_trunc = NULL;
content_type = stat_cache_content_type_get(con, sce);
if (!buffer_is_empty(content_type)) {
char *c;
if ( (c = strchr(sce->content_type->ptr, ';')) != NULL) {
content_type = con->srv->tmp_buf;
buffer_copy_string_len(content_type, sce->content_type->ptr, c - sce->content_type->ptr);
if ( (c = strchr(content_type->ptr, ';')) != NULL) {
content_type_trunc = con->srv->tmp_buf;
buffer_copy_string_len(content_type_trunc, content_type->ptr, c - content_type->ptr);
}
}
else {
content_type = con->srv->tmp_buf;
buffer_copy_string_len(content_type, CONST_STR_LEN(""));
content_type = content_type_trunc = con->srv->tmp_buf;
buffer_copy_string_len(content_type_trunc, CONST_STR_LEN(""));
}
for (m = 0; m < p->conf.compress->used; m++) {
data_string *compress_ds = (data_string *)p->conf.compress->data[m];
if (buffer_is_equal(&compress_ds->value, sce->content_type)
|| (content_type && buffer_is_equal(&compress_ds->value, content_type))) {
if (buffer_is_equal(&compress_ds->value, content_type)
|| (content_type_trunc && buffer_is_equal(&compress_ds->value, content_type_trunc))) {
break;
}
}
@ -884,7 +889,6 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
int accept_encoding = 0;
char *value = vb->ptr;
int matched_encodings = 0;
int use_etag = sce->etag != NULL && sce->etag->ptr != NULL;
/* get client side support encodings */
#ifdef USE_ZLIB
@ -913,7 +917,7 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
int compression_type = 0;
if (!con->conf.follow_symlink
&& 0 != stat_cache_path_contains_symlink(con, con->physical.path)) {
&& 0 != stat_cache_path_contains_symlink(con->physical.path, con->conf.errh)) {
return HANDLER_GO_ON;
}
@ -927,10 +931,10 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
mtime = strftime_cache_get(con->srv, sce->st.st_mtime);
/* try matching original etag of uncompressed version */
if (use_etag) {
etag_mutate(con->physical.etag, sce->etag);
if (etag) {
etag_mutate(con->physical.etag, etag);
if (HANDLER_FINISHED == http_response_handle_cachable(con, mtime)) {
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(content_type));
http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
close(fd);
@ -957,10 +961,10 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
compression_name = dflt_deflate;
}
if (use_etag) {
if (etag) {
/* try matching etag of compressed version */
buffer * const tb = con->srv->tmp_buf;
buffer_copy_buffer(tb, sce->etag);
buffer_copy_buffer(tb, etag);
buffer_append_string_len(tb, CONST_STR_LEN("-"));
buffer_append_string(tb, compression_name);
etag_mutate(con->physical.etag, tb);
@ -968,9 +972,9 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
if (HANDLER_FINISHED == http_response_handle_cachable(con, mtime)) {
http_header_response_set(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(content_type));
http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
if (use_etag) {
if (etag) {
http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
}
close(fd);
@ -978,7 +982,7 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
}
/* deflate it */
if (use_etag && !buffer_string_is_empty(p->conf.compress_cache_dir)) {
if (etag && !buffer_string_is_empty(p->conf.compress_cache_dir)) {
if (0 != deflate_file_to_file(con, p, fd, con->physical.path, sce, compression_type)) {
close(fd);
return HANDLER_GO_ON;
@ -992,12 +996,12 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
close(fd);
http_header_response_set(con, HTTP_HEADER_CONTENT_ENCODING, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
http_header_response_set(con, HTTP_HEADER_LAST_MODIFIED, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
if (use_etag) {
if (etag) {
http_header_response_set(con, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
}
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
http_header_response_set(con, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(content_type));
/* let mod_staticfile handle the cached compressed files, physical path was modified */
return (use_etag && !buffer_string_is_empty(p->conf.compress_cache_dir)) ? HANDLER_GO_ON : HANDLER_FINISHED;
return (etag && !buffer_string_is_empty(p->conf.compress_cache_dir)) ? HANDLER_GO_ON : HANDLER_FINISHED;
}
}
}

View File

@ -25,14 +25,6 @@
* this is a dirlisting for a lighttpd plugin
*/
#ifdef HAVE_ATTR_ATTRIBUTES_H
#include <attr/attributes.h>
#endif
#ifdef HAVE_SYS_EXTATTR_H
#include <sys/extattr.h>
#endif
typedef struct {
char dir_listing;
char hide_dot_files;
@ -835,13 +827,9 @@ static int http_list_directory(connection *con, plugin_data *p, buffer *dir) {
dirls_entry_t *tmp;
char sizebuf[sizeof("999.9K")];
char datebuf[sizeof("2005-Jan-01 22:23:24")];
const char *content_type;
const buffer *content_type;
long name_max;
log_error_st * const errh = con->conf.errh;
#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR)
char attrval[128];
int attrlen;
#endif
#ifdef HAVE_LOCALTIME_R
struct tm tm;
#endif
@ -974,32 +962,24 @@ static int http_list_directory(connection *con, plugin_data *p, buffer *dir) {
}
/* files */
const array * const mimetypes = con->conf.mimetypes;
for (i = 0; i < files.used; i++) {
tmp = files.ent[i];
#if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) /*(pass full path)*/
content_type = NULL;
#if defined(HAVE_XATTR)
if (con->conf.use_xattr) {
memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
attrlen = sizeof(attrval) - 1;
if (attr_get(path, con->srv->srvconf.xattr_name, attrval, &attrlen, 0) == 0) {
attrval[attrlen] = '\0';
content_type = attrval;
}
content_type = stat_cache_mimetype_by_xattr(path);
}
#elif defined(HAVE_EXTATTR)
if (con->conf.use_xattr) {
memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
if(-1 != (attrlen = extattr_get_file(path, EXTATTR_NAMESPACE_USER, con->srv->srvconf.xattr_name, attrval, sizeof(attrval)-1))) {
attrval[attrlen] = '\0';
content_type = attrval;
}
}
#endif
if (content_type == NULL) {
const buffer *type = stat_cache_mimetype_by_ext(con, DIRLIST_ENT_NAME(tmp), tmp->namelen);
content_type = NULL != type ? type->ptr : "application/octet-stream";
if (NULL == content_type)
#endif
content_type = stat_cache_mimetype_by_ext(mimetypes, DIRLIST_ENT_NAME(tmp), tmp->namelen);
if (NULL == content_type) {
static const buffer octet_stream =
{ "application/octet-stream",
sizeof("application/octet-stream"), 0 };
content_type = &octet_stream;
}
#ifdef HAVE_LOCALTIME_R
@ -1019,7 +999,7 @@ static int http_list_directory(connection *con, plugin_data *p, buffer *dir) {
buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"s\">"));
buffer_append_string(out, sizebuf);
buffer_append_string_len(out, CONST_STR_LEN("</td><td class=\"t\">"));
buffer_append_string(out, content_type);
buffer_append_string_buffer(out, content_type);
buffer_append_string_len(out, CONST_STR_LEN("</td></tr>\n"));
free(tmp);
@ -1078,7 +1058,8 @@ URIHANDLER_FUNC(mod_dirlisting_subrequest) {
"URI : %s", con->uri.path->ptr);
}
if (HANDLER_ERROR == stat_cache_get_entry(con, con->physical.path, &sce)) {
sce = stat_cache_get_entry(con->physical.path);
if (NULL == sce) {
log_error(con->conf.errh, __FILE__, __LINE__,
"stat_cache_get_entry failed: %s", con->physical.path->ptr);
con->http_status = 500;

View File

@ -338,7 +338,8 @@ static handler_t mod_evhost_uri_handler(connection *con, void *p_d) {
buffer * const b = &p->tmp_buf;
mod_evhost_build_doc_root_path(b, &p->split_vals, con->uri.authority, p->conf.path_pieces);
if (HANDLER_ERROR == stat_cache_get_entry(con, b, &sce)) {
sce = stat_cache_get_entry(b);
if (NULL == sce) {
log_perror(con->conf.errh, __FILE__, __LINE__, "%s", b->ptr);
} else if(!S_ISDIR(sce->st.st_mode)) {
log_error(con->conf.errh, __FILE__, __LINE__, "not a directory: %s", b->ptr);

View File

@ -318,8 +318,7 @@ CONNECTION_FUNC(mod_expire_handler) {
case 1:
/* modification */
/* if stat fails => sce == NULL, ignore return value */
(void) stat_cache_get_entry(con, con->physical.path, &sce);
sce = stat_cache_get_entry(con->physical.path);
/* can't set modification based expire header if
* mtime is not available

View File

@ -133,8 +133,8 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) {
}
buffer_append_string_buffer(b, &ds->value);
stat_cache_entry *sce = NULL;
if (HANDLER_ERROR == stat_cache_get_entry(con, b, &sce)) {
stat_cache_entry * const sce = stat_cache_get_entry(b);
if (NULL == sce) {
if (errno == EACCES) {
con->http_status = 403;
buffer_reset(con->physical.path);

View File

@ -288,24 +288,14 @@ static int magnet_print(lua_State *L) {
}
static int magnet_stat(lua_State *L) {
connection *con = magnet_get_connection(L);
stat_cache_entry *sce = NULL;
{
buffer *sb = magnet_checkbuffer(L, 1);
handler_t res;
res = stat_cache_get_entry(con, sb, &sce);
if (HANDLER_GO_ON != res) {
buffer_free(sb);
buffer * const sb = magnet_checkbuffer(L, 1);
stat_cache_entry * const sce = stat_cache_get_entry(sb);
buffer_free(sb);
if (NULL == sce) {
lua_pushnil(L);
return 1;
}
stat_cache_content_type_get(con, sb, sce);
buffer_free(sb);
}
lua_newtable(L); // return value
lua_pushboolean(L, S_ISREG(sce->st.st_mode));
@ -350,18 +340,21 @@ static int magnet_stat(lua_State *L) {
lua_pushinteger(L, sce->st.st_ino);
lua_setfield(L, -2, "st_ino");
if (!buffer_string_is_empty(stat_cache_etag_get(sce, con->conf.etag_flags))) {
connection * const con = magnet_get_connection(L);
const buffer *etag = stat_cache_etag_get(sce, con->conf.etag_flags);
if (!buffer_string_is_empty(etag)) {
/* we have to mutate the etag */
buffer * const tb = con->srv->tmp_buf;
etag_mutate(tb, sce->etag);
etag_mutate(tb, etag);
lua_pushlstring(L, CONST_BUF_LEN(tb));
} else {
lua_pushnil(L);
}
lua_setfield(L, -2, "etag");
if (!buffer_string_is_empty(sce->content_type)) {
lua_pushlstring(L, CONST_BUF_LEN(sce->content_type));
const buffer *content_type = stat_cache_content_type_get(con, sce);
if (!buffer_string_is_empty(content_type)) {
lua_pushlstring(L, CONST_BUF_LEN(content_type));
} else {
lua_pushnil(L);
}
@ -774,7 +767,7 @@ static handler_t magnet_attract(connection *con, plugin_data *p, buffer *name) {
const int lighty_table_ndx = 2;
/* get the script-context */
L = script_cache_get_script(con, &p->cache, name);
L = script_cache_get_script(&p->cache, name, con->conf.etag_flags);
if (lua_isstring(L, -1)) {
log_error(con->conf.errh, __FILE__, __LINE__,

View File

@ -1,7 +1,7 @@
#include "first.h"
#include "mod_magnet_cache.h"
#include "base.h"
#include "log.h"
#include "stat_cache.h"
#include <stdlib.h>
@ -53,29 +53,29 @@ void script_cache_free_data(script_cache *p) {
free(p->ptr);
}
lua_State *script_cache_get_script(connection *con, script_cache *cache, buffer *name) {
size_t i;
lua_State *script_cache_get_script(script_cache *cache, buffer *name, int etag_flags) {
script *sc = NULL;
stat_cache_entry *sce;
for (i = 0; i < cache->used; i++) {
for (uint32_t i = 0; i < cache->used; ++i, sc = NULL) {
sc = cache->ptr[i];
if (!buffer_is_equal(name, sc->name)) continue;
if (buffer_is_equal(name, sc->name)) {
sc->last_used = time(NULL);
sc->last_used = log_epoch_secs;
/* oops, the script failed last time */
if (lua_gettop(sc->L) == 0) break;
force_assert(lua_gettop(sc->L) == 1);
if (HANDLER_ERROR == stat_cache_get_entry(con, sc->name, &sce)) {
sce = stat_cache_get_entry(sc->name);
if (NULL == sce) {
lua_pop(sc->L, 1); /* pop the old function */
break;
}
stat_cache_etag_get(sce, con->conf.etag_flags);
if (!buffer_is_equal(sce->etag, sc->etag)) {
const buffer *etag = stat_cache_etag_get(sce, etag_flags);
if (NULL == etag || !buffer_is_equal(sc->etag, etag)) {
/* the etag is outdated, reload the function */
lua_pop(sc->L, 1);
break;
@ -84,9 +84,6 @@ lua_State *script_cache_get_script(connection *con, script_cache *cache, buffer
force_assert(lua_isfunction(sc->L, -1));
return sc->L;
}
sc = NULL;
}
/* if the script was script already loaded but either got changed or
@ -107,15 +104,16 @@ lua_State *script_cache_get_script(connection *con, script_cache *cache, buffer
luaL_openlibs(sc->L);
}
sc->last_used = time(NULL);
sc->last_used = log_epoch_secs;
if (0 != luaL_loadfile(sc->L, name->ptr)) {
/* oops, an error, return it */
return sc->L;
}
if (HANDLER_GO_ON == stat_cache_get_entry(con, sc->name, &sce)) {
buffer_copy_buffer(sc->etag, stat_cache_etag_get(sce, con->conf.etag_flags));
sce = stat_cache_get_entry(sc->name);
if (sce) {
buffer_copy_buffer(sc->etag, stat_cache_etag_get(sce, etag_flags));
}
force_assert(lua_isfunction(sc->L, -1));

View File

@ -18,14 +18,13 @@ typedef struct {
typedef struct {
script **ptr;
size_t used;
size_t size;
uint32_t used;
uint32_t size;
} script_cache;
script_cache *script_cache_init(void);
void script_cache_free_data(script_cache *cache);
lua_State *script_cache_get_script(connection *con, script_cache *cache, buffer *name);
lua_State *script_cache_get_script(script_cache *cache, buffer *name, int etag_flags);
#endif

View File

@ -324,7 +324,8 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
buffer_copy_string(b, row[0]);
buffer_append_slash(b);
if (HANDLER_ERROR == stat_cache_get_entry(con, b, &sce)) {
sce = stat_cache_get_entry(b);
if (NULL == sce) {
log_perror(con->conf.errh, __FILE__, __LINE__, "%s", b->ptr);
goto ERR500;
}

View File

@ -334,10 +334,8 @@ URIHANDLER_FUNC(mod_rewrite_physical) {
if (!p->conf.rewrite_NF || !p->conf.rewrite_NF->used) return HANDLER_GO_ON;
/* skip if physical.path is a regular file */
stat_cache_entry *sce;
if (HANDLER_ERROR != stat_cache_get_entry(con, con->physical.path, &sce)) {
if (S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
}
stat_cache_entry *sce = stat_cache_get_entry(con->physical.path);
if (sce && S_ISREG(sce->st.st_mode)) return HANDLER_GO_ON;
return process_rewrite_rules(con, p, p->conf.rewrite_NF);
}

View File

@ -158,7 +158,8 @@ static int build_doc_root(connection *con, plugin_data *p, buffer *out, const bu
/* one-element cache (postive cache, not negative cache) */
if (buffer_is_equal(out, &p->last_root)) return 1;
if (HANDLER_ERROR == stat_cache_get_entry(con, out, &sce)) {
sce = stat_cache_get_entry(out);
if (NULL == sce) {
if (p->conf.debug) {
log_perror(con->conf.errh, __FILE__, __LINE__, "%s", out->ptr);
}

View File

@ -605,7 +605,7 @@ static int process_ssi_stmt(connection *con, handler_ctx *p, const char **l, siz
}
if (!con->conf.follow_symlink
&& 0 != stat_cache_path_contains_symlink(con, p->stat_fn)) {
&& 0 != stat_cache_path_contains_symlink(p->stat_fn, con->conf.errh)) {
break;
}

View File

@ -190,7 +190,8 @@ CONNECTION_FUNC(mod_vhostdb_handle_docroot) {
/* sanity check that really is a directory */
buffer_append_slash(b);
if (HANDLER_ERROR == stat_cache_get_entry(con, b, &sce)) {
sce = stat_cache_get_entry(b);
if (NULL == sce) {
log_perror(con->conf.errh, __FILE__, __LINE__, "%s", b->ptr);
return mod_vhostdb_error_500(con); /* HANDLER_FINISHED */
}

View File

@ -312,7 +312,6 @@ typedef struct {
unsigned short deprecated_unsafe_partial_put_compat;
sql_config *sql;
server *srv;
buffer *tmpb;
buffer *sqlite_db_name; /* not used after worker init */
array *opts;
@ -497,7 +496,6 @@ SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
}
}
p->defaults.srv = srv;
p->defaults.tmpb = srv->tmp_buf;
/* initialize p->defaults from global config context */
@ -2170,27 +2168,25 @@ webdav_if_match_or_unmodified_since (connection * const con, struct stat *st)
static void
webdav_response_etag (const plugin_config * const pconf,
connection * const con, struct stat *st)
webdav_response_etag (connection * const con, struct stat *st)
{
server *srv = pconf->srv;
if (0 != con->conf.etag_flags) {
buffer *etagb = con->physical.etag;
etag_create(etagb, st, con->conf.etag_flags);
stat_cache_update_entry(srv,CONST_BUF_LEN(con->physical.path),st,etagb);
stat_cache_update_entry(CONST_BUF_LEN(con->physical.path), st, etagb);
etag_mutate(etagb, etagb);
http_header_response_set(con, HTTP_HEADER_ETAG,
CONST_STR_LEN("ETag"),
CONST_BUF_LEN(etagb));
}
else {
stat_cache_update_entry(srv,CONST_BUF_LEN(con->physical.path),st,NULL);
stat_cache_update_entry(CONST_BUF_LEN(con->physical.path), st, NULL);
}
}
static void
webdav_parent_modified (const plugin_config * const pconf, const buffer *path)
webdav_parent_modified (const buffer *path)
{
size_t dirlen = buffer_string_length(path);
const char *fn = path->ptr;
@ -2199,7 +2195,7 @@ webdav_parent_modified (const plugin_config * const pconf, const buffer *path)
if (fn[dirlen-1] == '/') --dirlen;
if (0 != dirlen) while (fn[--dirlen] != '/') ;
if (0 == dirlen) dirlen = 1; /* root dir ("/") */
stat_cache_invalidate_entry(pconf->srv, fn, dirlen);
stat_cache_invalidate_entry(fn, dirlen);
}
@ -2229,7 +2225,7 @@ webdav_unlinkat (const plugin_config * const pconf, const buffer * const uri,
const int dfd, const char * const d_name, size_t len)
{
if (0 == unlinkat(dfd, d_name, 0)) {
stat_cache_delete_entry(pconf->srv, d_name, len);
stat_cache_delete_entry(d_name, len);
return webdav_prop_delete_uri(pconf, uri);
}
@ -2246,7 +2242,7 @@ webdav_delete_file (const plugin_config * const pconf,
const physical_st * const dst)
{
if (0 == unlink(dst->path->ptr)) {
stat_cache_delete_entry(pconf->srv, CONST_BUF_LEN(dst->path));
stat_cache_delete_entry(CONST_BUF_LEN(dst->path));
return webdav_prop_delete_uri(pconf, dst->rel_path);
}
@ -2448,7 +2444,7 @@ webdav_copytmp_rename (const plugin_config * const pconf,
{
/* unconditional stat cache deletion
* (not worth extra syscall/race to detect overwritten or not) */
stat_cache_delete_entry(pconf->srv, CONST_BUF_LEN(dst->path));
stat_cache_delete_entry(CONST_BUF_LEN(dst->path));
return 0;
}
else {
@ -2501,8 +2497,8 @@ webdav_copymove_file (const plugin_config * const pconf,
if (overwrite) unlink(src->path->ptr);
/* unconditional stat cache deletion
* (not worth extra syscall/race to detect overwritten or not) */
stat_cache_delete_entry(pconf->srv, CONST_BUF_LEN(dst->path));
stat_cache_delete_entry(pconf->srv, CONST_BUF_LEN(src->path));
stat_cache_delete_entry(CONST_BUF_LEN(dst->path));
stat_cache_delete_entry(CONST_BUF_LEN(src->path));
webdav_prop_move_uri(pconf, src->rel_path, dst->rel_path);
return 0;
}
@ -2546,7 +2542,7 @@ webdav_mkdir (const plugin_config * const pconf,
const int overwrite)
{
if (0 == mkdir(dst->path->ptr, WEBDAV_DIR_MODE)) {
webdav_parent_modified(pconf, dst->path);
webdav_parent_modified(dst->path);
return 0;
}
@ -2594,7 +2590,7 @@ webdav_mkdir (const plugin_config * const pconf,
if (0 != status)
return status;
webdav_parent_modified(pconf, dst->path);
webdav_parent_modified(dst->path);
return (0 == mkdir(dst->path->ptr, WEBDAV_DIR_MODE))
? 0
: 409; /* Conflict */
@ -3026,8 +3022,9 @@ webdav_propfind_live_props (const webdav_propfind_bufs * const restrict pb,
else {
/* provide content type by extension
* Note: not currently supporting filesystem xattr */
const array * const mtypes = pb->con->conf.mimetypes;
const buffer *ct =
stat_cache_mimetype_by_ext(pb->con, CONST_BUF_LEN(pb->dst->path));
stat_cache_mimetype_by_ext(mtypes, CONST_BUF_LEN(pb->dst->path));
if (NULL != ct) {
buffer_append_string_len(b, CONST_STR_LEN(
"<D:getcontenttype>"));
@ -4047,7 +4044,7 @@ mod_webdav_delete (connection * const con, const plugin_config * const pconf)
buffer_free(ms);
/* invalidate stat cache of src if DELETE, whether or not successful */
stat_cache_delete_dir(pconf->srv, CONST_BUF_LEN(con->physical.path));
stat_cache_delete_dir(CONST_BUF_LEN(con->physical.path));
}
else if (con->physical.path->ptr[con->physical.path->used - 2] == '/')
http_status_set_error(con, 403);
@ -4191,10 +4188,10 @@ mod_webdav_put_0 (connection * const con, const plugin_config * const pconf)
if (0 != con->conf.etag_flags) {
/*(skip sending etag if fstat() error; not expected)*/
struct stat st;
if (0 == fstat(fd, &st)) webdav_response_etag(pconf, con, &st);
if (0 == fstat(fd, &st)) webdav_response_etag(con, &st);
}
close(fd);
webdav_parent_modified(pconf, con->physical.path);
webdav_parent_modified(con->physical.path);
http_status_set_fin(con, 201); /* Created */
return HANDLER_FINISHED;
}
@ -4311,7 +4308,6 @@ mod_webdav_put_prep (connection * const con, const plugin_config * const pconf)
#if (defined(__linux__) || defined(__CYGWIN__)) && defined(O_TMPFILE)
static int
mod_webdav_put_linkat_rename (connection * const con,
const plugin_config * const pconf,
const char * const pathtemp)
{
chunkqueue * const cq = con->request_content_queue;
@ -4336,7 +4332,7 @@ mod_webdav_put_linkat_rename (connection * const con,
? 204 /* No Content */
: 201); /* Created */
if (201 == http_status_get(con))
webdav_parent_modified(pconf, con->physical.path);
webdav_parent_modified(con->physical.path);
if (0 != rename(pathtemp, con->physical.path->ptr))
#endif
{
@ -4351,7 +4347,7 @@ mod_webdav_put_linkat_rename (connection * const con,
&& http_status_get(con) < 300) { /*(201, 204)*/
/*(skip sending etag if fstat() error; not expected)*/
if (0 == fstat(c->file.fd, &st))
webdav_response_etag(pconf, con, &st);
webdav_response_etag(con, &st);
}
chunkqueue_mark_written(cq, c->file.length);
@ -4366,7 +4362,6 @@ mod_webdav_put_linkat_rename (connection * const con,
__attribute_cold__
static handler_t
mod_webdav_put_deprecated_unsafe_partial_put_compat (connection * const con,
const plugin_config *pconf,
const buffer * const h)
{
/* historical code performed very limited range parse (repeated here) */
@ -4416,7 +4411,7 @@ mod_webdav_put_deprecated_unsafe_partial_put_compat (connection * const con,
if (!http_status_is_set(con)) {
http_status_set_fin(con, 204); /* No Content */
if (0 != con->conf.etag_flags) webdav_response_etag(pconf, con, &st);
if (0 != con->conf.etag_flags) webdav_response_etag(con, &st);
}
return HANDLER_FINISHED;
@ -4450,7 +4445,7 @@ mod_webdav_put (connection * const con, const plugin_config * const pconf)
CONST_STR_LEN("Content-Range"));
if (NULL != h)
return
mod_webdav_put_deprecated_unsafe_partial_put_compat(con,pconf,h);
mod_webdav_put_deprecated_unsafe_partial_put_compat(con, h);
}
/* construct temporary filename in same directory as target
@ -4499,7 +4494,7 @@ mod_webdav_put (connection * const con, const plugin_config * const pconf)
if (!mod_webdav_write_single_file_chunk(con, cq))
return HANDLER_FINISHED;
}
if (mod_webdav_put_linkat_rename(con, pconf, pathtemp))
if (mod_webdav_put_linkat_rename(con, pathtemp))
return HANDLER_FINISHED;
/* attempt traditional copy (below) if linkat() failed for any reason */
}
@ -4535,9 +4530,9 @@ mod_webdav_put (connection * const con, const plugin_config * const pconf)
? 204 /* No Content */
: 201); /* Created */
if (201 == http_status_get(con))
webdav_parent_modified(pconf, con->physical.path);
webdav_parent_modified(con->physical.path);
if (0 == rename(pathtemp, con->physical.path->ptr)) {
if (0 != con->conf.etag_flags) webdav_response_etag(pconf,con,&st);
if (0 != con->conf.etag_flags) webdav_response_etag(con, &st);
}
else {
if (errno == EISDIR)
@ -4833,7 +4828,7 @@ mod_webdav_copymove_b (connection * const con, const plugin_config * const pconf
buffer_free(ms);
/* invalidate stat cache of src if MOVE, whether or not successful */
if (con->request.http_method == HTTP_METHOD_MOVE)
stat_cache_delete_dir(pconf->srv,CONST_BUF_LEN(con->physical.path));
stat_cache_delete_dir(CONST_BUF_LEN(con->physical.path));
return HANDLER_FINISHED;
}
else if (con->physical.path->ptr[con->physical.path->used - 2] == '/') {
@ -4891,7 +4886,7 @@ mod_webdav_copymove_b (connection * const con, const plugin_config * const pconf
*slash = '/';
/* new entity will be created */
if (!http_status_is_set(con)) {
webdav_parent_modified(pconf, dst_path);
webdav_parent_modified(dst_path);
http_status_set_fin(con, 201); /* Created */
}
break;
@ -5364,7 +5359,7 @@ mod_webdav_lock (connection * const con, const plugin_config * const pconf)
if (0 != fstat(fd, &st)) con->conf.etag_flags = 0;
close(fd);
created = 1;
webdav_parent_modified(pconf, con->physical.path);
webdav_parent_modified(con->physical.path);
}
else if (errno != EEXIST) {
http_status_set_error(con, 403); /* Forbidden */
@ -5423,7 +5418,7 @@ mod_webdav_lock (connection * const con, const plugin_config * const pconf)
lockstr, sizeof(lockstr)-1);
webdav_xml_doc_lock_acquired(con, pconf, &lockdata);
if (0 != con->conf.etag_flags && !S_ISDIR(st.st_mode))
webdav_response_etag(pconf, con, &st);
webdav_response_etag(con, &st);
http_status_set_fin(con, created ? 201 : 200); /* Created | OK */
}
else /*(database error obtaining lock)*/

View File

@ -133,9 +133,9 @@ int http_response_write_header(connection *con) {
}
static handler_t http_response_physical_path_check(connection *con) {
stat_cache_entry *sce = NULL;
stat_cache_entry *sce = stat_cache_get_entry(con->physical.path);
if (HANDLER_ERROR != stat_cache_get_entry(con, con->physical.path, &sce)) {
if (sce) {
/* file exists */
} else {
char *pathinfo = NULL;
@ -204,9 +204,9 @@ static handler_t http_response_physical_path_check(connection *con) {
buffer * const tb = con->srv->tmp_buf;
for (char *pprev = pathinfo; pathinfo; pprev = pathinfo, pathinfo = strchr(pathinfo+1, '/')) {
stat_cache_entry *nsce = NULL;
buffer_copy_string_len(tb, con->physical.path->ptr, pathinfo - con->physical.path->ptr);
if (HANDLER_ERROR == stat_cache_get_entry(con, tb, &nsce)) {
stat_cache_entry *nsce = stat_cache_get_entry(tb);
if (NULL == nsce) {
pathinfo = pathinfo != pprev ? pprev : NULL;
break;
}
@ -254,7 +254,7 @@ static handler_t http_response_physical_path_check(connection *con) {
}
if (!con->conf.follow_symlink
&& 0 != stat_cache_path_contains_symlink(con, con->physical.path)) {
&& 0 != stat_cache_path_contains_symlink(con->physical.path, con->conf.errh)) {
con->http_status = 403;
if (con->conf.log_request_handling) {

View File

@ -285,9 +285,7 @@ static void server_free(server *srv) {
free(srv->joblist.ptr);
free(srv->fdwaitqueue.ptr);
if (srv->stat_cache) {
stat_cache_free(srv->stat_cache);
}
stat_cache_free();
li_rand_cleanup();
chunkqueue_chunk_pool_free();
@ -1541,7 +1539,7 @@ static int server_main (server * const srv, int argc, char **argv) {
}
/* might fail if user is using fam (not gamin) and famd isn't running */
if (NULL == (srv->stat_cache = stat_cache_init(srv))) {
if (!stat_cache_init(srv)) {
log_error(srv->errh, __FILE__, __LINE__,
"stat-cache could not be setup, dieing.");
return -1;
@ -1646,7 +1644,7 @@ static void server_handle_sigalrm (server * const srv, time_t min_ts, time_t las
/* free excess chunkqueue buffers every 64 seconds */
if (0 == (min_ts & 0x3f)) chunkqueue_chunk_pool_clear();
/* cleanup stat-cache */
stat_cache_trigger_cleanup(srv);
stat_cache_trigger_cleanup();
/* reset global/aggregate rate limit counters */
config_reset_config_bytes_sec(srv->config_data_base);
/* if graceful_shutdown, accelerate cleanup of recently completed request/responses */

View File

@ -38,19 +38,22 @@
*/
enum {
STAT_CACHE_ENGINE_UNSET,
STAT_CACHE_ENGINE_SIMPLE, /*(default)*/
STAT_CACHE_ENGINE_NONE,
STAT_CACHE_ENGINE_SIMPLE,
STAT_CACHE_ENGINE_FAM
};
struct stat_cache_fam; /* declaration */
typedef struct stat_cache {
int stat_cache_engine;
splay_tree *files; /* nodes of tree are (stat_cache_entry *) */
struct stat_cache_fam *scf;
log_error_st *errh;
} stat_cache;
static stat_cache sc;
/* the famous DJB hash function for strings */
__attribute_pure__
@ -206,10 +209,10 @@ static void fam_dir_tag_refcnt(splay_tree *t, int *keys, int *ndx)
}
}
static void fam_dir_periodic_cleanup(server *srv) {
static void fam_dir_periodic_cleanup() {
int max_ndx, i;
int keys[8192]; /* 32k size on stack */
stat_cache_fam * const scf = srv->stat_cache->scf;
stat_cache_fam * const scf = sc.scf;
do {
if (!scf->dirs) return;
max_ndx = 0;
@ -241,10 +244,10 @@ static void fam_dir_invalidate_tree(splay_tree *t, const char *name, size_t len)
}
/* declarations */
static void stat_cache_delete_tree(server *srv, const char *name, size_t len);
static void stat_cache_invalidate_dir_tree(server *srv, const char *name, size_t len);
static void stat_cache_delete_tree(const char *name, size_t len);
static void stat_cache_invalidate_dir_tree(const char *name, size_t len);
static void stat_cache_handle_fdevent_in(server *srv, stat_cache_fam *scf)
static void stat_cache_handle_fdevent_in(stat_cache_fam *scf)
{
for (int i = 0, ndx; i || (i = FAMPending(&scf->fam)) > 0; --i) {
FAMEvent fe;
@ -290,7 +293,7 @@ static void stat_cache_handle_fdevent_in(server *srv, stat_cache_fam *scf)
buffer_append_string_len(n, CONST_STR_LEN("/"));
buffer_append_string_len(n,fe.filename,strlen(fe.filename));
/* (alternatively, could chose to stat() and update)*/
stat_cache_invalidate_entry(srv, CONST_BUF_LEN(n));
stat_cache_invalidate_entry(CONST_BUF_LEN(n));