Browse Source

dropped file-cache, added stat-cache and modules ALWAYS cleanup at connection-end

git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x@502 152afb58-edef-0310-8abb-c4023f1b3aa9
svn/tags/lighttpd-1.4.2
Jan Kneschke 17 years ago
parent
commit
5e134da075
  1. 18
      src/Makefile.am
  2. 65
      src/base.h
  3. 21
      src/config.c
  4. 27
      src/connections.c
  5. 483
      src/file_cache.c
  6. 12
      src/file_cache.h
  7. 46
      src/mod_compress.c
  8. 7
      src/mod_evhost.c
  9. 8
      src/mod_expire.c
  10. 44
      src/mod_fastcgi.c
  11. 8
      src/mod_mysql_vhost.c
  12. 57
      src/mod_proxy.c
  13. 10
      src/mod_simple_vhost.c
  14. 12
      src/mod_ssi.c
  15. 1
      src/network.c
  16. 28
      src/network_freebsd_sendfile.c
  17. 77
      src/network_linux_sendfile.c
  18. 37
      src/network_openssl.c
  19. 65
      src/network_write.c
  20. 89
      src/network_writev.c
  21. 29
      src/response.c
  22. 22
      src/server.c
  23. 213
      src/splaytree.c
  24. 17
      src/splaytree.h
  25. 498
      src/stat_cache.c
  26. 13
      src/stat_cache.h

18
src/Makefile.am

@ -30,7 +30,7 @@ mod_ssi_expr.c: mod_ssi_exprparser.h
common_src=buffer.c log.c \
keyvalue.c chunk.c \
http_chunk.c stream.c fdevent.c \
file_cache.c plugin.c joblist.c etag.c array.c \
stat_cache.c plugin.c joblist.c etag.c array.c \
data_string.c data_count.c data_array.c \
data_integer.c md5.c data_fastcgi.c \
fdevent_select.c fdevent_linux_rtsig.c \
@ -40,7 +40,8 @@ common_src=buffer.c log.c \
inet_ntop_cache.c crc32.c \
connections-glue.c \
configfile-glue.c \
http-header-glue.c
http-header-glue.c \
splaytree.c
src = server.c response.c connections.c network.c \
network_write.c network_linux_sendfile.c \
@ -59,9 +60,9 @@ if NO_RDYNAMIC
# everything
lib_LTLIBRARIES += liblightcomp.la
liblightcomp_la_SOURCES=$(common_src)
liblightcomp_la_CFLAGS=$(AM_CFLAGS)
liblightcomp_la_CFLAGS=$(AM_CFLAGS) $(FAM_CFLAGS)
liblightcomp_la_LDFLAGS = -avoid-version -no-undefined
liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB)
liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS)
common_libadd = liblightcomp.la
else
src += $(common_src)
@ -199,20 +200,21 @@ hdr = server.h buffer.h network.h log.h keyvalue.h \
response.h request.h fastcgi.h chunk.h \
settings.h http_chunk.h http_auth_digest.h \
md5.h md5_global.h http_auth.h stream.h \
fdevent.h connections.h base.h file_cache.h \
fdevent.h connections.h base.h stat_cache.h \
plugin.h mod_auth.h \
etag.h joblist.h array.h crc32.h \
network_backends.h configfile.h bitset.h \
mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
configparser.h mod_ssi_exprparser.h \
sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h
sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
splaytree.h
DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
lighttpd_SOURCES = $(src)
lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB)
lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS)
lighttpd_LDFLAGS = -export-dynamic
lighttpd_CCPFLAGS = $(MYSQL_INCLUDES)
lighttpd_CCPFLAGS = $(MYSQL_INCLUDES) $(FAM_CFLAGS)
array_SOURCES = array.c buffer.c data_string.c data_count.c
array_CPPFLAGS= -DDEBUG_ARRAY

65
src/base.h

@ -22,6 +22,7 @@
#include "settings.h"
#include "fdevent.h"
#include "sys-socket.h"
#include "splaytree.h"
#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
@ -29,6 +30,10 @@
# include <openssl/ssl.h>
#endif
#ifdef HAVE_FAM_H
# include <fam.h>
#endif
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
@ -167,26 +172,6 @@ typedef struct {
} transfer_encoding;
} response;
typedef struct {
buffer *name;
buffer *etag;
struct stat st;
int fd;
int fde_ndx;
char *mmap_p;
size_t mmap_length;
off_t mmap_offset;
size_t in_use;
size_t is_dirty;
time_t stat_ts;
buffer *content_type;
} file_cache_entry;
typedef struct {
buffer *scheme;
buffer *authority;
@ -205,13 +190,32 @@ typedef struct {
} physical;
typedef struct {
file_cache_entry **ptr;
buffer *name;
buffer *etag;
size_t size;
size_t used;
struct stat st;
time_t stat_ts;
buffer *dir_name;
} file_cache;
#ifdef HAVE_FAM_H
int dir_version;
int dir_ndx;
#endif
buffer *content_type;
} stat_cache_entry;
typedef struct {
splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
buffer *dir_name; /* for building the dirname from the filename */
#ifdef HAVE_FAM_H
splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
FAMConnection *fam;
int fam_fcce_ndx;
#endif
} stat_cache;
typedef struct {
array *indexfiles;
@ -348,8 +352,6 @@ typedef struct {
connection_type mode;
file_cache_entry *fce; /* filecache entry for the selected file */
void **plugin_ctx; /* plugin connection specific config */
specific_config conf; /* global connection specific config */
@ -428,6 +430,12 @@ typedef struct {
unsigned short log_request_header_on_error;
unsigned short log_state_handling;
enum { STAT_CACHE_ENGINE_UNSET,
STAT_CACHE_ENGINE_NONE,
STAT_CACHE_ENGINE_SIMPLE,
STAT_CACHE_ENGINE_FAM
} stat_cache_engine;
} server_config;
typedef struct {
@ -525,8 +533,7 @@ typedef struct {
connections *joblist;
connections *fdwaitqueue;
file_cache *file_cache;
buffer *file_cache_etag;
stat_cache *stat_cache;
buffer_array *config_patches;

21
src/config.c

@ -24,6 +24,7 @@
static int config_insert(server *srv) {
size_t i;
int ret = 0;
buffer *stat_cache_string;
config_values_t cv[] = {
{ "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
@ -78,6 +79,7 @@ static int config_insert(server *srv) {
{ "dir-listing.encoding", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
{ "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 42 */
{ "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
{ "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
{ "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
@ -111,6 +113,9 @@ static int config_insert(server *srv) {
cv[42].destination = &(srv->srvconf.errorlog_use_syslog);
stat_cache_string = buffer_init();
cv[44].destination = stat_cache_string;
srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
assert(srv->config_storage);
@ -193,6 +198,22 @@ static int config_insert(server *srv) {
}
}
if (buffer_is_empty(stat_cache_string)) {
srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("fam"))) {
srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_FAM;
} else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
} else {
log_error_write(srv, __FILE__, __LINE__, "sb",
"server.stat-cache-engine can be one of \"none\", \"simple\", \"fam\", but not:", stat_cache_string);
ret = HANDLER_ERROR;
}
buffer_free(stat_cache_string);
return ret;
}

27
src/connections.c

@ -18,7 +18,7 @@
#include "response.h"
#include "network.h"
#include "http_chunk.h"
#include "file_cache.h"
#include "stat_cache.h"
#include "joblist.h"
#include "plugin.h"
@ -390,9 +390,10 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
case 200: /* class: header + body */
if (con->physical.path->used) {
stat_cache_entry *sce = NULL;
con->file_finished = 1;
if (HANDLER_GO_ON != file_cache_get_entry(srv, con, con->physical.path, &(con->fce))) {
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), con->physical.path);
@ -401,13 +402,13 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
return -1;
}
if (S_ISREG(con->fce->st.st_mode)) {
if (S_ISREG(sce->st.st_mode)) {
if (con->request.http_method == HTTP_METHOD_GET ||
con->request.http_method == HTTP_METHOD_POST) {
http_chunk_append_file(srv, con, con->physical.path, 0, con->fce->st.st_size);
http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
con->response.content_length = http_chunkqueue_length(srv, con);
} else if (con->request.http_method == HTTP_METHOD_HEAD) {
con->response.content_length = con->fce->st.st_size;
con->response.content_length = sce->st.st_size;
} else {
connection_set_state(srv, con, CON_STATE_ERROR);
return -1;
@ -415,7 +416,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
http_response_write_header(srv, con,
con->response.content_length,
con->fce->st.st_mtime);
sce->st.st_mtime);
} else {
@ -737,14 +738,14 @@ int connection_reset(server *srv, connection *con) {
array_reset(con->environment);
chunkqueue_reset(con->write_queue);
if (con->fce) {
file_cache_entry_release(srv, con, con->fce);
con->fce = NULL;
}
/* the plugins should cleanup themself */
for (i = 0; i < srv->plugins.used; i++) {
con->plugin_ctx[0] = NULL;
if (con->plugin_ctx[i] != NULL) {
log_error_write(srv, __FILE__, __LINE__, "sb", "missing cleanup in", ((plugin **)(srv->plugins.ptr))[i]->name);
}
con->plugin_ctx[i] = NULL;
}
con->header_len = 0;

483
src/file_cache.c

@ -1,483 +0,0 @@
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include "log.h"
#include "file_cache.h"
#include "fdevent.h"
#include "etag.h"
#ifdef HAVE_ATTR_ATTRIBUTES_H
#include <attr/attributes.h>
#endif
#include "sys-mmap.h"
/* NetBSD 1.3.x needs it */
#ifndef MAP_FAILED
# define MAP_FAILED -1
#endif
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
#ifndef HAVE_LSTAT
#define lstat stat
#endif
/* don't enable the dir-cache
*
* F_NOTIFY would be nice but only works with linux-rtsig
*/
#undef USE_LINUX_SIGIO
file_cache *file_cache_init(void) {
file_cache *fc = NULL;
fc = calloc(1, sizeof(*fc));
fc->dir_name = buffer_init();
return fc;
}
static file_cache_entry * file_cache_entry_init(void) {
file_cache_entry *fce = NULL;
fce = calloc(1, sizeof(*fce));
fce->fd = -1;
fce->fde_ndx = -1;
fce->name = buffer_init();
fce->etag = buffer_init();
fce->content_type = buffer_init();
return fce;
}
static void file_cache_entry_free(server *srv, file_cache_entry *fce) {
if (!fce) return;
if (fce->fd >= 0) {
close(fce->fd);
srv->cur_fds--;
}
buffer_free(fce->etag);
buffer_free(fce->name);
buffer_free(fce->content_type);
if (fce->mmap_p) munmap(fce->mmap_p, fce->mmap_length);
free(fce);
}
static int file_cache_entry_reset(server *srv, file_cache_entry *fce) {
if (fce->fd < 0) return 0;
close(fce->fd);
srv->cur_fds--;
#ifdef USE_LINUX_SIGIO
/* doesn't work anymore */
if (fce->fde_ndx != -1) {
fdevent_event_del(srv->ev, &(fce->fde_ndx), fce->fd);
}
#else
UNUSED(srv);
#endif
if (fce->mmap_p) {
munmap(fce->mmap_p, fce->mmap_length);
fce->mmap_p = NULL;
}
fce->fd = -1;
buffer_reset(fce->etag);
buffer_reset(fce->name);
buffer_reset(fce->content_type);
return 0;
}
void file_cache_free(server *srv, file_cache *fc) {
size_t i;
for (i = 0; i < fc->used; i++) {
file_cache_entry_free(srv, fc->ptr[i]);
}
free(fc->ptr);
buffer_free(fc->dir_name);
free(fc);
}
#ifdef HAVE_XATTR
int fce_attr_get(buffer *buf, char *name) {
int attrlen;
int ret;
attrlen = 1024;
buffer_prepare_copy(buf, attrlen);
attrlen--;
if(0 == (ret = attr_get(name, "Content-Type", buf->ptr, &attrlen, 0))) {
buf->used = attrlen + 1;
buf->ptr[attrlen] = '\0';
}
return ret;
}
#endif
file_cache_entry * file_cache_get_unused_entry(server *srv) {
file_cache_entry *fce = NULL;
file_cache *fc = srv->file_cache;
size_t i;
if (fc->size == 0) {
fc->size = 16;
fc->ptr = calloc(fc->size, sizeof(*fc->ptr));
fc->used = 0;
}
for (i = 0; i < fc->used; i++) {
file_cache_entry *f = fc->ptr[i];
if (f->fd == -1) {
return f;
}
}
if (fc->used < fc->size) {
fce = file_cache_entry_init();
fc->ptr[fc->used++] = fce;
} else {
/* the cache is full, time to resize */
fc->size += 16;
fc->ptr = realloc(fc->ptr, sizeof(*fc->ptr) * fc->size);
fce = file_cache_entry_init();
fc->ptr[fc->used++] = fce;
}
return fce;
}
handler_t file_cache_handle_fdevent(void *_srv, void *_fce, int revent) {
size_t i;
server *srv = _srv;
file_cache_entry *fce = _fce;
file_cache *fc = srv->file_cache;;
UNUSED(revent);
/* */
#if 0
log_error_write(srv, __FILE__, __LINE__, "sds", "dir has changed: ", fce->fd, fce->name->ptr);
#endif
/* touch all files below this directory */
for (i = 0; i < fc->used; i++) {
file_cache_entry *f = fc->ptr[i];
if (fce == f) continue;
if (0 == strncmp(fce->name->ptr, f->name->ptr, fce->name->used - 1)) {
#if 0
log_error_write(srv, __FILE__, __LINE__, "ss", "file hit: ", f->name->ptr);
#endif
f->is_dirty = 1;
}
}
return HANDLER_GO_ON;
}
#if 0
/* dead code, might be reused somewhere again */
int file_cache_check_cache() {
file_cache_entry *first_unused_fce = NULL;
file_cache *fc = srv->file_cache;
size_t i;
/* check the cache */
for (i = 0; i < fc->used; i++) {
fce = fc->ptr[i];
if (buffer_is_equal(name, fce->name)) {
log_error_write(srv, __FILE__, __LINE__, "sb", "cache hit:", name);
#ifdef USE_LINUX_SIGIO
if (fce->is_dirty == 0) {
fce->in_use++;
return fce;
}
#endif
/* get the etag information */
if (-1 == (stat(name->ptr, &(fce->st)))) {
fce->in_use = 0;
log_error_write(srv, __FILE__, __LINE__, "sbs", "stat failed: ", name, strerror(errno));
file_cache_entry_reset(srv, fce);
return NULL;
}
fce->stat_ts = srv->cur_ts;
/* create etag */
etag_create(srv->file_cache_etag, &(fce->st));
if (!buffer_is_equal(srv->file_cache_etag, fce->etag)) {
size_t s_len = 0, k;
/* etag has changed: reopen file */
file_cache_entry_reset(srv, fce);
if (-1 == (fce->fd = open(fce->name->ptr, O_RDONLY | O_LARGEFILE))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
buffer_reset(fce->name);
return NULL;
}
srv->cur_fds++;
buffer_copy_string_buffer(fce->etag, srv->file_cache_etag);
/* determine mimetype */
buffer_reset(fce->content_type);
s_len = name->used - 1;
for (k = 0; k < con->conf.mimetypes->used; k++) {
data_string *ds = (data_string *)con->conf.mimetypes->data[k];
size_t ct_len;
ct_len = ds->key->used - 1;
if (buffer_is_equal_right_len(name, ds->key, ct_len)) {
buffer_copy_string_buffer(fce->content_type, ds->value);
break;
}
}
#ifdef HAVE_XATTR
if (buffer_is_empty(fce->content_type)) {
fce_attr_get(fce->content_type, name->ptr);
}
#endif
}
#ifdef USE_LINUX_SIGIO
fce->is_dirty = 0;
#endif
fce->in_use++;
if (fce->fd == -1) {
log_error_write(srv, __FILE__, __LINE__, "sb", "fd is still -1 !", fce->name);
}
if (fce->st.st_size == 0) {
log_error_write(srv, __FILE__, __LINE__, "sb", "size is still 0 !", fce->name);
}
return fce;
}
if (fce->in_use == 0) {
if (!first_unused_fce) first_unused_fce = fce;
if (srv->cur_ts - fce->stat_ts > 10) {
file_cache_entry_reset(srv, fce);
}
}
}
if (first_unused_fce) {
file_cache_entry_reset(srv, fce);
fce = first_unused_fce;
} else {
/* not found, insert */
fce = file_cache_get_unused_entry(srv);
}
}
#endif
handler_t file_cache_get_entry(server *srv, connection *con, buffer *name, file_cache_entry **o_fce_ptr) {
file_cache_entry *fce = NULL;
file_cache_entry *o_fce = *o_fce_ptr;
UNUSED(con);
/* still valid ? */
if (o_fce != NULL) {
if (buffer_is_equal(name, o_fce->name) &&
(o_fce->fd != -1) &&
(o_fce->stat_ts == srv->cur_ts)
) {
return HANDLER_GO_ON;
} else {
o_fce->in_use--;
}
file_cache_entry_reset(srv, o_fce);
}
fce = file_cache_get_unused_entry(srv);
buffer_copy_string_buffer(fce->name, name);
fce->in_use = 0;
fce->fd = -1;
if (-1 == (con->conf.follow_symlink ? stat(name->ptr, &(fce->st)) : lstat(name->ptr, &(fce->st)))) {
int oerrno = errno;
#if 0
log_error_write(srv, __FILE__, __LINE__, "sbs", "stat failed:", name, strerror(errno));
#endif
file_cache_entry_reset(srv, fce);
buffer_reset(fce->name);
errno = oerrno;
return HANDLER_ERROR;
}
fce->stat_ts = srv->cur_ts;
if (S_ISREG(fce->st.st_mode)) {
size_t k, s_len;
#ifdef USE_LINUX_SIGIO
file_cache_entry *dir_fce;
char *slash;
#endif
if (-1 == (fce->fd = open(name->ptr, O_RDONLY | O_LARGEFILE))) {
int oerrno = errno;
if (errno == EMFILE || errno == EINTR) {
return HANDLER_WAIT_FOR_FD;
}
log_error_write(srv, __FILE__, __LINE__, "sbs",
"open failed for:", name,
strerror(errno));
buffer_reset(fce->name);
errno = oerrno;
return HANDLER_ERROR;
}
srv->cur_fds++;
/* determine mimetype */
buffer_reset(fce->content_type);
s_len = name->used - 1;
for (k = 0; k < con->conf.mimetypes->used; k++) {
data_string *ds = (data_string *)con->conf.mimetypes->data[k];
size_t ct_len;
if (ds->key->used == 0) continue;
ct_len = ds->key->used - 1;
if (s_len < ct_len) continue;
if (0 == strncasecmp(name->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
buffer_copy_string_buffer(fce->content_type, ds->value);
break;
}
}
#ifdef HAVE_XATTR
if (buffer_is_empty(fce->content_type)) {
fce_attr_get(fce->content_type, name->ptr);
}
#endif
etag_create(fce->etag, &(fce->st));
#ifdef USE_LINUX_SIGIO
/* register sigio for the directory */
dir_fce = file_cache_get_unused_entry(srv);
buffer_copy_string_buffer(fc->dir_name, name);
/* get dirname */
if (0 == (slash = strrchr(fc->dir_name->ptr, '/'))) {
SEGFAULT();
}
*(slash+1) = '\0';
if (-1 == (dir_fce->fd = open(fc->dir_name->ptr, O_RDONLY))) {
int oerrno = errno;
log_error_write(srv, __FILE__, __LINE__, "sbs",
"open failed:", fc->dir_name, strerror(errno));
errno = oerrno;
return HANDLER_ERROR;
}
srv->cur_fds++;
if (fcntl(dir_fce->fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT) < 0) {
int oerrno = errno;
log_error_write(srv, __FILE__, __LINE__, "ss",
"fcntl failed:", strerror(errno));
close(dir_fce->fd);
srv->cur_fds--;
errno = oerrno;
return HANDLER_ERROR;
}
/* ->used is not updated -> no _buffer copy */
buffer_copy_string(dir_fce->name, fc->dir_name->ptr);
/* register fd-handler */
fdevent_register(srv->ev, dir_fce->fd, file_cache_handle_fdevent, dir_fce);
fdevent_event_add(srv->ev, &(dir_fce->fde_ndx), dir_fce->fd, FDEVENT_IN);
# if 1
log_error_write(srv, __FILE__, __LINE__, "sddb", "fdevent_event_add:", fce->fde_ndx, fce->fd, fce->name);
# endif
#endif
}
fce->in_use++;
*o_fce_ptr = fce;
return HANDLER_GO_ON;
}
int file_cache_entry_release(server *srv, connection *con, file_cache_entry *fce) {
UNUSED(srv);
UNUSED(con);
if (fce->in_use > 0) fce->in_use--;
file_cache_entry_reset(srv, fce);
return 0;
}

12
src/file_cache.h

@ -1,12 +0,0 @@
#ifndef _FILE_CACHE_H_
#define _FILE_CACHE_H_
#include "base.h"
file_cache *file_cache_init(void);
void file_cache_free(server *srv, file_cache *fc);
handler_t file_cache_get_entry(server *srv, connection *con, buffer *name, file_cache_entry **o_fce);
int file_cache_entry_release(server *srv, connection *con, file_cache_entry *fce);
#endif

46
src/mod_compress.c

@ -13,6 +13,7 @@
#include "log.h"
#include "buffer.h"
#include "response.h"
#include "stat_cache.h"
#include "plugin.h"
@ -318,7 +319,7 @@ static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_dat
}
#endif
static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, buffer *fn, file_cache_entry *fce, int type) {
static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, buffer *fn, stat_cache_entry *sce, int type) {
int ifd, ofd;
int ret = -1;
void *start;
@ -326,14 +327,14 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
ssize_t r;
/* overflow */
if ((off_t)(fce->st.st_size * 1.1) < fce->st.st_size) return -1;
if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
/* don't mmap files > size_t
*
* we could use a sliding window, but currently there is no need for it
*/
if (fce->st.st_size > SIZE_MAX) return -1;
if (sce->st.st_size > SIZE_MAX) return -1;
buffer_reset(p->ofn);
buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
@ -380,7 +381,7 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
return -1;
}
buffer_append_string_buffer(p->ofn, fce->etag);
buffer_append_string_buffer(p->ofn, sce->etag);
if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL, 0600))) {
if (errno == EEXIST) {
@ -409,7 +410,7 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
}
if (MAP_FAILED == (start = mmap(NULL, fce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
close(ofd);
@ -420,15 +421,15 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
switch(type) {
#ifdef USE_ZLIB
case HTTP_ACCEPT_ENCODING_GZIP:
ret = deflate_file_to_buffer_gzip(srv, con, p, start, fce->st.st_size, fce->st.st_mtime);
ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
break;
case HTTP_ACCEPT_ENCODING_DEFLATE:
ret = deflate_file_to_buffer_deflate(srv, con, p, start, fce->st.st_size);
ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
break;
#endif
#ifdef USE_BZ2LIB
case HTTP_ACCEPT_ENCODING_BZIP2:
ret = deflate_file_to_buffer_bzip2(srv, con, p, start, fce->st.st_size);
ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
break;
#endif
default:
@ -444,7 +445,7 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
}
munmap(start, fce->st.st_size);
munmap(start, sce->st.st_size);
close(ofd);
close(ifd);
@ -455,21 +456,21 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu
return 0;
}
static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p, buffer *fn, file_cache_entry *fce, int type) {
static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p, buffer *fn, stat_cache_entry *sce, int type) {
int ifd;
int ret = -1;
void *start;
buffer *b;
/* overflow */
if ((off_t)(fce->st.st_size * 1.1) < fce->st.st_size) return -1;
if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
/* don't mmap files > size_t
*
* we could use a sliding window, but currently there is no need for it
*/
if (fce->st.st_size > SIZE_MAX) return -1;
if (sce->st.st_size > SIZE_MAX) return -1;
if (-1 == (ifd = open(fn->ptr, O_RDONLY))) {
@ -479,7 +480,7 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
}
if (MAP_FAILED == (start = mmap(NULL, fce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
close(ifd);
@ -489,15 +490,15 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
switch(type) {
#ifdef USE_ZLIB
case HTTP_ACCEPT_ENCODING_GZIP:
ret = deflate_file_to_buffer_gzip(srv, con, p, start, fce->st.st_size, fce->st.st_mtime);
ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
break;
case HTTP_ACCEPT_ENCODING_DEFLATE:
ret = deflate_file_to_buffer_deflate(srv, con, p, start, fce->st.st_size);
ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
break;
#endif
#ifdef USE_BZ2LIB
case HTTP_ACCEPT_ENCODING_BZIP2:
ret = deflate_file_to_buffer_bzip2(srv, con, p, start, fce->st.st_size);
ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
break;
#endif
default:
@ -505,7 +506,7 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p,
break;
}
munmap(start, fce->st.st_size);
munmap(start, sce->st.st_size);
close(ifd);
if (ret != 0) return -1;
@ -574,6 +575,7 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
data_string *content_ds;
size_t m, i;
off_t max_fsize;
stat_cache_entry *sce = NULL;
/* only GET and POST can get compressed */
if (con->request.http_method != HTTP_METHOD_GET &&
@ -590,9 +592,11 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
max_fsize = p->conf.compress_max_filesize;
stat_cache_get_entry(srv, con, con->physical.path, &sce);
/* don't compress files that are too large as we need to much time to handle them */
if (max_fsize && (con->fce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
if (NULL == (content_ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
log_error_write(srv, __FILE__, __LINE__, "sbb", "Content-Type is not set for", con->physical.path, con->uri.path);
@ -665,14 +669,14 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
/* deflate it */
if (p->conf.compress_cache_dir->used) {
if (0 == deflate_file_to_file(srv, con, p,
con->physical.path, con->fce, compression_type)) {
con->physical.path, sce, compression_type)) {
struct tm *tm;
time_t last_mod;
response_header_insert(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
/* Set Last-Modified of ORIGINAL file */
last_mod = con->fce->st.st_mtime;
last_mod = sce->st.st_mtime;
for (i = 0; i < FILE_CACHE_MAX; i++) {
if (srv->mtime_cache[i].mtime == last_mod) break;
@ -709,7 +713,7 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
return HANDLER_FINISHED;
}
} else if (0 == deflate_file_to_buffer(srv, con, p,
con->physical.path, con->fce, compression_type)) {
con->physical.path, sce, compression_type)) {
response_header_insert(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));

7
src/mod_evhost.c

@ -5,7 +5,7 @@
#include "plugin.h"
#include "log.h"
#include "response.h"
#include "file_cache.h"
#include "stat_cache.h"
typedef struct {
/* unparsed pieces */
@ -267,6 +267,7 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
array *parsed_host;
register char *ptr;
int not_good = 0;
stat_cache_entry *sce = NULL;
/* not authority set */
if (con->uri.authority->used == 0) return HANDLER_GO_ON;
@ -309,10 +310,10 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d)
array_free(parsed_host);
if (HANDLER_GO_ON != file_cache_get_entry(srv, con, p->tmp_buf, &(con->fce))) {
if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
not_good = 1;
} else if(!S_ISDIR(con->fce->st.st_mode)) {
} else if(!S_ISDIR(sce->st.st_mode)) {
log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
not_good = 1;
}

8
src/mod_expire.c

@ -9,10 +9,9 @@
#include "response.h"
#include "plugin.h"
#include "stat_cache.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/**
* this is a expire module for a lighttpd
@ -315,6 +314,9 @@ URIHANDLER_FUNC(mod_expire_path_handler) {
int ts;
time_t t;
size_t len;
stat_cache_entry *sce = NULL;
stat_cache_get_entry(srv, con, con->physical.path, &sce);
switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
case 0:
@ -324,7 +326,7 @@ URIHANDLER_FUNC(mod_expire_path_handler) {
case 1:
/* modification */
t = (ts += con->fce->st.st_mtime);
t = (ts += sce->st.st_mtime);
break;
default:
/* -1 is handled at parse-time */

44
src/mod_fastcgi.c

@ -1249,7 +1249,7 @@ static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
return 0;
}
void fcgi_connection_cleanup(server *srv, handler_ctx *hctx) {
void fcgi_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
@ -1348,7 +1348,7 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
fcgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
fcgi_connection_close(srv, con->plugin_ctx[p->id]);
return HANDLER_GO_ON;
}
@ -2650,7 +2650,7 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
}
fcgi_restart_dead_procs(srv, p, host);
fcgi_connection_cleanup(srv, hctx);
fcgi_connection_close(srv, hctx);
buffer_reset(con->physical.path);
con->mode = DIRECT;
@ -2672,7 +2672,7 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
return HANDLER_WAIT_FOR_FD;
} else {
fcgi_connection_cleanup(srv, hctx);
fcgi_connection_close(srv, hctx);
buffer_reset(con->physical.path);
con->mode = DIRECT;
@ -2694,30 +2694,6 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
}
}
static handler_t fcgi_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
if (NULL == hctx) return HANDLER_GO_ON;
p = hctx->plugin_data;
con = hctx->remote_conn;
if (con->mode != p->id) return HANDLER_GO_ON;
log_error_write(srv, __FILE__, __LINE__, "ssdsd",
"emergency exit: fastcgi:",
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
fcgi_connection_cleanup(srv, hctx);
return HANDLER_FINISHED;
}
static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
server *srv = (server *)s;
handler_ctx *hctx = ctx;
@ -2747,13 +2723,13 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
buffer_copy_string_buffer(con->physical.path, host->docroot);
buffer_append_string_buffer(con->physical.path, con->uri.path);
fcgi_connection_cleanup(srv, hctx);
fcgi_connection_close(srv, hctx);
con->mode = DIRECT;
con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
} else {
/* we are done */
fcgi_connection_cleanup(srv, hctx);
fcgi_connection_close(srv, hctx);
}
joblist_append(srv, con);
@ -2825,7 +2801,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
fcgi_connection_cleanup(srv, hctx);
fcgi_connection_close(srv, hctx);
connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
buffer_reset(con->physical.path);
@ -2833,7 +2809,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
con->mode = DIRECT;
} else {
/* response might have been already started, kill the connection */
fcgi_connection_cleanup(srv, hctx);
fcgi_connection_close(srv, hctx);
log_error_write(srv, __FILE__, __LINE__, "ssdsd",
"response already sent out, termination connection",
@ -3176,7 +3152,9 @@ JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
return fcgi_connection_close(srv, con->plugin_ctx[p->id]);
fcgi_connection_close(srv, con->plugin_ctx[p->id]);
return HANDLER_GO_ON;
}
TRIGGER_FUNC(mod_fastcgi_handle_trigger) {

8
src/mod_mysql_vhost.c

@ -8,7 +8,7 @@
#include "config.h"
#include "log.h"
#include "file_cache.h"
#include "stat_cache.h"
#ifdef HAVE_MYSQL
#include <mysql/mysql.h>
#endif
@ -322,6 +322,7 @@ static int mod_mysql_vhost_setup_connection(server *srv, connection *con, plugin
CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
plugin_data *p = p_d;
plugin_connection_data *c;
stat_cache_entry *sce;
unsigned cols;
MYSQL_ROW row;
@ -368,11 +369,12 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
/* sanity check that really is a directory */
buffer_copy_string(p->tmp_buf, row[0]);
BUFFER_APPEND_SLASH(p->tmp_buf);
if (file_cache_get_entry(srv, con, p->tmp_buf, &(con->fce)) != HANDLER_GO_ON) {
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
goto ERR500;
}
if (!S_ISDIR(con->fce->st.st_mode)) {
if (!S_ISDIR(sce->st.st_mode)) {
log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
goto ERR500;
}

57
src/mod_proxy.c

@ -335,21 +335,19 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) {
return HANDLER_GO_ON;
}
void proxy_connection_cleanup(server *srv, handler_ctx *hctx) {
void proxy_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
connection *con;
if (NULL == hctx) return;
p = hctx->plugin_data;
con = hctx->remote_conn;
if (con->mode != p->id) return;
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
if (hctx->fd != -1) {
fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
fdevent_unregister(srv->ev, hctx->fd);
close(hctx->fd);
srv->cur_fds--;
}
@ -358,14 +356,6 @@ void proxy_connection_cleanup(server *srv, handler_ctx *hctx) {
con->plugin_ctx[p->id] = NULL;
}
static handler_t mod_proxy_connection_reset(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
proxy_connection_cleanup(srv, con->plugin_ctx[p->id]);
return HANDLER_GO_ON;
}
static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
struct sockaddr *proxy_addr;
struct sockaddr_in proxy_addr_in;
@ -877,7 +867,7 @@ SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
host->is_disabled = 1;
host->disable_ts = srv->cur_ts;
proxy_connection_cleanup(srv, hctx);
proxy_connection_close(srv, hctx);
/* reset the enviroment and restart the sub-request */
buffer_reset(con->physical.path);
@ -906,23 +896,6 @@ SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
}
}
static handler_t proxy_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
if (NULL == hctx) return HANDLER_GO_ON;
p = hctx->plugin_data;
con = hctx->remote_conn;
if (con->mode != p->id) return HANDLER_GO_ON;
proxy_connection_cleanup(srv, hctx);
return HANDLER_FINISHED;
}
static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
server *srv = (server *)s;
handler_ctx *hctx = ctx;
@ -945,7 +918,7 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
hctx->host->usage--;
/* we are done */
proxy_connection_cleanup(srv, hctx);
proxy_connection_close(srv, hctx);
joblist_append(srv, con);
return HANDLER_FINISHED;
@ -1016,12 +989,10 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
} else if (revents & FDEVENT_ERR) {
/* kill all connections to the proxy process */
log_error_write(srv, __FILE__, __LINE__, "s", "proxy-FDEVENT_ERR");
log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
joblist_append(srv, con);
proxy_connection_close(srv, hctx);
return HANDLER_ERROR;
}
return HANDLER_FINISHED;
@ -1238,7 +1209,9 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p
static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
plugin_data *p = p_d;
return proxy_connection_close(srv, con->plugin_ctx[p->id]);
proxy_connection_close(srv, con->plugin_ctx[p->id]);
return HANDLER_GO_ON;
}
/**
@ -1284,17 +1257,17 @@ TRIGGER_FUNC(mod_proxy_trigger) {
int mod_proxy_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("proxy");
p->init = mod_proxy_init;
p->cleanup = mod_proxy_free;
p->set_defaults = mod_proxy_set_defaults;
p->connection_reset = mod_proxy_connection_reset;
p->handle_connection_close = mod_proxy_connection_close_callback;
p->connection_reset = mod_proxy_connection_close_callback; /* end of req-resp cycle */
p->handle_connection_close = mod_proxy_connection_close_callback; /* end of client connection */
p->handle_uri_clean = mod_proxy_check_extension;
p->handle_subrequest = mod_proxy_handle_subrequest;
p->handle_trigger = mod_proxy_trigger;
p->handle_trigger = mod_proxy_trigger;
p->data = NULL;

10
src/mod_simple_vhost.c

@ -6,7 +6,7 @@
#include "base.h"
#include "log.h"
#include "buffer.h"
#include "file_cache.h"
#include "stat_cache.h"
#include "plugin.h"
@ -119,6 +119,8 @@ SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
}
static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
stat_cache_entry *sce = NULL;
buffer_prepare_copy(out, 128);
if (p->conf.server_root->used) {
@ -151,13 +153,11 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *
BUFFER_APPEND_SLASH(out);
}
if (HANDLER_GO_ON != file_cache_get_entry(srv, con, out, &(con->fce))) {
if (HANDLER_ERROR != stat_cache_get_entry(srv, con, out, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
strerror(errno), out);
return -1;
}
if (!S_ISDIR(con->fce->st.st_mode)) {
} else if (!S_ISDIR(sce->st.st_mode)) {
return -1;
}

12
src/mod_ssi.c

@ -10,6 +10,7 @@
#include "base.h"
#include "log.h"
#