[multiple] stat_cache singleton
parent
b5775b9951
commit
68d8d4c532
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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__,
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
@ -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)*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
503
src/stat_cache.c
503
src/stat_cache.c
|
@ -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));
|
||||
|
||||