summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Krzyżaniak <eloy@debian.org>2006-01-16 19:08:37 +0000
committerKrzysztof Krzyżaniak <eloy@debian.org>2006-01-16 19:08:37 +0000
commitf40f3dcc4b1cbbbd3bcf640e6d852786bd546d12 (patch)
treef6c6501b996665c51a3504bf5327b2753d3e048c /src
parentae6e5f21be48a40bc2a29518dc655245408cf972 (diff)
downloadlighttpd-f40f3dcc4b1cbbbd3bcf640e6d852786bd546d12.tar.gz
eloy: new upstream versiondebian/1.4.9-1
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am6
-rw-r--r--src/Makefile.in68
-rw-r--r--src/base.h34
-rw-r--r--src/buffer.c27
-rw-r--r--src/buffer.h1
-rw-r--r--src/configfile.c19
-rw-r--r--src/configparser.c4
-rw-r--r--src/configparser.y4
-rw-r--r--src/connections.c15
-rw-r--r--src/http_auth.c12
-rw-r--r--src/http_auth_digest.c82
-rw-r--r--src/http_auth_digest.h24
-rw-r--r--src/keyvalue.c1
-rw-r--r--src/keyvalue.h3
-rw-r--r--src/mod_access.c18
-rw-r--r--src/mod_auth.c22
-rw-r--r--src/mod_cgi.c4
-rw-r--r--src/mod_cml.c122
-rw-r--r--src/mod_cml.h1
-rw-r--r--src/mod_cml_lua.c24
-rw-r--r--src/mod_dirlisting.c92
-rw-r--r--src/mod_evasive.c178
-rw-r--r--src/mod_fastcgi.c927
-rw-r--r--src/mod_mysql_vhost.c2
-rw-r--r--src/mod_proxy.c7
-rw-r--r--src/mod_scgi.c2
-rw-r--r--src/mod_secure_download.c2
-rw-r--r--src/mod_setenv.c51
-rw-r--r--src/mod_staticfile.c34
-rw-r--r--src/mod_status.c52
-rw-r--r--src/mod_webdav.c22
-rw-r--r--src/network.c41
-rw-r--r--src/network_linux_sendfile.c5
-rw-r--r--src/plugin.c19
-rw-r--r--src/request.c53
-rw-r--r--src/response.c14
-rw-r--r--src/server.c38
37 files changed, 1389 insertions, 641 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8caace2..7e9fc9e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,6 +68,12 @@ src += $(common_src)
common_libadd =
endif
+lib_LTLIBRARIES += mod_evasive.la
+mod_evasive_la_SOURCES = mod_evasive.c
+mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_evasive_la_LIBADD = $(common_libadd)
+
+
lib_LTLIBRARIES += mod_webdav.la
mod_webdav_la_SOURCES = mod_webdav.c
mod_webdav_la_CFLAGS = $(XML_CFLAGS)
diff --git a/src/Makefile.in b/src/Makefile.in
index e892092..cc6fab9 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -16,7 +16,7 @@
-SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
+SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
srcdir = @srcdir@
top_srcdir = @top_srcdir@
@@ -145,6 +145,9 @@ mod_dirlisting_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
$(am__DEPENDENCIES_1)
am_mod_dirlisting_la_OBJECTS = mod_dirlisting.lo
mod_dirlisting_la_OBJECTS = $(am_mod_dirlisting_la_OBJECTS)
+mod_evasive_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_evasive_la_OBJECTS = mod_evasive.lo
+mod_evasive_la_OBJECTS = $(am_mod_evasive_la_OBJECTS)
mod_evhost_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_evhost_la_OBJECTS = mod_evhost.lo
mod_evhost_la_OBJECTS = $(am_mod_evhost_la_OBJECTS)
@@ -282,23 +285,7 @@ SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) \
$(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) \
$(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) \
$(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) \
- $(mod_dirlisting_la_SOURCES) $(mod_evhost_la_SOURCES) \
- $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) \
- $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) \
- $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) \
- $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) \
- $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) \
- $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) \
- $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \
- $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) \
- $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) \
- $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) \
- $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
-DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \
- $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) \
- $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) \
- $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) \
- $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) \
+ $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) \
$(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) \
$(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) \
$(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) \
@@ -309,8 +296,26 @@ DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \
$(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) \
$(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) \
$(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) \
- $(lemon_SOURCES) $(am__lighttpd_SOURCES_DIST) \
- $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
+ $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) \
+ $(spawn_fcgi_SOURCES)
+DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \
+ $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) \
+ $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) \
+ $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) \
+ $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) \
+ $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \
+ $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) \
+ $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) \
+ $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) \
+ $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) \
+ $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) \
+ $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) \
+ $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \
+ $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) \
+ $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) \
+ $(mod_webdav_la_SOURCES) $(lemon_SOURCES) \
+ $(am__lighttpd_SOURCES_DIST) $(proc_open_SOURCES) \
+ $(spawn_fcgi_SOURCES)
HEADERS = $(noinst_HEADERS)
ETAGS = etags
CTAGS = ctags
@@ -480,20 +485,24 @@ spawn_fcgi_SOURCES = spawn-fcgi.c
#mod_httptls_la_SOURCES = mod_httptls.c
#mod_httptls_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
#mod_httptls_la_LIBADD = $(common_libadd)
-lib_LTLIBRARIES = $(am__append_1) mod_webdav.la mod_cml.la \
- mod_trigger_b4_dl.la mod_mysql_vhost.la mod_cgi.la mod_scgi.la \
- mod_staticfile.la mod_dirlisting.la mod_indexfile.la \
- mod_setenv.la mod_alias.la mod_userdir.la mod_rrdtool.la \
- mod_usertrack.la mod_proxy.la mod_ssi.la mod_secdownload.la \
- mod_expire.la mod_evhost.la mod_simple_vhost.la mod_fastcgi.la \
- mod_access.la mod_compress.la mod_auth.la mod_rewrite.la \
- mod_redirect.la mod_status.la mod_accesslog.la
+lib_LTLIBRARIES = $(am__append_1) mod_evasive.la mod_webdav.la \
+ mod_cml.la mod_trigger_b4_dl.la mod_mysql_vhost.la mod_cgi.la \
+ mod_scgi.la mod_staticfile.la mod_dirlisting.la \
+ mod_indexfile.la mod_setenv.la mod_alias.la mod_userdir.la \
+ mod_rrdtool.la mod_usertrack.la mod_proxy.la mod_ssi.la \
+ mod_secdownload.la mod_expire.la mod_evhost.la \
+ mod_simple_vhost.la mod_fastcgi.la mod_access.la \
+ mod_compress.la mod_auth.la mod_rewrite.la mod_redirect.la \
+ mod_status.la mod_accesslog.la
@NO_RDYNAMIC_TRUE@liblightcomp_la_SOURCES = $(common_src)
@NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS) $(FAM_CFLAGS)
@NO_RDYNAMIC_TRUE@liblightcomp_la_LDFLAGS = -avoid-version -no-undefined
@NO_RDYNAMIC_TRUE@liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS)
@NO_RDYNAMIC_FALSE@common_libadd =
@NO_RDYNAMIC_TRUE@common_libadd = liblightcomp.la
+mod_evasive_la_SOURCES = mod_evasive.c
+mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_evasive_la_LIBADD = $(common_libadd)
mod_webdav_la_SOURCES = mod_webdav.c
mod_webdav_la_CFLAGS = $(XML_CFLAGS)
mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
@@ -693,6 +702,8 @@ mod_compress.la: $(mod_compress_la_OBJECTS) $(mod_compress_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(mod_compress_la_LDFLAGS) $(mod_compress_la_OBJECTS) $(mod_compress_la_LIBADD) $(LIBS)
mod_dirlisting.la: $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(mod_dirlisting_la_LDFLAGS) $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_LIBADD) $(LIBS)
+mod_evasive.la: $(mod_evasive_la_OBJECTS) $(mod_evasive_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(mod_evasive_la_LDFLAGS) $(mod_evasive_la_OBJECTS) $(mod_evasive_la_LIBADD) $(LIBS)
mod_evhost.la: $(mod_evhost_la_OBJECTS) $(mod_evhost_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(mod_evhost_la_LDFLAGS) $(mod_evhost_la_OBJECTS) $(mod_evhost_la_LIBADD) $(LIBS)
mod_expire.la: $(mod_expire_la_OBJECTS) $(mod_expire_la_DEPENDENCIES)
@@ -897,6 +908,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_compress.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_dirlisting.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evasive.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evhost.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_expire.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_fastcgi.Plo@am__quote@
diff --git a/src/base.h b/src/base.h
index 506fdad..98e23b8 100644
--- a/src/base.h
+++ b/src/base.h
@@ -260,7 +260,7 @@ typedef struct {
unsigned short use_ipv6;
unsigned short is_ssl;
unsigned short allow_http11;
- unsigned short force_lower_case; /* if the FS is case-insensitive, force all files to lower-case */
+ unsigned short force_lowercase_filenames; /* if the FS is case-insensitive, force all files to lower-case */
unsigned short max_request_size;
unsigned short kbytes_per_second; /* connection kb/s limit */
@@ -289,7 +289,21 @@ typedef struct {
#endif
} specific_config;
-typedef enum { CON_STATE_CONNECT, CON_STATE_REQUEST_START, CON_STATE_READ, CON_STATE_REQUEST_END, CON_STATE_READ_POST, CON_STATE_HANDLE_REQUEST, CON_STATE_RESPONSE_START, CON_STATE_WRITE, CON_STATE_RESPONSE_END, CON_STATE_ERROR, CON_STATE_CLOSE } connection_state_t;
+/* the order of the items should be the same as they are processed
+ * read before write as we use this later */
+typedef enum {
+ CON_STATE_CONNECT,
+ CON_STATE_REQUEST_START,
+ CON_STATE_READ,
+ CON_STATE_REQUEST_END,
+ CON_STATE_READ_POST,
+ CON_STATE_HANDLE_REQUEST,
+ CON_STATE_RESPONSE_START,
+ CON_STATE_WRITE,
+ CON_STATE_RESPONSE_END,
+ CON_STATE_ERROR,
+ CON_STATE_CLOSE
+} connection_state_t;
typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
typedef struct {
@@ -459,6 +473,7 @@ typedef struct {
STAT_CACHE_ENGINE_SIMPLE,
STAT_CACHE_ENGINE_FAM
} stat_cache_engine;
+ unsigned short enable_cores;
} server_config;
typedef struct {
@@ -558,6 +573,21 @@ typedef struct server {
connections *fdwaitqueue;
stat_cache *stat_cache;
+
+ /**
+ * The status array can carry all the status information you want
+ * the key to the array is <module-prefix>.<name>
+ * and the values are counters
+ *
+ * example:
+ * fastcgi.backends = 10
+ * fastcgi.active-backends = 6
+ * fastcgi.backend.<key>.load = 24
+ * fastcgi.backend.<key>....
+ *
+ * fastcgi.backend.<key>.disconnects = ...
+ */
+ array *status;
fdevent_handler_t event_handler;
diff --git a/src/buffer.c b/src/buffer.c
index cd4a72a..40b8cb9 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -685,6 +685,28 @@ const char encoded_chars_html[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
};
+const char encoded_chars_minimal_xml[] = {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 70 - 7F DEL */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+};
+
const char encoded_chars_hex[] = {
/*
0 1 2 3 4 5 6 7 8 9 A B C D E F
@@ -731,6 +753,9 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
case ENCODING_HTML:
map = encoded_chars_html;
break;
+ case ENCODING_MINIMAL_XML:
+ map = encoded_chars_minimal_xml;
+ break;
case ENCODING_HEX:
map = encoded_chars_hex;
break;
@@ -749,6 +774,7 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
d_len += 3;
break;
case ENCODING_HTML:
+ case ENCODING_MINIMAL_XML:
d_len += 6;
break;
case ENCODING_HEX:
@@ -774,6 +800,7 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
d[d_len++] = hex_chars[(*ds) & 0x0F];
break;
case ENCODING_HTML:
+ case ENCODING_MINIMAL_XML:
d[d_len++] = '&';
d[d_len++] = '#';
d[d_len++] = 'x';
diff --git a/src/buffer.h b/src/buffer.h
index c304d76..3ca22e5 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -88,6 +88,7 @@ typedef enum {
ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
ENCODING_HTML, /* & becomes &amp; and so on */
+ ENCODING_MINIMAL_XML, /* minimal encoding for xml */
ENCODING_HEX /* encode string as hex */
} buffer_encoding_t;
diff --git a/src/configfile.c b/src/configfile.c
index e9080c3..6f13cd6 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -44,7 +44,7 @@ static int config_insert(server *srv) {
{ "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
{ "server.max-worker", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 13 */
{ "server.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
- { "server.force-lower-case-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 15 */
+ { "server.force-lowercase-filenames", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 15 */
{ "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 16 */
{ "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
{ "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
@@ -79,6 +79,7 @@ static int config_insert(server *srv) {
{ "server.max-connections", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 42 */
{ "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
{ "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
+ { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
{ "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 },
@@ -88,6 +89,7 @@ static int config_insert(server *srv) {
{ "server.userid", "use server.username instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.groupid", "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.use-keep-alive", "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
+ { "server.force-lower-case-files", "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -116,6 +118,7 @@ static int config_insert(server *srv) {
cv[41].destination = stat_cache_string;
cv[43].destination = srv->srvconf.network_backend;
cv[44].destination = srv->srvconf.upload_tempdirs;
+ cv[45].destination = &(srv->srvconf.enable_cores);
cv[42].destination = &(srv->srvconf.max_conns);
cv[12].destination = &(srv->srvconf.max_request_size);
@@ -147,7 +150,7 @@ static int config_insert(server *srv) {
s->kbytes_per_second = 0;
s->allow_http11 = 1;
s->range_requests = 1;
- s->force_lower_case = 0;
+ s->force_lowercase_filenames = 0;
s->global_kbytes_per_second = 0;
s->global_bytes_per_second_cnt = 0;
s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
@@ -160,7 +163,7 @@ static int config_insert(server *srv) {
/* 13 max-worker */
cv[14].destination = s->document_root;
- cv[15].destination = &(s->force_lower_case);
+ cv[15].destination = &(s->force_lowercase_filenames);
cv[16].destination = &(s->log_condition_handling);
cv[17].destination = &(s->max_keep_alive_requests);
cv[18].destination = s->server_name;
@@ -244,7 +247,7 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(log_file_not_found);
PATCH(range_requests);
- PATCH(force_lower_case);
+ PATCH(force_lowercase_filenames);
PATCH(is_ssl);
PATCH(ssl_pemfile);
@@ -316,8 +319,8 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
PATCH(log_file_not_found);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
PATCH(allow_http11);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lower-case-files"))) {
- PATCH(force_lower_case);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
+ PATCH(force_lowercase_filenames);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
PATCH(global_kbytes_per_second);
PATCH(global_bytes_per_second_cnt);
@@ -1085,7 +1088,7 @@ int config_set_defaults(server *srv) {
* an other filename, no need to stat(),
* just assume it is case-sensitive. */
- s->force_lower_case = 0;
+ s->force_lowercase_filenames = 0;
} else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
/* upper case exists too, doesn't the FS handle this ? */
@@ -1095,7 +1098,7 @@ int config_set_defaults(server *srv) {
if (st1.st_ino == st2.st_ino) {
/* upper and lower have the same inode -> case-insensitve FS */
- s->force_lower_case = 1;
+ s->force_lowercase_filenames = 1;
}
}
}
diff --git a/src/configparser.c b/src/configparser.c
index 68d9c62..2ce169a 100644
--- a/src/configparser.c
+++ b/src/configparser.c
@@ -1194,8 +1194,8 @@ static void yy_reduce(
dc->string = buffer_init_buffer(rvalue);
}
#else
- fprintf(stderr, "regex conditionals are not allowed as pcre-support" \
- "is missing: $%s[%s]\n",
+ fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
+ "(perhaps just a missing pcre-devel package ?) \n",
yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy1->ptr);
ctx->ok = 0;
#endif
diff --git a/src/configparser.y b/src/configparser.y
index 4ca4fa0..767024f 100644
--- a/src/configparser.y
+++ b/src/configparser.y
@@ -447,8 +447,8 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
dc->string = buffer_init_buffer(rvalue);
}
#else
- fprintf(stderr, "regex conditionals are not allowed as pcre-support" \
- "is missing: $%s[%s]\n",
+ fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
+ "(perhaps just a missing pcre-devel package ?) \n",
B->ptr, C->ptr);
ctx->ok = 0;
#endif
diff --git a/src/connections.c b/src/connections.c
index acd8880..ea3a66c 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -352,7 +352,13 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
case HTTP_METHOD_PROPPATCH:
break;
case HTTP_METHOD_OPTIONS:
- if (con->uri.path->ptr[0] != '*') {
+ /*
+ * 400 is coming from the request-parser BEFORE uri.path is set
+ * 403 is from the response handler when noone else catched it
+ *
+ * */
+ if (con->uri.path->used &&
+ con->uri.path->ptr[0] != '*') {
response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
con->http_status = 200;
@@ -364,6 +370,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
default:
switch(con->http_status) {
case 400: /* bad request */
+ case 414: /* overload request header */
case 505: /* unknown protocol */
case 207: /* this was webdav */
break;
@@ -864,6 +871,7 @@ int connection_handle_read_state(server *srv, connection *con) {
c->next = cq->unused;
cq->unused = c;
+ cq->unused_chunks++;
c = cq->first;
} else if (c->next && c->next->mem->used == 0) {
@@ -876,6 +884,7 @@ int connection_handle_read_state(server *srv, connection *con) {
fc->next = cq->unused;
cq->unused = fc;
+ cq->unused_chunks++;
/* the last node was empty */
if (c->next == NULL) {
@@ -981,11 +990,11 @@ int connection_handle_read_state(server *srv, connection *con) {
if (h_term) {
connection_set_state(srv, con, CON_STATE_REQUEST_END);
} else if (con->request.request->used > 64 * 1024) {
- log_error_write(srv, __FILE__, __LINE__, "sd", "http-header larger then 64k -> disconnected", chunkqueue_length(cq));
+ log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414");
con->http_status = 414; /* Request-URI too large */
con->keep_alive = 0;
- connection_set_state(srv, con, CON_STATE_REQUEST_END);
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
}
break;
case CON_STATE_READ_POST:
diff --git a/src/http_auth.c b/src/http_auth.c
index 478a2f7..9976c15 100644
--- a/src/http_auth.c
+++ b/src/http_auth.c
@@ -350,19 +350,25 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha
/* from r to r + r_len is a rule */
if (0 == strncmp(r, "valid-user", r_len)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "valid-user cannot be combined with other require rules");
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
+ require->value);
return -1;
}
/* search for = in the rules */
if (NULL == (eq = strchr(r, '='))) {
- log_error_write(srv, __FILE__, __LINE__, "s", "= is missing");
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing the 'require' section in 'auth.require' failed: a = is missing",
+ require->value);
return -1;
}
/* = out of range */
if (eq > r + r_len) {
- log_error_write(srv, __FILE__, __LINE__, "s", "= out of range");
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing the 'require' section in 'auth.require' failed: = out of range",
+ require->value);
return -1;
}
diff --git a/src/http_auth_digest.c b/src/http_auth_digest.c
index 8f7086f..e440430 100644
--- a/src/http_auth_digest.c
+++ b/src/http_auth_digest.c
@@ -17,85 +17,3 @@ void CvtHex(IN HASH Bin, OUT HASHHEX Hex) {
Hex[HASHHEXLEN] = '\0';
}
-/* calculate H(A1) as per spec */
-void DigestCalcHA1(
- IN char * pszAlg,
- IN char * pszUserName,
- IN char * pszRealm,
- IN char * pszPassword,
- IN char * pszNonce,
- IN char * pszCNonce,
- OUT HASHHEX SessionKey
- )
-{
- MD5_CTX Md5Ctx;
- HASH HA1;
-
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)pszUserName, strlen(pszUserName));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszRealm, strlen(pszRealm));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszPassword, strlen(pszPassword));
- MD5_Final(HA1, &Md5Ctx);
- if (strcasecmp(pszAlg, "md5-sess") == 0) {
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)HA1, HASHLEN);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszNonce, strlen(pszNonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszCNonce, strlen(pszCNonce));
- MD5_Final(HA1, &Md5Ctx);
- }
- CvtHex(HA1, SessionKey);
-}
-
-/* calculate request-digest/response-digest as per HTTP Digest spec */
-void DigestCalcResponse(
- IN HASHHEX HA1, /* H(A1) */
- IN char * pszNonce, /* nonce from server */
- IN char * pszNonceCount, /* 8 hex digits */
- IN char * pszCNonce, /* client nonce */
- IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
- IN char * pszMethod, /* method from the request */
- IN char * pszDigestUri, /* requested URL */
- IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
- OUT HASHHEX Response /* request-digest or response-digest */
- )
-{
- MD5_CTX Md5Ctx;
- HASH HA2;
- HASH RespHash;
- HASHHEX HA2Hex;
-
- /* calculate H(A2) */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)pszMethod, strlen(pszMethod));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszDigestUri, strlen(pszDigestUri));
- if (strcasecmp(pszQop, "auth-int") == 0) {
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)HEntity, HASHHEXLEN);
- };
- MD5_Final(HA2, &Md5Ctx);
- CvtHex(HA2, HA2Hex);
-
- /* calculate response */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)HA1, HASHHEXLEN);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszNonce, strlen(pszNonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- if (*pszQop) {
- MD5_Update(&Md5Ctx, (unsigned char *)pszNonceCount, strlen(pszNonceCount));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszCNonce, strlen(pszCNonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszQop, strlen(pszQop));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- }
- MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
- MD5_Final(RespHash, &Md5Ctx);
- CvtHex(RespHash, Response);
-}
-
diff --git a/src/http_auth_digest.h b/src/http_auth_digest.h
index 3f11d70..8bffce4 100644
--- a/src/http_auth_digest.h
+++ b/src/http_auth_digest.h
@@ -16,30 +16,6 @@ typedef char HASHHEX[HASHHEXLEN+1];
#endif
#define OUT
-/* calculate H(A1) as per HTTP Digest spec */
-void DigestCalcHA1(
- IN char * pszAlg,
- IN char * pszUserName,
- IN char * pszRealm,
- IN char * pszPassword,
- IN char * pszNonce,
- IN char * pszCNonce,
- OUT HASHHEX SessionKey
- );
-
-/* calculate request-digest/response-digest as per HTTP Digest spec */
-void DigestCalcResponse(
- IN HASHHEX HA1, /* H(A1) */
- IN char * pszNonce, /* nonce from server */
- IN char * pszNonceCount, /* 8 hex digits */
- IN char * pszCNonce, /* client nonce */
- IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
- IN char * pszMethod, /* method from the request */
- IN char * pszDigestUri, /* requested URL */
- IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
- OUT HASHHEX Response /* request-digest or response-digest */
- );
-
void CvtHex(
IN HASH Bin,
OUT HASHHEX Hex
diff --git a/src/keyvalue.c b/src/keyvalue.c
index c438a43..b26588f 100644
--- a/src/keyvalue.c
+++ b/src/keyvalue.c
@@ -29,6 +29,7 @@ static keyvalue http_methods[] = {
{ HTTP_METHOD_CHECKIN, "CHECKIN" },
{ HTTP_METHOD_UNCHECKOUT, "UNCHECKOUT" },
{ HTTP_METHOD_VERSION_CONTROL, "VERSION-CONTROL" },
+ { HTTP_METHOD_CONNECT, "CONNECT" },
{ HTTP_METHOD_UNSET, NULL }
};
diff --git a/src/keyvalue.h b/src/keyvalue.h
index 7c78037..e1c940f 100644
--- a/src/keyvalue.h
+++ b/src/keyvalue.h
@@ -27,7 +27,8 @@ typedef enum {
HTTP_METHOD_CHECKIN,
HTTP_METHOD_VERSION_CONTROL,
HTTP_METHOD_UNCHECKOUT,
- HTTP_METHOD_LABEL
+ HTTP_METHOD_LABEL,
+ HTTP_METHOD_CONNECT
} http_method_t;
typedef enum { HTTP_VERSION_UNSET = -1, HTTP_VERSION_1_0, HTTP_VERSION_1_1 } http_version_t;
diff --git a/src/mod_access.c b/src/mod_access.c
index aa8d16f..f3f7071 100644
--- a/src/mod_access.c
+++ b/src/mod_access.c
@@ -129,11 +129,21 @@ URIHANDLER_FUNC(mod_access_uri_handler) {
if (ct_len > s_len) continue;
if (ds->value->used == 0) continue;
-
- if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
- con->http_status = 403;
+
+ /* if we have a case-insensitive FS we have to lower-case the URI here too */
+
+ if (con->conf.force_lowercase_filenames) {
+ if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+ con->http_status = 403;
- return HANDLER_FINISHED;
+ return HANDLER_FINISHED;
+ }
+ } else {
+ if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+ con->http_status = 403;
+
+ return HANDLER_FINISHED;
+ }
}
}
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 703107c..9b791d4 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -193,11 +193,23 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
/* search auth-directives for path */
for (k = 0; k < p->conf.auth_require->used; k++) {
- if (p->conf.auth_require->data[k]->key->used == 0) continue;
-
- if (0 == strncmp(con->uri.path->ptr, p->conf.auth_require->data[k]->key->ptr, p->conf.auth_require->data[k]->key->used - 1)) {
- auth_required = 1;
- break;
+ buffer *req = p->conf.auth_require->data[k]->key;
+
+ if (req->used == 0) continue;
+ if (con->uri.path->used < req->used) continue;
+
+ /* if we have a case-insensitive FS we have to lower-case the URI here too */
+
+ if (con->conf.force_lowercase_filenames) {
+ if (0 == strncasecmp(con->uri.path->ptr, req->ptr, req->used - 1)) {
+ auth_required = 1;
+ break;
+ }
+ } else {
+ if (0 == strncmp(con->uri.path->ptr, req->ptr, req->used - 1)) {
+ auth_required = 1;
+ break;
+ }
}
}
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index d747ccf..9480032 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -5,7 +5,6 @@
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/mman.h>
-#include <sys/fcntl.h>
#include <netinet/in.h>
@@ -22,6 +21,7 @@
#include <assert.h>
#include <stdio.h>
+#include <fcntl.h>
#include "server.h"
#include "keyvalue.h"
@@ -1278,7 +1278,7 @@ int mod_cgi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("cgi");
- p->handle_connection_close = cgi_connection_close_callback;
+ p->connection_reset = cgi_connection_close_callback;
p->handle_subrequest_start = cgi_is_handled;
p->handle_subrequest = mod_cgi_handle_subrequest;
#if 0
diff --git a/src/mod_cml.c b/src/mod_cml.c
index def16c7..0be9747 100644
--- a/src/mod_cml.c
+++ b/src/mod_cml.c
@@ -47,6 +47,7 @@ FREE_FUNC(mod_cml_free) {
buffer_free(s->ext);
buffer_free(s->mc_namespace);
+ buffer_free(s->power_magnet);
array_free(s->mc_hosts);
#if defined(HAVE_MEMCACHE_H)
@@ -78,6 +79,7 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) {
{ "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -92,6 +94,7 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) {
s->ext = buffer_init();
s->mc_hosts = array_init();
s->mc_namespace = buffer_init();
+ s->power_magnet = buffer_init();
#if defined(HAVE_MEMCACHE_H)
s->mc = NULL;
#endif
@@ -99,6 +102,7 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) {
cv[0].destination = s->ext;
cv[1].destination = s->mc_hosts;
cv[2].destination = s->mc_namespace;
+ cv[3].destination = s->power_magnet;
p->config_storage[i] = s;
@@ -144,6 +148,7 @@ static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p
PATCH(mc);
#endif
PATCH(mc_namespace);
+ PATCH(power_magnet);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
@@ -165,6 +170,8 @@ static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p
#endif
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
PATCH(mc_namespace);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
+ PATCH(power_magnet);
}
}
}
@@ -289,36 +296,11 @@ int cache_get_session_id(server *srv, connection *con, plugin_data *p) {
}
-
-URIHANDLER_FUNC(mod_cml_is_handled) {
- int ct_len, s_len;
+int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
buffer *b;
char *c;
- buffer *fn = con->physical.path;
- plugin_data *p = p_d;
int ret;
-
- if (fn->used == 0) return HANDLER_ERROR;
-
- mod_cml_patch_connection(srv, con, p);
-
- buffer_reset(p->basedir);
- buffer_reset(p->baseurl);
- buffer_reset(p->session_id);
- buffer_reset(p->trigger_handler);
-
- if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
-
- ct_len = p->conf.ext->used - 1;
- s_len = fn->used - 1;
-
- if (s_len < ct_len) return HANDLER_GO_ON;
-
- if (0 != strncmp(fn->ptr + s_len - ct_len, p->conf.ext->ptr, ct_len)) {
- /* not my job */
- return HANDLER_GO_ON;
- }
-
+
/* cleanup basedir */
b = p->baseurl;
buffer_copy_string_buffer(b, con->uri.path);
@@ -330,7 +312,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
}
b = p->basedir;
- buffer_copy_string_buffer(b, fn);
+ buffer_copy_string_buffer(b, con->physical.path);
for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
if (*c == '/') {
@@ -338,6 +320,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
*(c+1) = '\0';
}
+
/* prepare variables
* - session-id
* - cookie-based
@@ -346,9 +329,82 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
cache_get_session_id(srv, con, p);
- ret = cache_parse_lua(srv, con, p, fn);
+ return cache_parse_lua(srv, con, p, cml_file);
+
+}
+
+URIHANDLER_FUNC(mod_cml_power_magnet) {
+ plugin_data *p = p_d;
+
+ mod_cml_patch_connection(srv, con, p);
+
+ buffer_reset(p->basedir);
+ buffer_reset(p->baseurl);
+ buffer_reset(p->session_id);
+ buffer_reset(p->trigger_handler);
+
+ if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
+
+ /*
+ * power-magnet:
+ * cml.power-magnet = server.docroot + "/rewrite.cml"
+ *
+ * is called on EACH request, take the original REQUEST_URI and modifies the
+ * request header as neccesary.
+ *
+ * First use:
+ * if file_exists("/maintainance.html") {
+ * output_include = ( "/maintainance.html" )
+ * return CACHE_HIT
+ * }
+ *
+ * as we only want to rewrite HTML like requests we should cover it in a conditional
+ *
+ * */
+
+ switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
+ case -1:
+ /* error */
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
+ }
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
+ case 0:
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
+ }
+ /* cache-hit */
+ buffer_reset(con->physical.path);
+ return HANDLER_FINISHED;
+ case 1:
+ /* cache miss */
+ return HANDLER_GO_ON;
+ default:
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
+ }
+}
+
+URIHANDLER_FUNC(mod_cml_is_handled) {
+ plugin_data *p = p_d;
+
+ if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
+
+ mod_cml_patch_connection(srv, con, p);
+
+ buffer_reset(p->basedir);
+ buffer_reset(p->baseurl);
+ buffer_reset(p->session_id);
+ buffer_reset(p->trigger_handler);
+
+ if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
- switch(ret) {
+ if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
+ return HANDLER_GO_ON;
+ }
+
+ switch(cache_call_lua(srv, con, p, con->physical.path)) {
case -1:
/* error */
if (con->conf.log_request_handling) {
@@ -369,9 +425,10 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
}
/* cache miss */
return HANDLER_COMEBACK;
+ default:
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
}
-
- return 0;
}
int mod_cml_plugin_init(plugin *p) {
@@ -383,6 +440,7 @@ int mod_cml_plugin_init(plugin *p) {
p->set_defaults = mod_cml_set_defaults;
p->handle_subrequest_start = mod_cml_is_handled;
+ p->handle_physical = mod_cml_power_magnet;
p->data = NULL;
diff --git a/src/mod_cml.h b/src/mod_cml.h
index 9b09877..a2e9df4 100644
--- a/src/mod_cml.h
+++ b/src/mod_cml.h
@@ -22,6 +22,7 @@ typedef struct {
#if defined(HAVE_MEMCACHE_H)
struct memcache *mc;
#endif
+ buffer *power_magnet;
} plugin_config;
typedef struct {
diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c
index 5023b43..4e780e1 100644
--- a/src/mod_cml_lua.c
+++ b/src/mod_cml_lua.c
@@ -247,19 +247,19 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
}
- if (!lua_to_c_is_table(L, "output_include")) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "output_include is missing or not a table");
- ret = -1;
-
- goto error;
- }
-
if (ret == 0) {
/* up to now it is a cache-hit, check if all files exist */
int curelem;
time_t mtime = 0;
+
+ if (!lua_to_c_is_table(L, "output_include")) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "output_include is missing or not a table");
+ ret = -1;
+
+ goto error;
+ }
lua_pushstring(L, "output_include");
@@ -376,13 +376,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
}
}
- if (ret == 1 && buffer_is_empty(p->trigger_handler)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "cache-miss, but not trigger_handler set");
- ret = -1;
- }
-
- if (ret == 1) {
+ if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
/* cache-miss */
buffer_copy_string_buffer(con->uri.path, p->baseurl);
buffer_append_string_buffer(con->uri.path, p->trigger_handler);
diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
index 9b06fdb..69eb1e9 100644
--- a/src/mod_dirlisting.c
+++ b/src/mod_dirlisting.c
@@ -51,6 +51,9 @@ typedef struct {
unsigned short dir_listing;
unsigned short hide_dot_files;
unsigned short show_readme;
+ unsigned short hide_readme_file;
+ unsigned short show_header;
+ unsigned short hide_header_file;
excludes_buffer *excludes;
@@ -62,6 +65,7 @@ typedef struct {
PLUGIN_DATA;
buffer *tmp_buf;
+ buffer *content_charset;
plugin_config **config_storage;
@@ -144,7 +148,9 @@ INIT_FUNC(mod_dirlisting_init) {
plugin_data *p;
p = calloc(1, sizeof(*p));
+
p->tmp_buf = buffer_init();
+ p->content_charset = buffer_init();
return p;
}
@@ -174,6 +180,7 @@ FREE_FUNC(mod_dirlisting_free) {
}
buffer_free(p->tmp_buf);
+ buffer_free(p->content_charset);
free(p);
@@ -228,13 +235,16 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
size_t i = 0;
config_values_t cv[] = {
- { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "dir-listing.external-css", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "dir-listing.encoding", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "dir-listing.show-readme", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "dir-listing.external-css", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "dir-listing.encoding", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "dir-listing.show-readme", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "dir-listing.hide-readme-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "dir-listing.show-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -253,6 +263,9 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
s->external_css = buffer_init();
s->hide_dot_files = 0;
s->show_readme = 0;
+ s->hide_readme_file = 0;
+ s->show_header = 0;
+ s->hide_header_file = 0;
s->encoding = buffer_init();
cv[0].destination = s->excludes;
@@ -261,7 +274,10 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
cv[3].destination = s->external_css;
cv[4].destination = s->encoding;
cv[5].destination = &(s->show_readme);
- cv[6].destination = &(s->dir_listing); /* old name */
+ cv[6].destination = &(s->hide_readme_file);
+ cv[7].destination = &(s->show_header);
+ cv[8].destination = &(s->hide_header_file);
+ cv[9].destination = &(s->dir_listing); /* old name */
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
@@ -287,6 +303,9 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH(hide_dot_files);
PATCH(encoding);
PATCH(show_readme);
+ PATCH(hide_readme_file);
+ PATCH(show_header);
+ PATCH(hide_header_file);
PATCH(excludes);
/* skip the first, the global context */
@@ -312,6 +331,12 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH(encoding);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
PATCH(show_readme);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
+ PATCH(hide_readme_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
+ PATCH(show_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
+ PATCH(hide_header_file);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
PATCH(excludes);
}
@@ -414,7 +439,7 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
"<head>\n"
"<title>Index of "
);
- buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_HTML);
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out, "</title>\n");
if (p->conf.external_css->used > 1) {
@@ -461,8 +486,27 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
);
}
- BUFFER_APPEND_STRING_CONST(out, "</head>\n<body>\n<h2>Index of ");
- buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_HTML);
+ BUFFER_APPEND_STRING_CONST(out, "</head>\n<body>\n");
+
+ /* HEADER.txt */
+ if (p->conf.show_header) {
+ stream s;
+ /* if we have a HEADER file, display it in <pre class="header"></pre> */
+
+ buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+ BUFFER_APPEND_SLASH(p->tmp_buf);
+ BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
+
+ if (-1 != stream_open(&s, p->tmp_buf)) {
+ BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
+ buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
+ BUFFER_APPEND_STRING_CONST(out, "</pre>");
+ }
+ stream_close(&s);
+ }
+
+ BUFFER_APPEND_STRING_CONST(out, "<h2>Index of ");
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out,
"</h2>\n"
"<div class=\"list\">\n"
@@ -504,7 +548,7 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data
if (-1 != stream_open(&s, p->tmp_buf)) {
BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
- buffer_append_string_encoded(out, s.start, s.size, ENCODING_HTML);
+ buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out, "</pre>");
}
stream_close(&s);
@@ -602,6 +646,15 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
continue;
}
+ if (p->conf.hide_readme_file) {
+ if (strcmp(dent->d_name, "README.txt") == 0)
+ continue;
+ }
+ if (p->conf.hide_header_file) {
+ if (strcmp(dent->d_name, "HEADER.txt") == 0)
+ continue;
+ }
+
/* compare d_name against excludes array
* elements, skipping any that match.
*/
@@ -691,7 +744,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
BUFFER_APPEND_STRING_CONST(out, "/\">");
- buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_HTML);
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out, "</a>/</td><td class=\"m\">");
buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">- &nbsp;</td><td class=\"t\">Directory</td></tr>\n");
@@ -747,7 +800,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
BUFFER_APPEND_STRING_CONST(out, "\">");
- buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_HTML);
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out, "</a></td><td class=\"m\">");
buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">");
@@ -764,7 +817,16 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
free(path);
http_list_directory_footer(srv, con, p, out);
- response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+
+ /* Insert possible charset to Content-Type */
+ if (buffer_is_empty(p->conf.encoding)) {
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ } else {
+ buffer_copy_string(p->content_charset, "text/html; charset=");
+ buffer_append_string_buffer(p->content_charset, p->conf.encoding);
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
+ }
+
con->file_finished = 1;
return 0;
diff --git a/src/mod_evasive.c b/src/mod_evasive.c
new file mode 100644
index 0000000..b9d19ca
--- /dev/null
+++ b/src/mod_evasive.c
@@ -0,0 +1,178 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+
+/**
+ * mod_evasive
+ *
+ * we indent to implement all features the mod_evasive from apache has
+ *
+ * - limit of connections per IP
+ * - provide a list of block-listed ip/networks (no access)
+ * - provide a white-list of ips/network which is not affected by the limit
+ * (hmm, conditionals might be enough)
+ * - provide a bandwidth limiter per IP
+ *
+ * started by:
+ * - w1zzard@techpowerup.com
+ */
+
+typedef struct {
+ unsigned short max_conns;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_evasive_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+FREE_FUNC(mod_evasive_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->max_conns = 0;
+
+ cv[0].destination = &(s->max_conns);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(max_conns);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
+ PATCH(max_conns);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_evasive_uri_handler) {
+ plugin_data *p = p_d;
+ size_t conns_by_ip = 0;
+ size_t j;
+
+ if (con->uri.path->used == 0) return HANDLER_GO_ON;
+
+ mod_evasive_patch_connection(srv, con, p);
+
+ /* no limit set, nothing to block */
+ if (p->conf.max_conns == 0) return HANDLER_GO_ON;
+
+ for (j = 0; j < srv->conns->used; j++) {
+ connection *c = srv->conns->ptr[j];
+
+ /* check if other connections are already actively serving data for the same IP
+ * we can only ban connections which are already behind the 'read request' state
+ * */
+ if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
+ c->state > CON_STATE_REQUEST_END) {
+ conns_by_ip++;
+
+ if (conns_by_ip > p->conf.max_conns) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
+ "turned away. Too many connections.");
+
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_evasive_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("evasive");
+
+ p->init = mod_evasive_init;
+ p->set_defaults = mod_evasive_set_defaults;
+ p->handle_uri_clean = mod_evasive_uri_handler;
+ p->cleanup = mod_evasive_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index 890062c..8b1be0a 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -69,20 +69,24 @@ typedef struct fcgi_proc {
size_t requests; /* see max_requests */
struct fcgi_proc *prev, *next; /* see first */
- time_t disable_ts; /* replace by host->something */
+ time_t disabled_until; /* this proc is disabled until, use something else until than */
int is_local;
- enum { PROC_STATE_UNSET, /* init-phase */
- PROC_STATE_RUNNING, /* alive */
- PROC_STATE_DIED_WAIT_FOR_PID,
- PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
- PROC_STATE_DIED, /* marked as dead, should be restarted */
- PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
+ enum {
+ PROC_STATE_UNSET, /* init-phase */
+ PROC_STATE_RUNNING, /* alive */
+ PROC_STATE_DIED_WAIT_FOR_PID,
+ PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
+ PROC_STATE_DIED, /* marked as dead, should be restarted */
+ PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
} state;
} fcgi_proc;
typedef struct {
+ /* the key that is used to reference this value */
+ buffer *id;
+
/* list of processes handling this extension
* sorted by lowest load
*
@@ -300,6 +304,8 @@ typedef struct {
buffer *path;
buffer *parse_response;
+
+ buffer *statuskey;
plugin_config **config_storage;
@@ -307,13 +313,19 @@ typedef struct {
} plugin_data;
/* connection specific data */
-typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
- FCGI_STATE_WRITE, FCGI_STATE_READ
+typedef enum {
+ FCGI_STATE_UNSET,
+ FCGI_STATE_INIT,
+ FCGI_STATE_CONNECT_DELAYED,
+ FCGI_STATE_PREPARE_WRITE,
+ FCGI_STATE_WRITE,
+ FCGI_STATE_READ
} fcgi_connection_state_t;
typedef struct {
fcgi_proc *proc;
fcgi_extension_host *host;
+ fcgi_extension *ext;
fcgi_connection_state_t state;
time_t state_timestamp;
@@ -325,8 +337,6 @@ typedef struct {
buffer *response_header;
- int delayed; /* flag to mark that the connect() is delayed */
-
size_t request_id;
int fd; /* fd to the fastcgi process */
int fde_ndx; /* index into the fd-event buffer */
@@ -348,7 +358,74 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc);
+data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
+ data_integer *di;
+
+ if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
+ /* not found, create it */
+
+ if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
+ di = data_integer_init();
+ }
+ buffer_copy_string_len(di->key, s, len);
+ di->value = 0;
+
+ array_insert_unique(srv->status, (data_unset *)di);
+ }
+ return di;
+}
+
+/* dummies of the statistic framework functions
+ * they will be moved to a statistics.c later */
+int status_counter_inc(server *srv, const char *s, size_t len) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ di->value++;
+
+ return 0;
+}
+
+int status_counter_dec(server *srv, const char *s, size_t len) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ if (di->value > 0) di->value--;
+
+ return 0;
+}
+
+int status_counter_set(server *srv, const char *s, size_t len, int val) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ di->value = val;
+ return 0;
+}
+
+int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
+ buffer_copy_string(b, "fastcgi.backend.");
+ buffer_append_string_buffer(b, host->id);
+ buffer_append_string(b, ".");
+ buffer_append_long(b, proc->id);
+
+ return 0;
+}
+
+int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
+#define CLEAN(x) \
+ fastcgi_status_copy_procname(b, host, proc); \
+ buffer_append_string(b, x); \
+ status_counter_set(srv, CONST_BUF_LEN(b), 0);
+
+ CLEAN(".disabled");
+ CLEAN(".died");
+ CLEAN(".overloaded");
+ CLEAN(".connected");
+ CLEAN(".load");
+
+#undef CLEAN
+
+ return 0;
+}
static handler_ctx * handler_ctx_init() {
handler_ctx * hctx;
@@ -366,8 +443,6 @@ static handler_ctx * handler_ctx_init() {
hctx->fd = -1;
- hctx->delayed = 0;
-
hctx->reconnects = 0;
hctx->send_content_body = 1;
@@ -413,6 +488,7 @@ fcgi_extension_host *fastcgi_host_init() {
f = calloc(1, sizeof(*f));
+ f->id = buffer_init();
f->host = buffer_init();
f->unixsocket = buffer_init();
f->docroot = buffer_init();
@@ -427,6 +503,7 @@ fcgi_extension_host *fastcgi_host_init() {
void fastcgi_host_free(fcgi_extension_host *h) {
if (!h) return;
+ buffer_free(h->id);
buffer_free(h->host);
buffer_free(h->unixsocket);
buffer_free(h->docroot);
@@ -540,6 +617,8 @@ INIT_FUNC(mod_fastcgi_init) {
p->path = buffer_init();
p->parse_response = buffer_init();
+
+ p->statuskey = buffer_init();
return p;
}
@@ -556,6 +635,7 @@ FREE_FUNC(mod_fastcgi_free) {
buffer_free(p->fcgi_env);
buffer_free(p->path);
buffer_free(p->parse_response);
+ buffer_free(p->statuskey);
if (p->config_storage) {
size_t i, j, n;
@@ -824,6 +904,7 @@ static int fcgi_spawn_connection(server *srv,
switch ((child = fork())) {
case 0: {
size_t i = 0;
+ char *c;
char_array env;
char_array arg;
@@ -888,6 +969,20 @@ static int fcgi_spawn_connection(server *srv,
parse_binpath(&arg, host->bin_path);
+ /* chdir into the base of the bin-path,
+ * search for the last / */
+ if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
+ *c = '\0';
+
+ /* change to the physical directory */
+ if (-1 == chdir(arg.ptr[0])) {
+ *c = '/';
+ log_error_write(srv, __FILE__, __LINE__, "sss", "chdir failed:", strerror(errno), arg.ptr[0]);
+ }
+ *c = '/';
+ }
+
+
/* exec the cgi */
execve(arg.ptr[0], arg.ptr, env.ptr);
@@ -1058,7 +1153,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
for (n = 0; n < da_ext->value->used; n++) {
data_array *da_host = (data_array *)da_ext->value->data[n];
- fcgi_extension_host *df;
+ fcgi_extension_host *host;
config_values_t fcv[] = {
{ "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
@@ -1094,54 +1189,56 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
return HANDLER_ERROR;
}
- df = fastcgi_host_init();
+ host = fastcgi_host_init();
- df->check_local = 1;
- df->min_procs = 4;
- df->max_procs = 4;
- df->max_load_per_proc = 1;
- df->idle_timeout = 60;
- df->mode = FCGI_RESPONDER;
- df->disable_time = 60;
- df->break_scriptfilename_for_php = 0;
- df->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
+ buffer_copy_string_buffer(host->id, da_host->key);
+
+ host->check_local = 1;
+ host->min_procs = 4;
+ host->max_procs = 4;
+ host->max_load_per_proc = 1;
+ host->idle_timeout = 60;
+ host->mode = FCGI_RESPONDER;
+ host->disable_time = 60;
+ host->break_scriptfilename_for_php = 0;
+ host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
- fcv[0].destination = df->host;
- fcv[1].destination = df->docroot;
+ fcv[0].destination = host->host;
+ fcv[1].destination = host->docroot;
fcv[2].destination = fcgi_mode;
- fcv[3].destination = df->unixsocket;
- fcv[4].destination = df->bin_path;
+ fcv[3].destination = host->unixsocket;
+ fcv[4].destination = host->bin_path;
- fcv[5].destination = &(df->check_local);
- fcv[6].destination = &(df->port);
- fcv[7].destination = &(df->min_procs);
- fcv[8].destination = &(df->max_procs);
- fcv[9].destination = &(df->max_load_per_proc);
- fcv[10].destination = &(df->idle_timeout);
- fcv[11].destination = &(df->disable_time);
+ fcv[5].destination = &(host->check_local);
+ fcv[6].destination = &(host->port);
+ fcv[7].destination = &(host->min_procs);
+ fcv[8].destination = &(host->max_procs);
+ fcv[9].destination = &(host->max_load_per_proc);
+ fcv[10].destination = &(host->idle_timeout);
+ fcv[11].destination = &(host->disable_time);
- fcv[12].destination = df->bin_env;
- fcv[13].destination = df->bin_env_copy;
- fcv[14].destination = &(df->break_scriptfilename_for_php);
- fcv[15].destination = &(df->allow_xsendfile);
- fcv[16].destination = df->strip_request_uri;
+ fcv[12].destination = host->bin_env;
+ fcv[13].destination = host->bin_env_copy;
+ fcv[14].destination = &(host->break_scriptfilename_for_php);
+ fcv[15].destination = &(host->allow_xsendfile);
+ fcv[16].destination = host->strip_request_uri;
if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
return HANDLER_ERROR;
}
- if ((!buffer_is_empty(df->host) || df->port) &&
- !buffer_is_empty(df->unixsocket)) {
+ if ((!buffer_is_empty(host->host) || host->port) &&
+ !buffer_is_empty(host->unixsocket)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"either host+port or socket");
return HANDLER_ERROR;
}
- if (!buffer_is_empty(df->unixsocket)) {
+ if (!buffer_is_empty(host->unixsocket)) {
/* unix domain socket */
- if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
+ if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
log_error_write(srv, __FILE__, __LINE__, "s",
"path of the unixdomain socket is too large");
return HANDLER_ERROR;
@@ -1149,8 +1246,8 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
} else {
/* tcp/ip */
- if (buffer_is_empty(df->host) &&
- buffer_is_empty(df->bin_path)) {
+ if (buffer_is_empty(host->host) &&
+ buffer_is_empty(host->bin_path)) {
log_error_write(srv, __FILE__, __LINE__, "sbbbs",
"missing key (string):",
da->key,
@@ -1159,7 +1256,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
"host");
return HANDLER_ERROR;
- } else if (df->port == 0) {
+ } else if (host->port == 0) {
log_error_write(srv, __FILE__, __LINE__, "sbbbs",
"missing key (short):",
da->key,
@@ -1170,37 +1267,37 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
}
}
- if (!buffer_is_empty(df->bin_path)) {
+ if (!buffer_is_empty(host->bin_path)) {
/* a local socket + self spawning */
size_t pno;
/* HACK: just to make sure the adaptive spawing is disabled */
- df->min_procs = df->max_procs;
+ host->min_procs = host->max_procs;
- if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
- if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
+ if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
+ if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
"--- fastcgi spawning local",
- "\n\tproc:", df->bin_path,
- "\n\tport:", df->port,
- "\n\tsocket", df->unixsocket,
- "\n\tmin-procs:", df->min_procs,
- "\n\tmax-procs:", df->max_procs);
+ "\n\tproc:", host->bin_path,
+ "\n\tport:", host->port,
+ "\n\tsocket", host->unixsocket,
+ "\n\tmin-procs:", host->min_procs,
+ "\n\tmax-procs:", host->max_procs);
}
- for (pno = 0; pno < df->min_procs; pno++) {
+ for (pno = 0; pno < host->min_procs; pno++) {
fcgi_proc *proc;
proc = fastcgi_process_init();
- proc->id = df->num_procs++;
- df->max_id++;
+ proc->id = host->num_procs++;
+ host->max_id++;
- if (buffer_is_empty(df->unixsocket)) {
- proc->port = df->port + pno;
+ if (buffer_is_empty(host->unixsocket)) {
+ proc->port = host->port + pno;
} else {
- buffer_copy_string_buffer(proc->socket, df->unixsocket);
+ buffer_copy_string_buffer(proc->socket, host->unixsocket);
buffer_append_string(proc->socket, "-");
buffer_append_long(proc->socket, pno);
}
@@ -1208,49 +1305,53 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
"--- fastcgi spawning",
- "\n\tport:", df->port,
- "\n\tsocket", df->unixsocket,
- "\n\tcurrent:", pno, "/", df->min_procs);
+ "\n\tport:", host->port,
+ "\n\tsocket", host->unixsocket,
+ "\n\tcurrent:", pno, "/", host->min_procs);
}
- if (fcgi_spawn_connection(srv, p, df, proc)) {
+ if (fcgi_spawn_connection(srv, p, host, proc)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"[ERROR]: spawning fcgi failed.");
return HANDLER_ERROR;
}
+
+ fastcgi_status_init(srv, p->statuskey, host, proc);
- proc->next = df->first;
- if (df->first) df->first->prev = proc;
+ proc->next = host->first;
+ if (host->first) host->first->prev = proc;
- df->first = proc;
+ host->first = proc;
}
} else {
- fcgi_proc *fp;
+ fcgi_proc *proc;
- fp = fastcgi_process_init();
- fp->id = df->num_procs++;
- df->max_id++;
- df->active_procs++;
- fp->state = PROC_STATE_RUNNING;
+ proc = fastcgi_process_init();
+ proc->id = host->num_procs++;
+ host->max_id++;
+ host->active_procs++;
+ proc->state = PROC_STATE_RUNNING;
- if (buffer_is_empty(df->unixsocket)) {
- fp->port = df->port;
+ if (buffer_is_empty(host->unixsocket)) {
+ proc->port = host->port;
} else {
- buffer_copy_string_buffer(fp->socket, df->unixsocket);
+ buffer_copy_string_buffer(proc->socket, host->unixsocket);
}
- df->first = fp;
+ fastcgi_status_init(srv, p->statuskey, host, proc);
+
+ host->first = proc;
- df->min_procs = 1;
- df->max_procs = 1;
+ host->min_procs = 1;
+ host->max_procs = 1;
}
if (!buffer_is_empty(fcgi_mode)) {
if (strcmp(fcgi_mode->ptr, "responder") == 0) {
- df->mode = FCGI_RESPONDER;
+ host->mode = FCGI_RESPONDER;
} else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {
- df->mode = FCGI_AUTHORIZER;
- if (buffer_is_empty(df->docroot)) {
+ host->mode = FCGI_AUTHORIZER;
+ if (buffer_is_empty(host->docroot)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: docroot is required for authorizer mode.");
return HANDLER_ERROR;
@@ -1261,9 +1362,9 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
fcgi_mode, "(ignored, mode set to responder)");
}
}
-
+
/* if extension already exists, take it */
- fastcgi_extension_insert(s->exts, da_ext->key, df);
+ fastcgi_extension_insert(s->exts, da_ext->key, host);
}
}
}
@@ -1327,7 +1428,6 @@ static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
return 0;
}
-
void fcgi_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
@@ -1360,6 +1460,13 @@ void fcgi_connection_close(server *srv, handler_ctx *hctx) {
/* after the connect the process gets a load */
hctx->proc->load--;
+ status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".load");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddb",
"release proc:",
@@ -1397,11 +1504,13 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
* we have a connection but the child died by some other reason
*
*/
-
- fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
- fdevent_unregister(srv->ev, hctx->fd);
- close(hctx->fd);
- srv->cur_fds--;
+
+ 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--;
+ }
fcgi_requestid_del(srv, p, hctx->request_id);
@@ -1416,9 +1525,14 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
hctx->fd,
hctx->proc->pid, hctx->proc->socket);
}
-
- hctx->proc->load--;
- fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
+
+ if (hctx->proc) {
+ hctx->proc->load--;
+ fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
+ }
+
+ /* perhaps another host gives us more luck */
+ hctx->host = NULL;
return 0;
}
@@ -1491,7 +1605,15 @@ static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_
* 1 not connected yet
*/
-static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
+typedef enum {
+ CONNECTION_UNSET,
+ CONNECTION_OK,
+ CONNECTION_DELAYED, /* retry after event, take same host */
+ CONNECTION_OVERLOADED, /* disable for 1 seconds, take another backend */
+ CONNECTION_DEAD /* disable for 60 seconds, take another backend */
+} connection_result_t;
+
+static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) {
struct sockaddr *fcgi_addr;
struct sockaddr_in fcgi_addr_in;
#ifdef HAVE_SYS_UN_H
@@ -1540,57 +1662,37 @@ static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
errno == EALREADY ||
errno == EINTR) {
if (hctx->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "connect delayed, will continue later:", fcgi_fd);
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "connect delayed, will continue later:", host->host);
}
- return 1;
+ return CONNECTION_DELAYED;
} else if (errno == EAGAIN) {
-#if 0
- if(hctx->delayed == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sdsdsdb",
- "need reconnect, will continue later:", fcgi_fd,
- "reconnects:", hctx->reconnects,
- "load:", host->load,
- host->unixsocket);
+ if (hctx->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
+ "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
+ "The load for this fastcgi backend is:", proc->load);
}
-#endif
- hctx->reconnects++;
- return -1;
+
+ return CONNECTION_OVERLOADED;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sdsddb",
- "connect failed:", fcgi_fd,
- strerror(errno), errno,
+ log_error_write(srv, __FILE__, __LINE__, "ssdb",
+ "connect failed:",
+ strerror(errno),
proc->port, proc->socket);
-#if 0
- if (errno == EAGAIN) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
- "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
- "The load for this fastcgi backend is:", proc->load);
- }
-#endif
-
- return -1;
+ return CONNECTION_DEAD;
}
}
-#if 0
- if(hctx->delayed == 1) {
- log_error_write(srv, __FILE__, __LINE__, "sdsdsdb",
- "reconnected:", fcgi_fd,
- "reconnects:", hctx->reconnects,
- "load:", host->load,
- host->unixsocket);
- }
-#endif
+
hctx->reconnects = 0;
if (hctx->conf.debug > 1) {
log_error_write(srv, __FILE__, __LINE__, "sd",
"connect succeeded: ", fcgi_fd);
}
- return 0;
+ return CONNECTION_OK;
}
static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
@@ -1639,9 +1741,15 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
for (j = 0; j < ds->key->used - 1; j++) {
- srv->tmp_buf->ptr[srv->tmp_buf->used++] =
- isalpha((unsigned char)ds->key->ptr[j]) ?
- toupper((unsigned char)ds->key->ptr[j]) : '_';
+ char c = '_';
+ if (light_isalpha(ds->key->ptr[j])) {
+ /* upper-case */
+ c = ds->key->ptr[j] & ~32;
+ } else if (light_isdigit(ds->key->ptr[j])) {
+ /* copy */
+ c = ds->key->ptr[j];
+ }
+ srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
}
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
@@ -2156,7 +2264,7 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
/* no header */
buffer_free(packet->b);
- log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header to small");
+ log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header too small");
return -1;
}
@@ -2260,11 +2368,12 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
b->used = r + 1; /* one extra for the fake \0 */
b->ptr[b->used - 1] = '\0';
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssdsdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsbsd",
"unexpected end-of-file (perhaps the fastcgi process died):",
"pid:", proc->pid,
- "fcgi-fd:", fcgi_fd,
- "remote-fd:", con->fd);
+ "socket:", proc->socket,
+ "host:", host->host,
+ "port:", proc->port);
return -1;
}
@@ -2279,9 +2388,6 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
/* check if we have at least one packet */
if (0 != fastcgi_get_packet(srv, hctx, &packet)) {
/* no full packet */
-
- hctx->delayed = 1;
-
break;
}
@@ -2546,7 +2652,7 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
proc->pid);
}
- if (0 == proc->is_local) {
+ if (!proc->is_local) {
/*
* external servers might get disabled
*
@@ -2554,10 +2660,15 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
*/
if ((proc->state == PROC_STATE_DISABLED) &&
- (srv->cur_ts - proc->disable_ts > host->disable_time)) {
+ (srv->cur_ts > proc->disabled_until)) {
proc->state = PROC_STATE_RUNNING;
host->active_procs++;
+ fastcgi_status_copy_procname(p->statuskey, host, proc);
+ buffer_append_string(p->statuskey, ".disabled");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 0);
+
log_error_write(srv, __FILE__, __LINE__, "sbdb",
"fcgi-server re-enabled:",
host->host, host->port,
@@ -2626,7 +2737,6 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
return 0;
}
-
static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
fcgi_extension_host *host= hctx->host;
@@ -2645,10 +2755,60 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
host->unixsocket->used);
return HANDLER_ERROR;
}
+
+ /* we can't handle this in the switch as we have to fall through in it */
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
+ int socket_error;
+ socklen_t socket_error_len = sizeof(socket_error);
+
+ /* try to finish the connect() */
+ if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "getsockopt failed:", strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+ if (socket_error != 0) {
+ if (!hctx->proc->is_local || p->conf.debug) {
+ /* local procs get restarted */
+
+ log_error_write(srv, __FILE__, __LINE__, "sssd",
+ "establishing connection failed:", strerror(socket_error),
+ "port:", hctx->proc->port);
+ }
+ hctx->proc->disabled_until = srv->cur_ts + 10;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".died");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ return HANDLER_ERROR;
+ }
+ /* go on with preparing the request */
+ hctx->state = FCGI_STATE_PREPARE_WRITE;
+ }
+
switch(hctx->state) {
+ case FCGI_STATE_CONNECT_DELAYED:
+ /* should never happen */
+ break;
case FCGI_STATE_INIT:
+ /* do we have a running process for this host (max-procs) ? */
+
+ for (hctx->proc = hctx->host->first;
+ hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
+ hctx->proc = hctx->proc->next);
+
+ /* all childs are dead */
+ if (hctx->proc == NULL) {
+ hctx->fde_ndx = -1;
+
+ return HANDLER_ERROR;
+ }
+
ret = host->unixsocket->used ? AF_UNIX : AF_INET;
if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
@@ -2672,80 +2832,88 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss",
- "fcntl failed: ", strerror(errno));
+ "fcntl failed:", strerror(errno));
return HANDLER_ERROR;
}
-
- /* fall through */
- case FCGI_STATE_CONNECT:
- if (hctx->state == FCGI_STATE_INIT || hctx->delayed == 1) {
- for (hctx->proc = hctx->host->first;
- hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
- hctx->proc = hctx->proc->next);
-
- /* all childs are dead */
- if (hctx->proc == NULL) {
- hctx->fde_ndx = -1;
-
- return HANDLER_ERROR;
- }
- if (hctx->proc->is_local) {
- hctx->pid = hctx->proc->pid;
- }
+ if (hctx->proc->is_local) {
+ hctx->pid = hctx->proc->pid;
+ }
- switch (fcgi_establish_connection(srv, hctx)) {
- case 1:
- fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
-
- /* connection is in progress, wait for an event and call getsockopt() below */
-
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
- hctx->delayed = 0;
- return HANDLER_WAIT_FOR_EVENT;
- case -1:
- /* if ECONNREFUSED/EAGAIN re-try connect() */
-
- fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
- hctx->delayed = 1;
- return HANDLER_WAIT_FOR_EVENT;
- default:
- /* everything is ok, go on */
- break;
- }
+ switch (fcgi_establish_connection(srv, hctx)) {
+ case CONNECTION_DELAYED:
+ /* connection is in progress, wait for an event and call getsockopt() below */
+
+ fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
+ fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
+ return HANDLER_WAIT_FOR_EVENT;
+ case CONNECTION_OVERLOADED:
+ /* cool down the backend, it is overloaded
+ * -> EAGAIN */
- } else {
- int socket_error;
- socklen_t socket_error_len = sizeof(socket_error);
+ log_error_write(srv, __FILE__, __LINE__, "ssdsdb",
+ "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:"
+ "reconnects:", hctx->reconnects,
+ "load:", host->load,
+ host->unixsocket);
+
+
+ hctx->proc->disabled_until = srv->cur_ts + 2;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".overloaded");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
- /* try to finish the connect() */
- if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "getsockopt failed:", strerror(errno));
-
- return HANDLER_ERROR;
- }
- if (socket_error != 0) {
- if (!hctx->proc->is_local || p->conf.debug) {
- /* local procs get restarted */
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "establishing connection failed:", strerror(socket_error),
- "port:", hctx->proc->port);
- }
-
- return HANDLER_ERROR;
- }
+ return HANDLER_ERROR;
+ case CONNECTION_DEAD:
+ /* we got a hard error from the backend like
+ * - ECONNREFUSED for tcp-ip sockets
+ * - ENOENT for unix-domain-sockets
+ *
+ * for check if the host is back in 10 seconds
+ * */
+
+ hctx->proc->disabled_until = srv->cur_ts + 10;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".died");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ return HANDLER_ERROR;
+ case CONNECTION_OK:
+ /* everything is ok, go on */
+
+ fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
+
+ break;
+ case CONNECTION_UNSET:
+ break;
}
+ case FCGI_STATE_PREPARE_WRITE:
/* ok, we have the connection */
hctx->proc->load++;
hctx->proc->last_used = srv->cur_ts;
hctx->got_proc = 1;
-
+
+ status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
+ status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".connected");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".load");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddbdd",
"got proc:",
@@ -2766,9 +2934,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
"fcgi-request is already in use:", hctx->request_id);
}
- fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
/* fall through */
- case FCGI_STATE_PREPARE_WRITE:
fcgi_create_env(srv, hctx, hctx->request_id);
fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
@@ -2847,6 +3013,9 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
return HANDLER_WAIT_FOR_EVENT;
}
+
+/* might be called on fdevent after a connect() is delay too
+ * */
SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
plugin_data *p = p_d;
@@ -2858,83 +3027,118 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
/* not my job */
if (con->mode != p->id) return HANDLER_GO_ON;
+
+ /* we don't have a host yet, choose one
+ * -> this happens in the first round
+ * and when the host died and we have to select a new one */
+ if (hctx->host == NULL) {
+ size_t k;
+ int ndx, used = -1;
+
+ /* get best server */
+ for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
+ host = hctx->ext->hosts[k];
+
+ /* we should have at least one proc that can do somthing */
+ if (host->active_procs == 0) continue;
+
+ if (used == -1 || host->load < used) {
+ used = host->load;
+
+ ndx = k;
+ }
+ }
+ /* found a server */
+ if (ndx == -1) {
+ /* all hosts are down */
+
+ fcgi_connection_close(srv, hctx);
+
+ con->http_status = 500;
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+ }
+
+ host = hctx->ext->hosts[ndx];
+
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
+ */
+
+ /* init handler-context */
+ hctx->host = host;
+ hctx->proc = NULL;
+ } else {
+ host = hctx->host;
+ }
+
/* ok, create the request */
switch(fcgi_write_request(srv, hctx)) {
case HANDLER_ERROR:
proc = hctx->proc;
host = hctx->host;
-#if 0
- if (proc &&
- 0 == proc->is_local &&
- proc->state != PROC_STATE_DISABLED) {
- /* only disable remote servers as we don't manage them*/
-
- log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
- host->host,
- proc->port,
- proc->socket);
-
- /* disable this server */
- proc->disable_ts = srv->cur_ts;
- proc->state = PROC_STATE_DISABLED;
- host->active_procs--;
- }
-#endif
-
if (hctx->state == FCGI_STATE_INIT ||
- hctx->state == FCGI_STATE_CONNECT) {
+ hctx->state == FCGI_STATE_CONNECT_DELAYED) {
/* connect() or getsockopt() failed,
* restart the request-handling
*/
- if (proc && proc->is_local) {
+ if (proc) {
+ if (proc->is_local) {
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to fastcgi failed, restarting the request-handling:",
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sbdb",
+ "connect() to fastcgi failed, restarting the request-handling:",
host->host,
proc->port,
proc->socket);
- }
+ }
- /*
- * several hctx might reference the same proc
- *
- * Only one of them should mark the proc as dead all the other
- * ones should just take a new one.
- *
- * If a new proc was started with the old struct this might lead
- * the mark a perfect proc as dead otherwise
- *
- */
- if (proc->state == PROC_STATE_RUNNING &&
- hctx->pid == proc->pid) {
- proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
+ /*
+ * several hctx might reference the same proc
+ *
+ * Only one of them should mark the proc as dead all the other
+ * ones should just take a new one.
+ *
+ * If a new proc was started with the old struct this might lead
+ * the mark a perfect proc as dead otherwise
+ *
+ */
+ if (proc->state == PROC_STATE_RUNNING &&
+ hctx->pid == proc->pid) {
+ proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
+ }
+ } else {
+ proc->state = PROC_STATE_DISABLED;
}
+ host->active_procs--;
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".disabled");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 1);
}
+
fcgi_restart_dead_procs(srv, p, host);
-
- fcgi_connection_close(srv, hctx);
-
- buffer_reset(con->physical.path);
- con->mode = DIRECT;
- joblist_append(srv, con); /* really ? */
- /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
- * and hope that the childs will be restarted
- *
- */
-
- /* we might get into a LOOP here
- *
- * but how to handle this ?
- *
- * if we enter a endless loop, we will burn the CPU
- *
- * let this handle by the loop-detection
- */
+ /* cleanup this request and let the request handler start this request again */
+ if (hctx->reconnects < 5) {
+ fcgi_reconnect(srv, hctx);
+ joblist_append(srv, con); /* in case we come from the event-handler */
+
+ return HANDLER_WAIT_FOR_FD;
+ } else {
+ fcgi_connection_close(srv, hctx);
- return HANDLER_WAIT_FOR_FD;
+ buffer_reset(con->physical.path);
+ con->mode = DIRECT;
+ con->http_status = 500;
+ joblist_append(srv, con); /* in case we come from the event-handler */
+
+ return HANDLER_FINISHED;
+ }
} else {
fcgi_connection_close(srv, hctx);
@@ -3054,7 +3258,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
fcgi_reconnect(srv, hctx);
log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "response not sent, request not sent, reconnection.",
+ "response not received, request not sent, reconnecting.",
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
@@ -3062,7 +3266,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
}
log_error_write(srv, __FILE__, __LINE__, "sosdsd",
- "response not sent, request sent:", hctx->wb->bytes_out,
+ "response not received, request sent:", hctx->wb->bytes_out,
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
@@ -3093,7 +3297,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
}
if (revents & FDEVENT_OUT) {
- if (hctx->state == FCGI_STATE_CONNECT ||
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
hctx->state == FCGI_STATE_WRITE) {
/* we are allowed to send something out
*
@@ -3110,7 +3314,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
/* perhaps this issue is already handled */
if (revents & FDEVENT_HUP) {
- if (hctx->state == FCGI_STATE_CONNECT) {
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
/* getoptsock will catch this one (right ?)
*
* if we are in connect we might get a EINPROGRESS
@@ -3193,16 +3397,15 @@ static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
plugin_data *p = p_d;
size_t s_len;
- int used = -1;
- int ndx;
size_t k;
buffer *fn;
fcgi_extension *extension = NULL;
+ fcgi_extension_host *host = NULL;
/* Possibly, we processed already this request */
if (con->file_started == 1) return HANDLER_GO_ON;
-
- fn = con->uri.path;
+
+ fn = uri_path_handler ? con->uri.path : con->physical.path;
if (fn->used == 0) {
return HANDLER_ERROR;
@@ -3237,124 +3440,118 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
if (k == p->conf.exts->used) {
return HANDLER_GO_ON;
}
-
+
/* get best server */
- for (k = 0, ndx = -1; k < extension->used; k++) {
- fcgi_extension_host *host = extension->hosts[k];
-
+ for (k = 0; k < extension->used; k++) {
+ host = extension->hosts[k];
+
/* we should have at least one proc that can do somthing */
- if (host->active_procs == 0) continue;
+ if (host->active_procs == 0) {
+ host = NULL;
- if (used == -1 || host->load < used) {
- used = host->load;
-
- ndx = k;
+ continue;
}
+
+ /* we found one host that is alive */
+ break;
}
- /* found a server */
- if (ndx != -1) {
- fcgi_extension_host *host = extension->hosts[ndx];
+ if (!host) {
+ /* sorry, we don't have a server alive for this ext */
+ buffer_reset(con->physical.path);
+ con->http_status = 500;
- /*
- * if check-local is disabled, use the uri.path handler
- *
- */
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "no fcgi-handler found for:",
+ fn);
- /* init handler-context */
- if (uri_path_handler) {
- if (host->check_local == 0) {
- handler_ctx *hctx;
- char *pathinfo;
-
- hctx = handler_ctx_init();
-
- hctx->remote_conn = con;
- hctx->plugin_data = p;
- hctx->host = host;
- hctx->proc = NULL;
+ return HANDLER_FINISHED;
+ }
- hctx->conf.exts = p->conf.exts;
- hctx->conf.debug = p->conf.debug;
-
- con->plugin_ctx[p->id] = hctx;
-
- host->load++;
-
- con->mode = p->id;
-
- if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
- }
-
- /* the prefix is the SCRIPT_NAME,
- * everthing from start to the next slash
- * this is important for check-local = "disable"
- *
- * if prefix = /admin.fcgi
- *
- * /admin.fcgi/foo/bar
- *
- * SCRIPT_NAME = /admin.fcgi
- * PATH_INFO = /foo/bar
- *
- * if prefix = /fcgi-bin/
- *
- * /fcgi-bin/foo/bar
- *
- * SCRIPT_NAME = /fcgi-bin/foo
- * PATH_INFO = /bar
- *
- */
-
- /* the rewrite is only done for /prefix/? matches */
- if (extension->key->ptr[0] == '/' &&
- con->uri.path->used > extension->key->used &&
- NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
- /* rewrite uri.path and pathinfo */
-
- buffer_copy_string(con->request.pathinfo, pathinfo);
-
- con->uri.path->used -= con->request.pathinfo->used - 1;
- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
- }
- }
- return HANDLER_GO_ON;
- } else {
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
+ */
+
+ /* init handler-context */
+ if (uri_path_handler) {
+ if (host->check_local == 0) {
handler_ctx *hctx;
+ char *pathinfo;
+
hctx = handler_ctx_init();
hctx->remote_conn = con;
hctx->plugin_data = p;
- hctx->host = host;
- hctx->proc = NULL;
-
+ hctx->proc = NULL;
+ hctx->ext = extension;
+
+
hctx->conf.exts = p->conf.exts;
hctx->conf.debug = p->conf.debug;
-
+
con->plugin_ctx[p->id] = hctx;
-
- host->load++;
-
+
con->mode = p->id;
-
+
if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "handling it in mod_fastcgi");
}
+
+ /* the prefix is the SCRIPT_NAME,
+ * everthing from start to the next slash
+ * this is important for check-local = "disable"
+ *
+ * if prefix = /admin.fcgi
+ *
+ * /admin.fcgi/foo/bar
+ *
+ * SCRIPT_NAME = /admin.fcgi
+ * PATH_INFO = /foo/bar
+ *
+ * if prefix = /fcgi-bin/
+ *
+ * /fcgi-bin/foo/bar
+ *
+ * SCRIPT_NAME = /fcgi-bin/foo
+ * PATH_INFO = /bar
+ *
+ */
- return HANDLER_GO_ON;
+ /* the rewrite is only done for /prefix/? matches */
+ if (extension->key->ptr[0] == '/' &&
+ con->uri.path->used > extension->key->used &&
+ NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
+ /* rewrite uri.path and pathinfo */
+
+ buffer_copy_string(con->request.pathinfo, pathinfo);
+
+ con->uri.path->used -= con->request.pathinfo->used - 1;
+ con->uri.path->ptr[con->uri.path->used - 1] = '\0';
+ }
}
} else {
- /* no handler found */
- buffer_reset(con->physical.path);
- con->http_status = 500;
+ handler_ctx *hctx;
+ hctx = handler_ctx_init();
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "no fcgi-handler found for:",
- fn);
+ hctx->remote_conn = con;
+ hctx->plugin_data = p;
+ hctx->proc = NULL;
+ hctx->ext = extension;
- return HANDLER_FINISHED;
+ hctx->conf.exts = p->conf.exts;
+ hctx->conf.debug = p->conf.debug;
+
+ con->plugin_ctx[p->id] = hctx;
+
+ con->mode = p->id;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
+ }
}
+
return HANDLER_GO_ON;
}
@@ -3380,7 +3577,7 @@ JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
break;
- case FCGI_STATE_CONNECT:
+ case FCGI_STATE_CONNECT_DELAYED:
case FCGI_STATE_WRITE:
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
@@ -3598,7 +3795,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
int mod_fastcgi_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
+ p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("fastcgi");
p->init = mod_fastcgi_init;
diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
index ebe7657..bf13e09 100644
--- a/src/mod_mysql_vhost.c
+++ b/src/mod_mysql_vhost.c
@@ -413,7 +413,7 @@ int mod_mysql_vhost_plugin_init(plugin *p) {
p->init = mod_mysql_vhost_init;
p->cleanup = mod_mysql_vhost_cleanup;
- p->handle_connection_close = mod_mysql_vhost_handle_connection_close;
+ p->handle_request_done = mod_mysql_vhost_handle_connection_close;
p->set_defaults = mod_mysql_vhost_set_defaults;
p->handle_docroot = mod_mysql_vhost_handle_docroot;
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index c6a4660..6baf459 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -439,7 +439,12 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
- proxy_set_header(con, "X-Host", con->request.http_host->ptr);
+ /* http_host is NOT is just a pointer to a buffer
+ * which is NULL if it is not set */
+ if (con->request.http_host &&
+ !buffer_is_empty(con->request.http_host)) {
+ proxy_set_header(con, "X-Host", con->request.http_host->ptr);
+ }
proxy_set_header(con, "X-Forwarded-Proto", con->conf.is_ssl ? "https" : "http");
/* request header */
diff --git a/src/mod_scgi.c b/src/mod_scgi.c
index 06713e9..a27b28a 100644
--- a/src/mod_scgi.c
+++ b/src/mod_scgi.c
@@ -2677,7 +2677,7 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i
/* Possibly, we processed already this request */
if (con->file_started == 1) return HANDLER_GO_ON;
- fn = con->uri.path;
+ fn = uri_path_handler ? con->uri.path : con->physical.path;
if (fn->used == 0) {
return HANDLER_ERROR;
diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c
index 5139507..1ea5a50 100644
--- a/src/mod_secure_download.c
+++ b/src/mod_secure_download.c
@@ -37,7 +37,7 @@ typedef struct {
buffer *secret;
buffer *uri_prefix;
- time_t timeout;
+ unsigned short timeout;
} plugin_config;
typedef struct {
diff --git a/src/mod_setenv.c b/src/mod_setenv.c
index 001b238..9501554 100644
--- a/src/mod_setenv.c
+++ b/src/mod_setenv.c
@@ -12,6 +12,10 @@
/* plugin config for all request/connections */
typedef struct {
+ int handled; /* make sure that we only apply the headers once */
+} handler_ctx;
+
+typedef struct {
array *request_header;
array *response_header;
@@ -26,6 +30,21 @@ typedef struct {
plugin_config conf;
} plugin_data;
+static handler_ctx * handler_ctx_init() {
+ handler_ctx * hctx;
+
+ hctx = calloc(1, sizeof(*hctx));
+
+ hctx->handled = 0;
+
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+
/* init the plugin data */
INIT_FUNC(mod_setenv_init) {
plugin_data *p;
@@ -140,7 +159,22 @@ static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data
URIHANDLER_FUNC(mod_setenv_uri_handler) {
plugin_data *p = p_d;
size_t k;
-
+ handler_ctx *hctx;
+
+ if (con->plugin_ctx[p->id]) {
+ hctx = con->plugin_ctx[p->id];
+ } else {
+ hctx = handler_ctx_init();
+
+ con->plugin_ctx[p->id] = hctx;
+ }
+
+ if (hctx->handled) {
+ return HANDLER_GO_ON;
+ }
+
+ hctx->handled = 1;
+
mod_setenv_patch_connection(srv, con, p);
for (k = 0; k < p->conf.request_header->used; k++) {
@@ -181,6 +215,19 @@ URIHANDLER_FUNC(mod_setenv_uri_handler) {
return HANDLER_GO_ON;
}
+REQUESTDONE_FUNC(mod_setenv_reset) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (con->plugin_ctx[p->id]) {
+ handler_ctx_free(con->plugin_ctx[p->id]);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ return HANDLER_GO_ON;
+}
+
/* this function is called at dlopen() time and inits the callbacks */
int mod_setenv_plugin_init(plugin *p) {
@@ -192,6 +239,8 @@ int mod_setenv_plugin_init(plugin *p) {
p->set_defaults = mod_setenv_set_defaults;
p->cleanup = mod_setenv_free;
+ p->handle_request_done = mod_setenv_reset;
+
p->data = NULL;
return 0;
diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
index 6496689..cbc443d 100644
--- a/src/mod_staticfile.c
+++ b/src/mod_staticfile.c
@@ -372,17 +372,11 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
/* ignore certain extensions */
for (k = 0; k < p->conf.exclude_ext->used; k++) {
- int ct_len;
-
ds = (data_string *)p->conf.exclude_ext->data[k];
-
- ct_len = ds->value->used - 1;
-
- if (ct_len > s_len) continue;
if (ds->value->used == 0) continue;
-
- if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+
+ if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
return HANDLER_GO_ON;
}
}
@@ -446,13 +440,27 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
return HANDLER_FINISHED;
} else if (con->request.http_range && con->conf.range_requests) {
- /* content prepared, I'm done */
- con->file_finished = 1;
+ int do_range_request = 1;
+ /* check if we have a conditional GET */
+
+ if (NULL != (ds = array_get_element(con->request.headers, "If-Range"))) {
+ /* if the value is the same as our ETag, we do a Range-request,
+ * otherwise a full 200 */
+
+ if (!buffer_is_equal(ds->value, con->physical.etag)) {
+ do_range_request = 0;
+ }
+ }
+
+ if (do_range_request) {
+ /* content prepared, I'm done */
+ con->file_finished = 1;
- if (0 == http_response_parse_range(srv, con, p)) {
- con->http_status = 206;
+ if (0 == http_response_parse_range(srv, con, p)) {
+ con->http_status = 206;
+ }
+ return HANDLER_FINISHED;
}
- return HANDLER_FINISHED;
}
/* if we are still here, prepare body */
diff --git a/src/mod_status.c b/src/mod_status.c
index f69a1f4..f5a35e9 100644
--- a/src/mod_status.c
+++ b/src/mod_status.c
@@ -22,6 +22,8 @@
typedef struct {
buffer *config_url;
buffer *status_url;
+ buffer *statistics_url;
+
int sort;
} plugin_config;
@@ -84,6 +86,7 @@ FREE_FUNC(mod_status_free) {
plugin_config *s = p->config_storage[i];
buffer_free(s->status_url);
+ buffer_free(s->statistics_url);
buffer_free(s->config_url);
free(s);
@@ -104,7 +107,8 @@ SETDEFAULTS_FUNC(mod_status_set_defaults) {
config_values_t cv[] = {
{ "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
+ { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
+ { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -119,10 +123,12 @@ SETDEFAULTS_FUNC(mod_status_set_defaults) {
s->config_url = buffer_init();
s->status_url = buffer_init();
s->sort = 1;
+ s->statistics_url = buffer_init();
cv[0].destination = s->status_url;
cv[1].destination = s->config_url;
cv[2].destination = &(s->sort);
+ cv[3].destination = s->statistics_url;
p->config_storage[i] = s;
@@ -575,6 +581,40 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
return 0;
}
+static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ buffer *b, *m = p->module_list;
+ size_t i;
+ array *st = srv->status;
+
+ if (0 == st->used) {
+ /* we have nothing to send */
+ con->http_status = 204;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+ }
+
+ b = chunkqueue_get_append_buffer(con->write_queue);
+
+ for (i = 0; i < st->used; i++) {
+ size_t ndx = st->sorted[i];
+
+ buffer_append_string_buffer(b, st->data[ndx]->key);
+ buffer_append_string(b, ": ");
+ buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
+ buffer_append_string(b, "\n");
+ }
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
+
+ con->http_status = 200;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+}
+
+
static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
@@ -638,9 +678,9 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
mod_status_header_append(b, "Server-Features");
#ifdef HAVE_PCRE_H
- mod_status_row_append(b, "Rewrite Engine", "enabled");
+ mod_status_row_append(b, "RegEx Conditionals", "enabled");
#else
- mod_status_row_append(b, "Rewrite Engine", "disabled - pcre missing");
+ mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
#endif
mod_status_header_append(b, "Network Engine");
@@ -692,6 +732,7 @@ static int mod_status_patch_connection(server *srv, connection *con, plugin_data
PATCH(status_url);
PATCH(config_url);
PATCH(sort);
+ PATCH(statistics_url);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
@@ -711,6 +752,8 @@ static int mod_status_patch_connection(server *srv, connection *con, plugin_data
PATCH(config_url);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
PATCH(sort);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
+ PATCH(statistics_url);
}
}
}
@@ -729,6 +772,9 @@ static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
} else if (!buffer_is_empty(p->conf.config_url) &&
buffer_is_equal(p->conf.config_url, con->uri.path)) {
return mod_status_handle_server_config(srv, con, p_d);
+ } else if (!buffer_is_empty(p->conf.statistics_url) &&
+ buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
+ return mod_status_handle_server_statistics(srv, con, p_d);
}
return HANDLER_GO_ON;
diff --git a/src/mod_webdav.c b/src/mod_webdav.c
index 0e7a682..3306c73 100644
--- a/src/mod_webdav.c
+++ b/src/mod_webdav.c
@@ -291,6 +291,7 @@ static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data
PATCH(enabled);
PATCH(is_readonly);
+ PATCH(log_xml);
#ifdef USE_PROPPATCH
PATCH(sql);
@@ -1175,19 +1176,23 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
d.rel_path = buffer_init();
while(NULL != (de = readdir(dir))) {
- if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
- (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
+ if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
continue;
/* ignore the parent dir */
}
buffer_copy_string_buffer(d.path, dst->path);
BUFFER_APPEND_SLASH(d.path);
- buffer_append_string(d.path, de->d_name);
-
+
buffer_copy_string_buffer(d.rel_path, dst->rel_path);
BUFFER_APPEND_SLASH(d.rel_path);
- buffer_append_string(d.rel_path, de->d_name);
+
+ if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
+ /* don't append the . */
+ } else {
+ buffer_append_string(d.path, de->d_name);
+ buffer_append_string(d.rel_path, de->d_name);
+ }
buffer_reset(prop_200);
buffer_reset(prop_404);
@@ -1247,6 +1252,9 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
free(req_props);
}
+ buffer_free(prop_200);
+ buffer_free(prop_404);
+
buffer_append_string(b,"</D:multistatus>\n");
if (p->conf.log_xml) {
@@ -1531,10 +1539,10 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
buffer_path_simplify(p->uri.path, p->tmp_buf);
/* we now have a URI which is clean. transform it into a physical path */
- buffer_copy_string_buffer(p->physical.doc_root, con->conf.document_root);
+ buffer_copy_string_buffer(p->physical.doc_root, con->physical.doc_root);
buffer_copy_string_buffer(p->physical.rel_path, p->uri.path);
- if (con->conf.force_lower_case) {
+ if (con->conf.force_lowercase_filenames) {
buffer_to_lower(p->physical.rel_path);
}
diff --git a/src/network.c b/src/network.c
index 40e9bba..922009f 100644
--- a/src/network.c
+++ b/src/network.c
@@ -71,6 +71,7 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
const char *host;
buffer *b;
int is_unix_domain_socket = 0;
+ int fd;
#ifdef SO_ACCEPTFILTER
struct accept_filter_arg afa;
@@ -254,6 +255,33 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
addr_len = strlen(host) + sizeof(srv_socket->addr.un.sun_family);
#endif
+ /* check if the socket exists and try to connect to it. */
+ if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
+ close(fd);
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "server socket is still in use:",
+ host);
+
+
+ return -1;
+ }
+
+ /* connect failed */
+ switch(errno) {
+ case ECONNREFUSED:
+ unlink(host);
+ break;
+ case ENOENT:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "testing socket failed:",
+ host, strerror(errno));
+
+ return -1;
+ }
+
break;
default:
addr_len = 0;
@@ -262,7 +290,18 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
}
if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
- log_error_write(srv, __FILE__, __LINE__, "sds", "can't bind to port", port, strerror(errno));
+ switch(srv_socket->addr.plain.sa_family) {
+ case AF_UNIX:
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "can't bind to socket:",
+ host, strerror(errno));
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssds",
+ "can't bind to port:",
+ host, port, strerror(errno));
+ break;
+ }
return -1;
}
diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c
index 5628a94..5752385 100644
--- a/src/network_linux_sendfile.c
+++ b/src/network_linux_sendfile.c
@@ -173,6 +173,11 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd,
return -1;
}
}
+
+ if (r == 0) {
+ /* we got a event to write put we couldn't. remote side closed ? */
+ return -2;
+ }
c->offset += r;
cq->bytes_out += r;
diff --git a/src/plugin.c b/src/plugin.c
index b375017..e74d8b0 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -66,6 +66,7 @@ static void plugin_free(plugin *p) {
/*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
#endif
+#ifndef LIGHTTPD_STATIC
if (use_dlclose && p->lib) {
#ifdef __WIN32
FreeLibrary(p->lib);
@@ -73,6 +74,7 @@ static void plugin_free(plugin *p) {
dlclose(p->lib);
#endif
}
+#endif
free(p);
}
@@ -100,7 +102,23 @@ static int plugins_register(server *srv, plugin *p) {
*
*/
+#ifdef LIGHTTPD_STATIC
+int plugins_load(server *srv) {
+ plugin *p;
+#define PLUGIN_INIT(x)\
+ p = plugin_init(); \
+ if (x ## _plugin_init(p)) { \
+ log_error_write(srv, __FILE__, __LINE__, "ss", #x, "plugin init failed" ); \
+ plugin_free(p); \
+ return -1;\
+ }\
+ plugins_register(srv, p);
+
+#include "plugin-static.h"
+ return 0;
+}
+#else
int plugins_load(server *srv) {
plugin *p;
int (*init)(plugin *pl);
@@ -205,6 +223,7 @@ int plugins_load(server *srv) {
return 0;
}
+#endif
#define PLUGIN_TO_SLOT(x, y) \
handler_t plugins_call_##y(server *srv, connection *con) {\
diff --git a/src/request.c b/src/request.c
index 0935725..db58671 100644
--- a/src/request.c
+++ b/src/request.c
@@ -791,6 +791,12 @@ int http_request_parse(server *srv, connection *con) {
* -> (10.4.18) 417 (close)
*
* (not handled at all yet, we always send 417 here)
+ *
+ * What has to be added ?
+ * 1. handling of chunked request body
+ * 2. out-of-order sending from the HTTP/1.1 100 Continue
+ * header
+ *
*/
con->http_status = 417;
@@ -815,9 +821,14 @@ int http_request_parse(server *srv, connection *con) {
return 0;
}
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
- /* if dup, only the first one will survive */
+ /* Proxies sometimes send dup headers
+ * if they are the same we ignore the second
+ * if not, we raise an error */
if (!con->request.http_if_modified_since) {
con->request.http_if_modified_since = ds->value->ptr;
+ } else if (0 == strcasecmp(con->request.http_if_modified_since,
+ ds->value->ptr)) {
+ /* ignore it if they are the same */
} else {
con->http_status = 400;
con->keep_alive = 0;
@@ -963,22 +974,25 @@ int http_request_parse(server *srv, connection *con) {
return 0;
}
-
- /* check if we have read post data */
- if (con->request.http_method == HTTP_METHOD_POST
- || (con->request.http_method != HTTP_METHOD_GET
- && con->request.http_method != HTTP_METHOD_HEAD
- && con->request.http_method != HTTP_METHOD_OPTIONS
- && con_length_set)) {
-#if 0
- if (con->request.http_content_type == NULL) {
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_HEAD:
+ case HTTP_METHOD_OPTIONS:
+ /* content-length is forbidden for those */
+ if (con_length_set && con->request.content_length != 0) {
+ /* content-length is missing */
log_error_write(srv, __FILE__, __LINE__, "s",
- "Content-Length request, but content-type not set");
+ "GET/HEAD/OPTIONS with content-length -> 400");
+ con->keep_alive = 0;
+
+ con->http_status = 400;
+ return 0;
}
-#endif
-
- if (con_length_set == 0) {
+ break;
+ case HTTP_METHOD_POST:
+ /* content-length is required for them */
+ if (!con_length_set) {
/* content-length is missing */
log_error_write(srv, __FILE__, __LINE__, "s",
"POST-request, but content-length missing -> 411");
@@ -986,8 +1000,17 @@ int http_request_parse(server *srv, connection *con) {
con->http_status = 411;
return 0;
+
}
-
+ break;
+ default:
+ /* the may have a content-length */
+ break;
+ }
+
+
+ /* check if we have read post data */
+ if (con_length_set) {
/* don't handle more the SSIZE_MAX bytes in content-length */
if (con->request.content_length > SSIZE_MAX) {
con->http_status = 413;
diff --git a/src/response.c b/src/response.c
index 2617842..d955cec 100644
--- a/src/response.c
+++ b/src/response.c
@@ -133,6 +133,18 @@ handler_t http_response_prepare(server *srv, connection *con) {
/* no decision yet, build conf->filename */
if (con->mode == DIRECT && con->physical.path->used == 0) {
char *qstr;
+
+ /* we only come here when we have the parse the full request again
+ *
+ * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
+ * problem here as mod_setenv might get called multiple times
+ *
+ * fastcgi-auth might lead to a COMEBACK too
+ * fastcgi again dead server too
+ *
+ * mod_compress might add headers twice too
+ *
+ * */
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
@@ -334,7 +346,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
*
* convert to lower-case
*/
- if (con->conf.force_lower_case) {
+ if (con->conf.force_lowercase_filenames) {
buffer_to_lower(con->physical.rel_path);
}
diff --git a/src/server.c b/src/server.c
index 5c515e3..9eb9eb4 100644
--- a/src/server.c
+++ b/src/server.c
@@ -50,6 +50,10 @@
#include <sys/resource.h>
#endif
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
#ifndef __sgi
/* IRIX doesn't like the alarm based time() optimization */
/* #define USE_ALARM */
@@ -67,7 +71,11 @@ static void sigaction_handler(int sig, siginfo_t *si, void *context) {
switch (sig) {
case SIGTERM: srv_shutdown = 1; break;
- case SIGINT: graceful_shutdown = 1; break;
+ case SIGINT:
+ if (graceful_shutdown) srv_shutdown = 1;
+ else graceful_shutdown = 1;
+
+ break;
case SIGALRM: handle_sig_alarm = 1; break;
case SIGHUP: handle_sig_hup = 1; break;
case SIGCHLD: break;
@@ -77,7 +85,11 @@ static void sigaction_handler(int sig, siginfo_t *si, void *context) {
static void signal_handler(int sig) {
switch (sig) {
case SIGTERM: srv_shutdown = 1; break;
- case SIGINT: graceful_shutdown = 1; break;
+ case SIGINT:
+ if (graceful_shutdown) srv_shutdown = 1;
+ else graceful_shutdown = 1;
+
+ break;
case SIGALRM: handle_sig_alarm = 1; break;
case SIGHUP: handle_sig_hup = 1; break;
case SIGCHLD: break;
@@ -144,6 +156,7 @@ static server *server_init(void) {
CLEAN(config_context);
CLEAN(config_touched);
+ CLEAN(status);
#undef CLEAN
for (i = 0; i < FILE_CACHE_MAX; i++) {
@@ -241,6 +254,7 @@ static void server_free(server *srv) {
CLEAN(config_context);
CLEAN(config_touched);
+ CLEAN(status);
#undef CLEAN
joblist_free(srv, srv->joblist);
@@ -323,7 +337,7 @@ int main (int argc, char **argv) {
setlocale(LC_TIME, "C");
if (NULL == (srv = server_init())) {
- fprintf(stderr, "did this really happend ?\n");
+ fprintf(stderr, "did this really happen?\n");
return -1;
}
@@ -521,6 +535,12 @@ int main (int argc, char **argv) {
} else {
srv->max_fds = rlim.rlim_cur;
}
+
+ /* set core file rlimit, if enable_cores is set */
+ if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit(RLIMIT_CORE, &rlim);
+ }
#endif
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
/* don't raise the limit above FD_SET_SIZE */
@@ -593,6 +613,11 @@ int main (int argc, char **argv) {
initgroups(srv->srvconf.username->ptr, grp->gr_gid);
if (srv->srvconf.username->used) setuid(pwd->pw_uid);
#endif
+#ifdef HAVE_PRCTL
+ if (srv->srvconf.enable_cores) {
+ prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+ }
+#endif
} else {
#ifdef HAVE_GETRLIMIT
@@ -608,6 +633,13 @@ int main (int argc, char **argv) {
} else {
srv->max_fds = rlim.rlim_cur;
}
+
+ /* set core file rlimit, if enable_cores is set */
+ if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit(RLIMIT_CORE, &rlim);
+ }
+
#endif
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
/* don't raise the limit above FD_SET_SIZE */