summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArno Töll <arno@debian.org>2012-11-21 23:03:41 +0100
committerArno Töll <arno@debian.org>2012-11-21 23:03:41 +0100
commit6a6df8dc258631c6eaccb03bf08845241f6dfa4a (patch)
tree01eee8de64a85e5e2fef929050663ea2d3c850bd
parentec2cb646eff482dfe32955d01781b01211b0a77c (diff)
downloadlighttpd-6a6df8dc258631c6eaccb03bf08845241f6dfa4a.tar.gz
Imported Upstream version 1.4.12upstream/1.4.12
-rw-r--r--NEWS9
-rwxr-xr-xconfigure26
-rw-r--r--configure.in6
-rw-r--r--src/Makefile.am11
-rw-r--r--src/Makefile.in97
-rw-r--r--src/array.c24
-rw-r--r--src/base.h3
-rw-r--r--src/chunk.c19
-rw-r--r--src/chunk.h1
-rw-r--r--src/configfile-glue.c10
-rw-r--r--src/configparser.c293
-rw-r--r--src/configparser.y3
-rw-r--r--src/connections.c470
-rw-r--r--src/data_config.c28
-rw-r--r--src/data_count.c2
-rw-r--r--src/data_fastcgi.c2
-rw-r--r--src/data_integer.c2
-rw-r--r--src/data_string.c2
-rw-r--r--src/http_auth.c38
-rw-r--r--src/http_auth.h10
-rw-r--r--src/http_chunk.c3
-rw-r--r--src/mod_auth.c10
-rw-r--r--src/mod_cml_lua.c12
-rw-r--r--src/mod_fastcgi.c44
-rw-r--r--src/mod_magnet.c746
-rw-r--r--src/mod_magnet_cache.c137
-rw-r--r--src/mod_magnet_cache.h33
-rw-r--r--src/mod_mysql_vhost.c1
-rw-r--r--src/mod_ssi.c8
-rw-r--r--src/mod_webdav.c12
-rw-r--r--src/network.c2
-rw-r--r--src/network_freebsd_sendfile.c1
-rw-r--r--src/network_openssl.c25
-rw-r--r--src/network_writev.c45
-rw-r--r--src/server.c21
-rw-r--r--src/stat_cache.c118
-rw-r--r--src/status_counter.c60
-rw-r--r--src/status_counter.h14
-rwxr-xr-xtests/LightyTest.pm11
-rw-r--r--tests/Makefile.am5
-rw-r--r--tests/Makefile.in5
-rwxr-xr-xtests/cachable.t112
-rw-r--r--tests/lowercase.conf80
-rwxr-xr-xtests/lowercase.t94
44 files changed, 1997 insertions, 658 deletions
diff --git a/NEWS b/NEWS
index 4f3897c..ce33b15 100644
--- a/NEWS
+++ b/NEWS
@@ -3,13 +3,18 @@
NEWS
====
-- 1.4.12 -
+- 1.4.12 - 2006-09-23
* added experimental LOCK support for webdav
* added Content-Range support for PUT in webdav
* added support for += on empty arrays in config-files
* added ssl.cipher-list and ssl.use-sslv2
* added $HTTP["querystring"] conditional
+ * added mod_magnet as long-term replacement for mod_cml
+ * added work-around for a Opera Bug with SSL + Chunked-Encoding
+ * changed --print-config to print to stdout instead of stderr
+ * changed no longer use 0600 for new files with webdav. umask is
+ honored. Make sure you have set a proper umask.
* fixed upload hangs with SSL
* fixed connection drops with SSL (aka bad retry)
* fixed path traversal with \ on cygwin
@@ -23,6 +28,8 @@ NEWS
* fixed empty FCGI_STDERR packets
* fixed conditional server.allow-http-11
* fixed handling of follow-symlink + lstat()
+ * fixed SIGHUP handling if max-workers is used
+ * fixed "Software caused connection abort" messages on FreeBSD
- 1.4.11 - 2006-03-09
diff --git a/configure b/configure
index 259393b..475c381 100755
--- a/configure
+++ b/configure
@@ -26723,8 +26723,8 @@ fi
fi
-echo "$as_me:$LINENO: checking for lua" >&5
-echo $ECHO_N "checking for lua... $ECHO_C" >&6
+echo "$as_me:$LINENO: checking if lua-support is requested" >&5
+echo $ECHO_N "checking if lua-support is requested... $ECHO_C" >&6
# Check whether --with-lua or --without-lua was given.
if test "${with_lua+set}" = set; then
@@ -27036,12 +27036,12 @@ if test -n "$PKG_CONFIG"; then
pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
else
if test -n "$PKG_CONFIG" && \
- { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua\"") >&5
- ($PKG_CONFIG --exists --print-errors "lua") 2>&5
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua >= 5.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "lua >= 5.0") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; then
- pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua" 2>/dev/null`
+ pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua >= 5.0" 2>/dev/null`
else
pkg_failed=yes
fi
@@ -27054,12 +27054,12 @@ if test -n "$PKG_CONFIG"; then
pkg_cv_LUA_LIBS="$LUA_LIBS"
else
if test -n "$PKG_CONFIG" && \
- { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua\"") >&5
- ($PKG_CONFIG --exists --print-errors "lua") 2>&5
+ { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua >= 5.0\"") >&5
+ ($PKG_CONFIG --exists --print-errors "lua >= 5.0") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; then
- pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua" 2>/dev/null`
+ pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua >= 5.0" 2>/dev/null`
else
pkg_failed=yes
fi
@@ -27078,14 +27078,14 @@ else
_pkg_short_errors_supported=no
fi
if test $_pkg_short_errors_supported = yes; then
- LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "lua"`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "lua >= 5.0"`
else
- LUA_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "lua"`
+ LUA_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "lua >= 5.0"`
fi
# Put the nasty error message in config.log where it belongs
echo "$LUA_PKG_ERRORS" >&5
- { { echo "$as_me:$LINENO: error: Package requirements (lua) were not met:
+ { { echo "$as_me:$LINENO: error: Package requirements (lua >= 5.0) were not met:
$LUA_PKG_ERRORS
@@ -27096,7 +27096,7 @@ Alternatively, you may set the environment variables LUA_CFLAGS
and LUA_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.
" >&5
-echo "$as_me: error: Package requirements (lua) were not met:
+echo "$as_me: error: Package requirements (lua >= 5.0) were not met:
$LUA_PKG_ERRORS
@@ -30527,7 +30527,7 @@ else
no_build="$no_build $plugins"
fi
-plugins="mod_cml"
+plugins="mod_cml mod_magnet"
if test ! "x$LUA_LIBS" = x; then
do_build="$do_build $plugins"
else
diff --git a/configure.in b/configure.in
index 1d879ab..74bca03 100644
--- a/configure.in
+++ b/configure.in
@@ -375,7 +375,7 @@ if test "$WITH_MEMCACHE" != "no"; then
fi
dnl Check for lua
-AC_MSG_CHECKING(for lua)
+AC_MSG_CHECKING(if lua-support is requested)
AC_ARG_WITH(lua, AC_HELP_STRING([--with-lua],[lua engine for mod_cml]),
[WITH_LUA=$withval],[WITH_LUA=no])
@@ -400,7 +400,7 @@ if test "$WITH_LUA" != "no"; then
if test x"$LUA_LIBS" = x; then
# try pkgconfig
- PKG_CHECK_MODULES(LUA, lua, [
+ PKG_CHECK_MODULES(LUA, lua >= 5.0, [
AC_DEFINE([HAVE_LUA], [1], [liblua])
AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
])
@@ -557,7 +557,7 @@ else
no_build="$no_build $plugins"
fi
-plugins="mod_cml"
+plugins="mod_cml mod_magnet"
if test ! "x$LUA_LIBS" = x; then
do_build="$do_build $plugins"
else
diff --git a/src/Makefile.am b/src/Makefile.am
index ffec47e..3381100 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -46,7 +46,7 @@ common_src=buffer.c log.c \
network_write.c network_linux_sendfile.c \
network_freebsd_sendfile.c network_writev.c \
network_solaris_sendfilev.c network_openssl.c \
- splaytree.c
+ splaytree.c status_counter.c
src = server.c response.c connections.c network.c \
configfile.c configparser.c request.c proc_open.c
@@ -86,6 +86,12 @@ mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
+lib_LTLIBRARIES += mod_magnet.la
+mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c
+mod_magnet_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
+mod_magnet_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_magnet_la_LIBADD = $(common_libadd) $(LUA_LIBS) -lm
+
lib_LTLIBRARIES += mod_cml.la
mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
mod_cml_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
@@ -240,7 +246,8 @@ hdr = server.h buffer.h network.h log.h keyvalue.h \
mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
configparser.h mod_ssi_exprparser.h \
sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
- splaytree.h proc_open.h
+ splaytree.h proc_open.h status_counter.h \
+ mod_magnet_cache.h
DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
diff --git a/src/Makefile.in b/src/Makefile.in
index 7a316ce..ff69c2a 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_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_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_flv_streaming_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_magnet_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@
@@ -84,7 +84,8 @@ am__liblightcomp_la_SOURCES_DIST = buffer.c log.c keyvalue.c chunk.c \
inet_ntop_cache.c crc32.c connections-glue.c configfile-glue.c \
http-header-glue.c network_write.c network_linux_sendfile.c \
network_freebsd_sendfile.c network_writev.c \
- network_solaris_sendfilev.c network_openssl.c splaytree.c
+ network_solaris_sendfilev.c network_openssl.c splaytree.c \
+ status_counter.c
am__objects_1 = liblightcomp_la-buffer.lo liblightcomp_la-log.lo \
liblightcomp_la-keyvalue.lo liblightcomp_la-chunk.lo \
liblightcomp_la-http_chunk.lo liblightcomp_la-stream.lo \
@@ -111,7 +112,7 @@ am__objects_1 = liblightcomp_la-buffer.lo liblightcomp_la-log.lo \
liblightcomp_la-network_writev.lo \
liblightcomp_la-network_solaris_sendfilev.lo \
liblightcomp_la-network_openssl.lo \
- liblightcomp_la-splaytree.lo
+ liblightcomp_la-splaytree.lo liblightcomp_la-status_counter.lo
@NO_RDYNAMIC_TRUE@am_liblightcomp_la_OBJECTS = $(am__objects_1)
liblightcomp_la_OBJECTS = $(am_liblightcomp_la_OBJECTS)
@NO_RDYNAMIC_TRUE@am_liblightcomp_la_rpath = -rpath $(libdir)
@@ -163,6 +164,11 @@ mod_flv_streaming_la_OBJECTS = $(am_mod_flv_streaming_la_OBJECTS)
mod_indexfile_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_indexfile_la_OBJECTS = mod_indexfile.lo
mod_indexfile_la_OBJECTS = $(am_mod_indexfile_la_OBJECTS)
+mod_magnet_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_1)
+am_mod_magnet_la_OBJECTS = mod_magnet_la-mod_magnet.lo \
+ mod_magnet_la-mod_magnet_cache.lo
+mod_magnet_la_OBJECTS = $(am_mod_magnet_la_OBJECTS)
mod_mysql_vhost_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
$(am__DEPENDENCIES_2)
am_mod_mysql_vhost_la_OBJECTS = mod_mysql_vhost_la-mod_mysql_vhost.lo
@@ -236,7 +242,8 @@ am__lighttpd_SOURCES_DIST = server.c response.c connections.c \
connections-glue.c configfile-glue.c http-header-glue.c \
network_write.c network_linux_sendfile.c \
network_freebsd_sendfile.c network_writev.c \
- network_solaris_sendfilev.c network_openssl.c splaytree.c
+ network_solaris_sendfilev.c network_openssl.c splaytree.c \
+ status_counter.c
am__objects_2 = buffer.$(OBJEXT) log.$(OBJEXT) keyvalue.$(OBJEXT) \
chunk.$(OBJEXT) http_chunk.$(OBJEXT) stream.$(OBJEXT) \
fdevent.$(OBJEXT) stat_cache.$(OBJEXT) plugin.$(OBJEXT) \
@@ -254,7 +261,7 @@ am__objects_2 = buffer.$(OBJEXT) log.$(OBJEXT) keyvalue.$(OBJEXT) \
network_linux_sendfile.$(OBJEXT) \
network_freebsd_sendfile.$(OBJEXT) network_writev.$(OBJEXT) \
network_solaris_sendfilev.$(OBJEXT) network_openssl.$(OBJEXT) \
- splaytree.$(OBJEXT)
+ splaytree.$(OBJEXT) status_counter.$(OBJEXT)
@NO_RDYNAMIC_FALSE@am__objects_3 = $(am__objects_2)
am__objects_4 = server.$(OBJEXT) response.$(OBJEXT) \
connections.$(OBJEXT) network.$(OBJEXT) configfile.$(OBJEXT) \
@@ -291,24 +298,7 @@ SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) \
$(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) \
$(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) \
$(mod_fastcgi_la_SOURCES) $(mod_flv_streaming_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_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \
- $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) \
- $(mod_flv_streaming_la_SOURCES) $(mod_indexfile_la_SOURCES) \
+ $(mod_indexfile_la_SOURCES) $(mod_magnet_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) \
@@ -317,8 +307,27 @@ 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_flv_streaming_la_SOURCES) $(mod_indexfile_la_SOURCES) \
+ $(mod_magnet_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,7 +489,7 @@ common_src = buffer.c log.c \
network_write.c network_linux_sendfile.c \
network_freebsd_sendfile.c network_writev.c \
network_solaris_sendfilev.c network_openssl.c \
- splaytree.c
+ splaytree.c status_counter.c
src = server.c response.c connections.c network.c configfile.c \
configparser.c request.c proc_open.c $(am__append_2)
@@ -491,7 +500,7 @@ spawn_fcgi_SOURCES = spawn-fcgi.c
#mod_httptls_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
#mod_httptls_la_LIBADD = $(common_libadd)
lib_LTLIBRARIES = $(am__append_1) mod_flv_streaming.la mod_evasive.la \
- mod_webdav.la mod_cml.la mod_trigger_b4_dl.la \
+ mod_webdav.la mod_magnet.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 \
@@ -515,6 +524,10 @@ mod_webdav_la_SOURCES = mod_webdav.c
mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
+mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c
+mod_magnet_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
+mod_magnet_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_magnet_la_LIBADD = $(common_libadd) $(LUA_LIBS) -lm
mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
mod_cml_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS)
mod_cml_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
@@ -609,7 +622,8 @@ hdr = server.h buffer.h network.h log.h keyvalue.h \
mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
configparser.h mod_ssi_exprparser.h \
sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
- splaytree.h proc_open.h
+ splaytree.h proc_open.h status_counter.h \
+ mod_magnet_cache.h
lighttpd_SOURCES = $(src)
lighttpd_LDADD = $(PCRE_LIB) $(DL_LIB) $(SENDFILE_LIB) $(ATTR_LIB) $(common_libadd) $(SSL_LIB) $(FAM_LIBS)
@@ -722,6 +736,8 @@ mod_flv_streaming.la: $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_DEP
$(LINK) -rpath $(libdir) $(mod_flv_streaming_la_LDFLAGS) $(mod_flv_streaming_la_OBJECTS) $(mod_flv_streaming_la_LIBADD) $(LIBS)
mod_indexfile.la: $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(mod_indexfile_la_LDFLAGS) $(mod_indexfile_la_OBJECTS) $(mod_indexfile_la_LIBADD) $(LIBS)
+mod_magnet.la: $(mod_magnet_la_OBJECTS) $(mod_magnet_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(mod_magnet_la_LDFLAGS) $(mod_magnet_la_OBJECTS) $(mod_magnet_la_LIBADD) $(LIBS)
mod_mysql_vhost.la: $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(mod_mysql_vhost_la_LDFLAGS) $(mod_mysql_vhost_la_OBJECTS) $(mod_mysql_vhost_la_LIBADD) $(LIBS)
mod_proxy.la: $(mod_proxy_la_OBJECTS) $(mod_proxy_la_DEPENDENCIES)
@@ -905,6 +921,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-plugin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-splaytree.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-stat_cache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-status_counter.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightcomp_la-stream.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@
@@ -924,6 +941,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_fastcgi.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_flv_streaming.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_indexfile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_magnet_la-mod_magnet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_proxy.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_redirect.Plo@am__quote@
@@ -959,6 +978,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spawn-fcgi.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splaytree.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stat_cache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/status_counter.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Po@am__quote@
.c.o:
@@ -1248,6 +1268,13 @@ liblightcomp_la-splaytree.lo: splaytree.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-splaytree.lo `test -f 'splaytree.c' || echo '$(srcdir)/'`splaytree.c
+liblightcomp_la-status_counter.lo: status_counter.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -MT liblightcomp_la-status_counter.lo -MD -MP -MF "$(DEPDIR)/liblightcomp_la-status_counter.Tpo" -c -o liblightcomp_la-status_counter.lo `test -f 'status_counter.c' || echo '$(srcdir)/'`status_counter.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/liblightcomp_la-status_counter.Tpo" "$(DEPDIR)/liblightcomp_la-status_counter.Plo"; else rm -f "$(DEPDIR)/liblightcomp_la-status_counter.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='status_counter.c' object='liblightcomp_la-status_counter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(liblightcomp_la_CFLAGS) $(CFLAGS) -c -o liblightcomp_la-status_counter.lo `test -f 'status_counter.c' || echo '$(srcdir)/'`status_counter.c
+
mod_cml_la-mod_cml.lo: mod_cml.c
@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -MT mod_cml_la-mod_cml.lo -MD -MP -MF "$(DEPDIR)/mod_cml_la-mod_cml.Tpo" -c -o mod_cml_la-mod_cml.lo `test -f 'mod_cml.c' || echo '$(srcdir)/'`mod_cml.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_cml_la-mod_cml.Tpo" "$(DEPDIR)/mod_cml_la-mod_cml.Plo"; else rm -f "$(DEPDIR)/mod_cml_la-mod_cml.Tpo"; exit 1; fi
@@ -1269,6 +1296,20 @@ mod_cml_la-mod_cml_funcs.lo: mod_cml_funcs.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_cml_la_CFLAGS) $(CFLAGS) -c -o mod_cml_la-mod_cml_funcs.lo `test -f 'mod_cml_funcs.c' || echo '$(srcdir)/'`mod_cml_funcs.c
+mod_magnet_la-mod_magnet.lo: mod_magnet.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -MT mod_magnet_la-mod_magnet.lo -MD -MP -MF "$(DEPDIR)/mod_magnet_la-mod_magnet.Tpo" -c -o mod_magnet_la-mod_magnet.lo `test -f 'mod_magnet.c' || echo '$(srcdir)/'`mod_magnet.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_magnet_la-mod_magnet.Tpo" "$(DEPDIR)/mod_magnet_la-mod_magnet.Plo"; else rm -f "$(DEPDIR)/mod_magnet_la-mod_magnet.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mod_magnet.c' object='mod_magnet_la-mod_magnet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -c -o mod_magnet_la-mod_magnet.lo `test -f 'mod_magnet.c' || echo '$(srcdir)/'`mod_magnet.c
+
+mod_magnet_la-mod_magnet_cache.lo: mod_magnet_cache.c
+@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -MT mod_magnet_la-mod_magnet_cache.lo -MD -MP -MF "$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo" -c -o mod_magnet_la-mod_magnet_cache.lo `test -f 'mod_magnet_cache.c' || echo '$(srcdir)/'`mod_magnet_cache.c; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo" "$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Plo"; else rm -f "$(DEPDIR)/mod_magnet_la-mod_magnet_cache.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='mod_magnet_cache.c' object='mod_magnet_la-mod_magnet_cache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(mod_magnet_la_CFLAGS) $(CFLAGS) -c -o mod_magnet_la-mod_magnet_cache.lo `test -f 'mod_magnet_cache.c' || echo '$(srcdir)/'`mod_magnet_cache.c
+
mod_mysql_vhost_la-mod_mysql_vhost.lo: mod_mysql_vhost.c
@am__fastdepCC_TRUE@ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mod_mysql_vhost_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT mod_mysql_vhost_la-mod_mysql_vhost.lo -MD -MP -MF "$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo" -c -o mod_mysql_vhost_la-mod_mysql_vhost.lo `test -f 'mod_mysql_vhost.c' || echo '$(srcdir)/'`mod_mysql_vhost.c; \
@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo" "$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Plo"; else rm -f "$(DEPDIR)/mod_mysql_vhost_la-mod_mysql_vhost.Tpo"; exit 1; fi
diff --git a/src/array.c b/src/array.c
index 14afa28..3e1b32d 100644
--- a/src/array.c
+++ b/src/array.c
@@ -231,7 +231,7 @@ int array_insert_unique(array *a, data_unset *str) {
void array_print_indent(int depth) {
int i;
for (i = 0; i < depth; i ++) {
- fprintf(stderr, " ");
+ fprintf(stdout, " ");
}
}
@@ -275,20 +275,20 @@ int array_print(array *a, int depth) {
}
}
if (oneline) {
- fprintf(stderr, "(");
+ fprintf(stdout, "(");
for (i = 0; i < a->used; i++) {
data_unset *du = a->data[i];
if (i != 0) {
- fprintf(stderr, ", ");
+ fprintf(stdout, ", ");
}
du->print(du, depth + 1);
}
- fprintf(stderr, ")");
+ fprintf(stdout, ")");
return 0;
}
maxlen = array_get_max_key_length(a);
- fprintf(stderr, "(\n");
+ fprintf(stdout, "(\n");
for (i = 0; i < a->used; i++) {
data_unset *du = a->data[i];
array_print_indent(depth + 1);
@@ -296,24 +296,24 @@ int array_print(array *a, int depth) {
int j;
if (i && (i % 5) == 0) {
- fprintf(stderr, "# %zd\n", i);
+ fprintf(stdout, "# %zd\n", i);
array_print_indent(depth + 1);
}
- fprintf(stderr, "\"%s\"", du->key->ptr);
+ fprintf(stdout, "\"%s\"", du->key->ptr);
for (j = maxlen - strlen(du->key->ptr); j > 0; j --) {
- fprintf(stderr, " ");
+ fprintf(stdout, " ");
}
- fprintf(stderr, " => ");
+ fprintf(stdout, " => ");
}
du->print(du, depth + 1);
- fprintf(stderr, ",\n");
+ fprintf(stdout, ",\n");
}
if (!(i && (i - 1 % 5) == 0)) {
array_print_indent(depth + 1);
- fprintf(stderr, "# %zd\n", i);
+ fprintf(stdout, "# %zd\n", i);
}
array_print_indent(depth);
- fprintf(stderr, ")");
+ fprintf(stdout, ")");
return 0;
}
diff --git a/src/base.h b/src/base.h
index 654f2ed..15caee0 100644
--- a/src/base.h
+++ b/src/base.h
@@ -229,6 +229,7 @@ typedef struct {
FAMConnection *fam;
int fam_fcce_ndx;
#endif
+ buffer *hash_key; /* temp-store for the hash-key */
} stat_cache;
typedef struct {
@@ -407,7 +408,7 @@ typedef struct {
#ifdef USE_OPENSSL
SSL *ssl;
- int is_ssl_error_want;
+ buffer *ssl_error_want_reuse_buffer;
#endif
} connection;
diff --git a/src/chunk.c b/src/chunk.c
index 3903428..776d59e 100644
--- a/src/chunk.c
+++ b/src/chunk.c
@@ -194,6 +194,22 @@ int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
return 0;
}
+int chunkqueue_append_buffer_weak(chunkqueue *cq, buffer *mem) {
+ chunk *c;
+
+ if (mem->used == 0) return 0;
+
+ c = chunkqueue_get_unused_chunk(cq);
+ c->type = MEM_CHUNK;
+ c->offset = 0;
+ if (c->mem) buffer_free(c->mem);
+ c->mem = mem;
+
+ chunkqueue_append_chunk(cq, c);
+
+ return 0;
+}
+
int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
chunk *c;
@@ -209,6 +225,7 @@ int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
return 0;
}
+
int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
chunk *c;
@@ -355,7 +372,7 @@ int chunkqueue_remove_finished_chunks(chunkqueue *cq) {
switch (c->type) {
case MEM_CHUNK:
- if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
+ if (c->mem->used == 0 || (c->offset == (off_t)c->mem->used - 1)) is_finished = 1;
break;
case FILE_CHUNK:
if (c->offset == c->file.length) is_finished = 1;
diff --git a/src/chunk.h b/src/chunk.h
index ddc8617..3893919 100644
--- a/src/chunk.h
+++ b/src/chunk.h
@@ -51,6 +51,7 @@ int chunkqueue_set_tempdirs(chunkqueue *c, array *tempdirs);
int chunkqueue_append_file(chunkqueue *c, buffer *fn, off_t offset, off_t len);
int chunkqueue_append_mem(chunkqueue *c, const char *mem, size_t len);
int chunkqueue_append_buffer(chunkqueue *c, buffer *mem);
+int chunkqueue_append_buffer_weak(chunkqueue *c, buffer *mem);
int chunkqueue_prepend_buffer(chunkqueue *c, buffer *mem);
buffer * chunkqueue_get_append_buffer(chunkqueue *c);
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index 6d5132a..5d1c8ec 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -54,14 +54,14 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
array_insert_unique(cv[i].destination, (data_unset *)ds);
} else {
log_error_write(srv, __FILE__, __LINE__, "sssd",
- "the key of and array can only be a string or a integer, variable:",
+ "the key of an array can only be a string or a integer, variable:",
cv[i].key, "type:", da->value->data[j]->type);
return -1;
}
}
} else {
- log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
+ log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )");
return -1;
}
@@ -72,7 +72,7 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
buffer_copy_string_buffer(cv[i].destination, ds->value);
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
+ log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\"");
return -1;
}
@@ -88,7 +88,7 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
case TYPE_STRING: {
data_string *ds = (data_string *)du;
- log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
+ log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value);
return -1;
}
@@ -269,7 +269,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
nm_bits = strtol(nm_slash + 1, &err, 10);
if (*err) {
- log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
+ log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err);
return COND_RESULT_FALSE;
}
diff --git a/src/configparser.c b/src/configparser.c
index bc1a2ec..266a1c7 100644
--- a/src/configparser.c
+++ b/src/configparser.c
@@ -174,8 +174,8 @@ typedef union {
#define configparserARG_PDECL ,config_t *ctx
#define configparserARG_FETCH config_t *ctx = yypParser->ctx
#define configparserARG_STORE yypParser->ctx = ctx
-#define YYNSTATE 62
-#define YYNRULE 39
+#define YYNSTATE 63
+#define YYNRULE 40
#define YYERRORSYMBOL 26
#define YYERRSYMDT yy95
#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
@@ -230,61 +230,63 @@ typedef union {
** yy_default[] Default action for each state.
*/
static YYACTIONTYPE yy_action[] = {
- /* 0 */ 2, 3, 4, 5, 13, 14, 62, 15, 7, 44,
- /* 10 */ 20, 86, 16, 45, 28, 48, 40, 10, 39, 25,
- /* 20 */ 22, 49, 45, 8, 15, 102, 1, 20, 28, 18,
- /* 30 */ 57, 59, 19, 25, 22, 39, 19, 61, 98, 45,
- /* 40 */ 20, 6, 23, 24, 26, 28, 35, 57, 59, 12,
- /* 50 */ 25, 22, 28, 27, 36, 87, 29, 25, 22, 33,
- /* 60 */ 15, 30, 31, 20, 28, 38, 9, 17, 37, 25,
- /* 70 */ 22, 39, 42, 43, 10, 45, 11, 53, 54, 55,
- /* 80 */ 56, 28, 52, 57, 59, 34, 25, 22, 28, 27,
- /* 90 */ 32, 88, 41, 25, 22, 33, 28, 48, 46, 28,
- /* 100 */ 48, 25, 22, 58, 25, 22, 60, 21, 19, 47,
- /* 110 */ 51, 50, 25, 22, 88, 88, 93,
+ /* 0 */ 2, 3, 4, 5, 13, 14, 63, 15, 7, 45,
+ /* 10 */ 20, 88, 16, 46, 28, 49, 41, 10, 40, 25,
+ /* 20 */ 22, 50, 46, 8, 15, 104, 1, 20, 28, 18,
+ /* 30 */ 58, 60, 6, 25, 22, 40, 47, 62, 11, 46,
+ /* 40 */ 20, 9, 23, 24, 26, 29, 89, 58, 60, 10,
+ /* 50 */ 17, 38, 28, 27, 37, 19, 30, 25, 22, 34,
+ /* 60 */ 15, 100, 20, 20, 23, 24, 26, 12, 19, 31,
+ /* 70 */ 32, 40, 19, 44, 43, 46, 95, 35, 90, 89,
+ /* 80 */ 28, 49, 42, 58, 60, 25, 22, 59, 28, 27,
+ /* 90 */ 33, 48, 52, 25, 22, 34, 28, 49, 51, 28,
+ /* 100 */ 36, 25, 22, 61, 25, 22, 89, 28, 39, 89,
+ /* 110 */ 89, 89, 25, 22, 54, 55, 56, 57, 89, 28,
+ /* 120 */ 53, 21, 89, 89, 25, 22, 25, 22,
};
static YYCODETYPE yy_lookahead[] = {
/* 0 */ 29, 30, 31, 32, 33, 34, 0, 1, 44, 38,
/* 10 */ 4, 15, 41, 16, 35, 36, 45, 46, 12, 40,
/* 20 */ 41, 42, 16, 15, 1, 27, 28, 4, 35, 36,
- /* 30 */ 24, 25, 5, 40, 41, 12, 5, 14, 11, 16,
- /* 40 */ 4, 1, 6, 7, 8, 35, 36, 24, 25, 28,
- /* 50 */ 40, 41, 35, 36, 37, 15, 39, 40, 41, 42,
- /* 60 */ 1, 9, 10, 4, 35, 36, 38, 2, 3, 40,
- /* 70 */ 41, 12, 28, 14, 46, 16, 13, 20, 21, 22,
- /* 80 */ 23, 35, 36, 24, 25, 11, 40, 41, 35, 36,
- /* 90 */ 37, 13, 13, 40, 41, 42, 35, 36, 17, 35,
- /* 100 */ 36, 40, 41, 42, 40, 41, 42, 35, 5, 18,
- /* 110 */ 43, 19, 40, 41, 47, 47, 13,
+ /* 30 */ 24, 25, 1, 40, 41, 12, 17, 14, 13, 16,
+ /* 40 */ 4, 38, 6, 7, 8, 9, 15, 24, 25, 46,
+ /* 50 */ 2, 3, 35, 36, 37, 5, 39, 40, 41, 42,
+ /* 60 */ 1, 11, 4, 4, 6, 7, 8, 28, 5, 9,
+ /* 70 */ 10, 12, 5, 14, 28, 16, 13, 11, 13, 47,
+ /* 80 */ 35, 36, 13, 24, 25, 40, 41, 42, 35, 36,
+ /* 90 */ 37, 18, 43, 40, 41, 42, 35, 36, 19, 35,
+ /* 100 */ 36, 40, 41, 42, 40, 41, 47, 35, 36, 47,
+ /* 110 */ 47, 47, 40, 41, 20, 21, 22, 23, 47, 35,
+ /* 120 */ 36, 35, 47, 47, 40, 41, 40, 41,
};
#define YY_SHIFT_USE_DFLT (-5)
static signed char yy_shift_ofst[] = {
- /* 0 */ -5, 6, -5, -5, -5, 40, -4, 8, -3, -5,
- /* 10 */ 63, -5, 23, -5, -5, -5, 65, 36, 31, 36,
- /* 20 */ -5, -5, -5, -5, -5, -5, 36, 27, -5, 52,
- /* 30 */ -5, 36, -5, 74, 36, 31, -5, 36, 31, 78,
- /* 40 */ 79, -5, 59, -5, -5, 81, 91, 36, 31, 92,
- /* 50 */ 57, 36, 103, -5, -5, -5, -5, 36, -5, 36,
- /* 60 */ -5, -5,
+ /* 0 */ -5, 6, -5, -5, -5, 31, -4, 8, -3, -5,
+ /* 10 */ 25, -5, 23, -5, -5, -5, 48, 58, 67, 58,
+ /* 20 */ -5, -5, -5, -5, -5, -5, 36, 50, -5, -5,
+ /* 30 */ 60, -5, 58, -5, 66, 58, 67, -5, 58, 67,
+ /* 40 */ 65, 69, -5, 59, -5, -5, 19, 73, 58, 67,
+ /* 50 */ 79, 94, 58, 63, -5, -5, -5, -5, 58, -5,
+ /* 60 */ 58, -5, -5,
};
#define YY_REDUCE_USE_DFLT (-37)
static signed char yy_reduce_ofst[] = {
- /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 28, -37,
- /* 10 */ -37, 21, -29, -37, -37, -37, -37, -7, -37, 72,
+ /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 3, -37,
+ /* 10 */ -37, 39, -29, -37, -37, -37, -37, -7, -37, 86,
/* 20 */ -37, -37, -37, -37, -37, -37, 17, -37, -37, -37,
- /* 30 */ -37, 53, -37, -37, 10, -37, -37, 29, -37, -37,
- /* 40 */ -37, 44, -29, -37, -37, -37, -37, -21, -37, -37,
- /* 50 */ 67, 46, -37, -37, -37, -37, -37, 61, -37, 64,
- /* 60 */ -37, -37,
+ /* 30 */ -37, -37, 53, -37, -37, 64, -37, -37, 72, -37,
+ /* 40 */ -37, -37, 46, -29, -37, -37, -37, -37, -21, -37,
+ /* 50 */ -37, 49, 84, -37, -37, -37, -37, -37, 45, -37,
+ /* 60 */ 61, -37, -37,
};
static YYACTIONTYPE yy_default[] = {
- /* 0 */ 64, 101, 63, 65, 66, 101, 67, 101, 101, 90,
- /* 10 */ 101, 64, 101, 68, 69, 70, 101, 101, 71, 101,
- /* 20 */ 73, 74, 76, 77, 78, 79, 101, 84, 75, 101,
- /* 30 */ 80, 82, 81, 101, 101, 85, 83, 101, 72, 101,
- /* 40 */ 101, 64, 101, 89, 91, 101, 101, 101, 98, 101,
- /* 50 */ 101, 101, 101, 94, 95, 96, 97, 101, 99, 101,
- /* 60 */ 100, 92,
+ /* 0 */ 65, 103, 64, 66, 67, 103, 68, 103, 103, 92,
+ /* 10 */ 103, 65, 103, 69, 70, 71, 103, 103, 72, 103,
+ /* 20 */ 74, 75, 77, 78, 79, 80, 103, 86, 76, 81,
+ /* 30 */ 103, 82, 84, 83, 103, 103, 87, 85, 103, 73,
+ /* 40 */ 103, 103, 65, 103, 91, 93, 103, 103, 103, 100,
+ /* 50 */ 103, 103, 103, 103, 96, 97, 98, 99, 103, 101,
+ /* 60 */ 103, 102, 94,
};
#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
@@ -407,27 +409,28 @@ static const char *yyRuleName[] = {
/* 15 */ "value ::= STRING",
/* 16 */ "value ::= INTEGER",
/* 17 */ "value ::= array",
- /* 18 */ "array ::= LPARAN aelements RPARAN",
- /* 19 */ "aelements ::= aelements COMMA aelement",
- /* 20 */ "aelements ::= aelements COMMA",
- /* 21 */ "aelements ::= aelement",
- /* 22 */ "aelement ::= expression",
- /* 23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
- /* 24 */ "eols ::= EOL",
- /* 25 */ "eols ::=",
- /* 26 */ "globalstart ::= GLOBAL",
- /* 27 */ "global ::= globalstart LCURLY metalines RCURLY",
- /* 28 */ "condlines ::= condlines eols ELSE condline",
- /* 29 */ "condlines ::= condline",
- /* 30 */ "condline ::= context LCURLY metalines RCURLY",
- /* 31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
- /* 32 */ "cond ::= EQ",
- /* 33 */ "cond ::= MATCH",
- /* 34 */ "cond ::= NE",
- /* 35 */ "cond ::= NOMATCH",
- /* 36 */ "stringop ::= expression",
- /* 37 */ "include ::= INCLUDE stringop",
- /* 38 */ "include_shell ::= INCLUDE_SHELL stringop",
+ /* 18 */ "array ::= LPARAN RPARAN",
+ /* 19 */ "array ::= LPARAN aelements RPARAN",
+ /* 20 */ "aelements ::= aelements COMMA aelement",
+ /* 21 */ "aelements ::= aelements COMMA",
+ /* 22 */ "aelements ::= aelement",
+ /* 23 */ "aelement ::= expression",
+ /* 24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
+ /* 25 */ "eols ::= EOL",
+ /* 26 */ "eols ::=",
+ /* 27 */ "globalstart ::= GLOBAL",
+ /* 28 */ "global ::= globalstart LCURLY metalines RCURLY",
+ /* 29 */ "condlines ::= condlines eols ELSE condline",
+ /* 30 */ "condlines ::= condline",
+ /* 31 */ "condline ::= context LCURLY metalines RCURLY",
+ /* 32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
+ /* 33 */ "cond ::= EQ",
+ /* 34 */ "cond ::= MATCH",
+ /* 35 */ "cond ::= NE",
+ /* 36 */ "cond ::= NOMATCH",
+ /* 37 */ "stringop ::= expression",
+ /* 38 */ "include ::= INCLUDE stringop",
+ /* 39 */ "include_shell ::= INCLUDE_SHELL stringop",
};
#endif /* NDEBUG */
@@ -512,42 +515,42 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
case 25:
#line 142 "./configparser.y"
{ buffer_free((yypminor->yy0)); }
-#line 515 "configparser.c"
+#line 518 "configparser.c"
break;
case 35:
#line 133 "./configparser.y"
{ (yypminor->yy41)->free((yypminor->yy41)); }
-#line 520 "configparser.c"
+#line 523 "configparser.c"
break;
case 36:
#line 134 "./configparser.y"
{ (yypminor->yy41)->free((yypminor->yy41)); }
-#line 525 "configparser.c"
+#line 528 "configparser.c"
break;
case 37:
#line 135 "./configparser.y"
{ (yypminor->yy41)->free((yypminor->yy41)); }
-#line 530 "configparser.c"
+#line 533 "configparser.c"
break;
case 39:
#line 136 "./configparser.y"
{ array_free((yypminor->yy40)); }
-#line 535 "configparser.c"
+#line 538 "configparser.c"
break;
case 40:
#line 137 "./configparser.y"
{ array_free((yypminor->yy40)); }
-#line 540 "configparser.c"
+#line 543 "configparser.c"
break;
case 41:
#line 138 "./configparser.y"
{ buffer_free((yypminor->yy43)); }
-#line 545 "configparser.c"
+#line 548 "configparser.c"
break;
case 42:
#line 139 "./configparser.y"
{ buffer_free((yypminor->yy43)); }
-#line 550 "configparser.c"
+#line 553 "configparser.c"
break;
default: break; /* If no destructor action specified: do nothing */
}
@@ -741,6 +744,7 @@ static struct {
{ 35, 1 },
{ 35, 1 },
{ 35, 1 },
+ { 40, 2 },
{ 40, 3 },
{ 39, 3 },
{ 39, 2 },
@@ -816,7 +820,7 @@ static void yy_reduce(
case 5:
#line 116 "./configparser.y"
{ yymsp[-1].minor.yy78 = NULL; }
-#line 819 "configparser.c"
+#line 823 "configparser.c"
yy_destructor(1,&yymsp[0].minor);
break;
case 6:
@@ -851,7 +855,7 @@ static void yy_reduce(
buffer_free(yymsp[-2].minor.yy43);
yymsp[-2].minor.yy43 = NULL;
}
-#line 854 "configparser.c"
+#line 858 "configparser.c"
yy_destructor(2,&yymsp[-1].minor);
break;
case 10:
@@ -894,7 +898,7 @@ static void yy_reduce(
yymsp[-2].minor.yy43 = NULL;
yymsp[0].minor.yy41 = NULL;
}
-#line 897 "configparser.c"
+#line 901 "configparser.c"
yy_destructor(3,&yymsp[-1].minor);
break;
case 11:
@@ -910,7 +914,7 @@ static void yy_reduce(
yymsp[0].minor.yy0 = NULL;
}
}
-#line 913 "configparser.c"
+#line 917 "configparser.c"
break;
case 12:
#line 217 "./configparser.y"
@@ -923,7 +927,7 @@ static void yy_reduce(
yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
yymsp[0].minor.yy41 = NULL;
}
-#line 926 "configparser.c"
+#line 930 "configparser.c"
yy_destructor(5,&yymsp[-1].minor);
break;
case 13:
@@ -932,7 +936,7 @@ static void yy_reduce(
yygotominor.yy41 = yymsp[0].minor.yy41;
yymsp[0].minor.yy41 = NULL;
}
-#line 935 "configparser.c"
+#line 939 "configparser.c"
break;
case 14:
#line 232 "./configparser.y"
@@ -961,7 +965,7 @@ static void yy_reduce(
buffer_free(yymsp[0].minor.yy43);
yymsp[0].minor.yy43 = NULL;
}
-#line 964 "configparser.c"
+#line 968 "configparser.c"
break;
case 15:
#line 258 "./configparser.y"
@@ -971,7 +975,7 @@ static void yy_reduce(
buffer_free(yymsp[0].minor.yy0);
yymsp[0].minor.yy0 = NULL;
}
-#line 974 "configparser.c"
+#line 978 "configparser.c"
break;
case 16:
#line 265 "./configparser.y"
@@ -981,7 +985,7 @@ static void yy_reduce(
buffer_free(yymsp[0].minor.yy0);
yymsp[0].minor.yy0 = NULL;
}
-#line 984 "configparser.c"
+#line 988 "configparser.c"
break;
case 17:
#line 271 "./configparser.y"
@@ -991,20 +995,29 @@ static void yy_reduce(
((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
yymsp[0].minor.yy40 = NULL;
}
-#line 994 "configparser.c"
+#line 998 "configparser.c"
break;
case 18:
#line 277 "./configparser.y"
{
+ yygotominor.yy40 = array_init();
+}
+#line 1005 "configparser.c"
+ yy_destructor(8,&yymsp[-1].minor);
+ yy_destructor(9,&yymsp[0].minor);
+ break;
+ case 19:
+#line 280 "./configparser.y"
+{
yygotominor.yy40 = yymsp[-1].minor.yy40;
yymsp[-1].minor.yy40 = NULL;
}
-#line 1002 "configparser.c"
+#line 1015 "configparser.c"
yy_destructor(8,&yymsp[-2].minor);
yy_destructor(9,&yymsp[0].minor);
break;
- case 19:
-#line 282 "./configparser.y"
+ case 20:
+#line 285 "./configparser.y"
{
if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
@@ -1021,37 +1034,37 @@ static void yy_reduce(
yygotominor.yy40 = yymsp[-2].minor.yy40;
yymsp[-2].minor.yy40 = NULL;
}
-#line 1024 "configparser.c"
+#line 1037 "configparser.c"
yy_destructor(10,&yymsp[-1].minor);
break;
- case 20:
-#line 299 "./configparser.y"
+ case 21:
+#line 302 "./configparser.y"
{
yygotominor.yy40 = yymsp[-1].minor.yy40;
yymsp[-1].minor.yy40 = NULL;
}
-#line 1033 "configparser.c"
+#line 1046 "configparser.c"
yy_destructor(10,&yymsp[0].minor);
break;
- case 21:
-#line 304 "./configparser.y"
+ case 22:
+#line 307 "./configparser.y"
{
yygotominor.yy40 = array_init();
array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
yymsp[0].minor.yy41 = NULL;
}
-#line 1043 "configparser.c"
+#line 1056 "configparser.c"
break;
- case 22:
-#line 310 "./configparser.y"
+ case 23:
+#line 313 "./configparser.y"
{
yygotominor.yy41 = yymsp[0].minor.yy41;
yymsp[0].minor.yy41 = NULL;
}
-#line 1051 "configparser.c"
+#line 1064 "configparser.c"
break;
- case 23:
-#line 314 "./configparser.y"
+ case 24:
+#line 317 "./configparser.y"
{
buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
buffer_free(yymsp[-2].minor.yy43);
@@ -1060,27 +1073,27 @@ static void yy_reduce(
yygotominor.yy41 = yymsp[0].minor.yy41;
yymsp[0].minor.yy41 = NULL;
}
-#line 1063 "configparser.c"
+#line 1076 "configparser.c"
yy_destructor(11,&yymsp[-1].minor);
break;
- case 24:
- yy_destructor(1,&yymsp[0].minor);
- break;
case 25:
+ yy_destructor(1,&yymsp[0].minor);
break;
case 26:
-#line 326 "./configparser.y"
+ break;
+ case 27:
+#line 329 "./configparser.y"
{
data_config *dc;
dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
assert(dc);
configparser_push(ctx, dc, 0);
}
-#line 1079 "configparser.c"
+#line 1092 "configparser.c"
yy_destructor(12,&yymsp[0].minor);
break;
- case 27:
-#line 333 "./configparser.y"
+ case 28:
+#line 336 "./configparser.y"
{
data_config *cur;
@@ -1091,14 +1104,14 @@ static void yy_reduce(
yygotominor.yy0 = cur;
}
-#line 1094 "configparser.c"
+#line 1107 "configparser.c"
/* No destructor defined for globalstart */
yy_destructor(13,&yymsp[-2].minor);
/* No destructor defined for metalines */
yy_destructor(14,&yymsp[0].minor);
break;
- case 28:
-#line 344 "./configparser.y"
+ case 29:
+#line 347 "./configparser.y"
{
assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
@@ -1107,20 +1120,20 @@ static void yy_reduce(
yymsp[-3].minor.yy78 = NULL;
yymsp[0].minor.yy78 = NULL;
}
-#line 1110 "configparser.c"
+#line 1123 "configparser.c"
/* No destructor defined for eols */
yy_destructor(15,&yymsp[-1].minor);
break;
- case 29:
-#line 353 "./configparser.y"
+ case 30:
+#line 356 "./configparser.y"
{
yygotominor.yy78 = yymsp[0].minor.yy78;
yymsp[0].minor.yy78 = NULL;
}
-#line 1120 "configparser.c"
+#line 1133 "configparser.c"
break;
- case 30:
-#line 358 "./configparser.y"
+ case 31:
+#line 361 "./configparser.y"
{
data_config *cur;
@@ -1131,14 +1144,14 @@ static void yy_reduce(
yygotominor.yy78 = cur;
}
-#line 1134 "configparser.c"
+#line 1147 "configparser.c"
/* No destructor defined for context */
yy_destructor(13,&yymsp[-2].minor);
/* No destructor defined for metalines */
yy_destructor(14,&yymsp[0].minor);
break;
- case 31:
-#line 369 "./configparser.y"
+ case 32:
+#line 372 "./configparser.y"
{
data_config *dc;
buffer *b, *rvalue, *op;
@@ -1274,45 +1287,45 @@ static void yy_reduce(
yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
yymsp[0].minor.yy41 = NULL;
}
-#line 1277 "configparser.c"
+#line 1290 "configparser.c"
yy_destructor(16,&yymsp[-6].minor);
yy_destructor(18,&yymsp[-4].minor);
yy_destructor(19,&yymsp[-2].minor);
break;
- case 32:
-#line 504 "./configparser.y"
+ case 33:
+#line 507 "./configparser.y"
{
yygotominor.yy27 = CONFIG_COND_EQ;
}
-#line 1287 "configparser.c"
+#line 1300 "configparser.c"
yy_destructor(20,&yymsp[0].minor);
break;
- case 33:
-#line 507 "./configparser.y"
+ case 34:
+#line 510 "./configparser.y"
{
yygotominor.yy27 = CONFIG_COND_MATCH;
}
-#line 1295 "configparser.c"
+#line 1308 "configparser.c"
yy_destructor(21,&yymsp[0].minor);
break;
- case 34:
-#line 510 "./configparser.y"
+ case 35:
+#line 513 "./configparser.y"
{
yygotominor.yy27 = CONFIG_COND_NE;
}
-#line 1303 "configparser.c"
+#line 1316 "configparser.c"
yy_destructor(22,&yymsp[0].minor);
break;
- case 35:
-#line 513 "./configparser.y"
+ case 36:
+#line 516 "./configparser.y"
{
yygotominor.yy27 = CONFIG_COND_NOMATCH;
}
-#line 1311 "configparser.c"
+#line 1324 "configparser.c"
yy_destructor(23,&yymsp[0].minor);
break;
- case 36:
-#line 517 "./configparser.y"
+ case 37:
+#line 520 "./configparser.y"
{
yygotominor.yy43 = NULL;
if (ctx->ok) {
@@ -1329,10 +1342,10 @@ static void yy_reduce(
yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
yymsp[0].minor.yy41 = NULL;
}
-#line 1332 "configparser.c"
+#line 1345 "configparser.c"
break;
- case 37:
-#line 534 "./configparser.y"
+ case 38:
+#line 537 "./configparser.y"
{
if (ctx->ok) {
if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
@@ -1342,11 +1355,11 @@ static void yy_reduce(
yymsp[0].minor.yy43 = NULL;
}
}
-#line 1345 "configparser.c"
+#line 1358 "configparser.c"
yy_destructor(24,&yymsp[-1].minor);
break;
- case 38:
-#line 544 "./configparser.y"
+ case 39:
+#line 547 "./configparser.y"
{
if (ctx->ok) {
if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
@@ -1356,7 +1369,7 @@ static void yy_reduce(
yymsp[0].minor.yy43 = NULL;
}
}
-#line 1359 "configparser.c"
+#line 1372 "configparser.c"
yy_destructor(25,&yymsp[-1].minor);
break;
};
@@ -1390,7 +1403,7 @@ static void yy_parse_failed(
ctx->ok = 0;
-#line 1393 "configparser.c"
+#line 1406 "configparser.c"
configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
}
diff --git a/src/configparser.y b/src/configparser.y
index 2e9c819..122f424 100644
--- a/src/configparser.y
+++ b/src/configparser.y
@@ -274,6 +274,9 @@ value(A) ::= array(B). {
((data_array *)(A))->value = B;
B = NULL;
}
+array(A) ::= LPARAN RPARAN. {
+ A = array_init();
+}
array(A) ::= LPARAN aelements(B) RPARAN. {
A = B;
B = NULL;
diff --git a/src/connections.c b/src/connections.c
index fc67e59..4e5a4fb 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -190,51 +190,129 @@ static void dump_packet(const unsigned char *data, size_t len) {
}
#endif
-static int connection_handle_read(server *srv, connection *con) {
- int len;
- buffer *b;
- int toread;
+static int connection_handle_read_ssl(server *srv, connection *con) {
#ifdef USE_OPENSSL
- server_socket *srv_sock = con->srv_socket;
-#endif
+ int r, ssl_err, len;
+ buffer *b = NULL;
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- /* don't resize the buffer if we were in SSL_ERROR_WANT_* */
- if (!con->is_ssl_error_want) {
- b = chunkqueue_get_append_buffer(con->read_queue);
+ if (!con->conf.is_ssl) return -1;
+
+ /* don't resize the buffer if we were in SSL_ERROR_WANT_* */
+
+ do {
+ if (!con->ssl_error_want_reuse_buffer) {
+ b = buffer_init();
buffer_prepare_copy(b, SSL_pending(con->ssl) + (16 * 1024)); /* the pending bytes + 16kb */
+
+ /* overwrite everything with 0 */
+ memset(b->ptr, 0, b->size);
} else {
- /* we have to get the last buffer */
- chunk *c;
+ b = con->ssl_error_want_reuse_buffer;
+ }
- for (c = con->read_queue->first; c && c->next; c = c->next);
+ len = SSL_read(con->ssl, b->ptr, b->size - 1);
+ con->ssl_error_want_reuse_buffer = NULL; /* reuse it only once */
- if (!c) {
- b = chunkqueue_get_append_buffer(con->read_queue);
- buffer_prepare_copy(b, SSL_pending(con->ssl) + (16 * 1024)); /* the pending bytes + 16kb */
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "(debug) re-using last buffer after a SSL_ERROR_WANT_READ - good, please report this to jan@kneschke.de");
+ if (len > 0) {
+ b->used = len;
+ b->ptr[b->used++] = '\0';
+
+ /* we move the buffer to the chunk-queue, no need to free it */
- b = c->mem;
- }
+ chunkqueue_append_buffer_weak(con->read_queue, b);
+ con->bytes_read += len;
+ b = NULL;
}
- len = SSL_read(con->ssl, b->ptr, b->size - 1);
- con->is_ssl_error_want = 0; /* reset */
- } else {
- if (ioctl(con->fd, FIONREAD, &toread)) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "unexpected end-of-file:",
- con->fd);
- return -1;
+ } while (len > 0);
+
+
+ if (len < 0) {
+ switch ((r = SSL_get_error(con->ssl, len))) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ con->is_readable = 0;
+ con->ssl_error_want_reuse_buffer = b;
+
+ b = NULL;
+
+ /* we have to steal the buffer from the queue-queue */
+ return 0;
+ case SSL_ERROR_SYSCALL:
+ /**
+ * man SSL_get_error()
+ *
+ * SSL_ERROR_SYSCALL
+ * Some I/O error occurred. The OpenSSL error queue may contain more
+ * information on the error. If the error queue is empty (i.e.
+ * ERR_get_error() returns 0), ret can be used to find out more about
+ * the error: If ret == 0, an EOF was observed that violates the
+ * protocol. If ret == -1, the underlying BIO reported an I/O error
+ * (for socket I/O on Unix systems, consult errno for details).
+ *
+ */
+ while((ssl_err = ERR_get_error())) {
+ /* get all errors from the error-queue */
+ log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
+ r, ERR_error_string(ssl_err, NULL));
+ }
+
+ switch(errno) {
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
+ len, r, errno,
+ strerror(errno));
+ break;
+ }
+
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ /* clean shutdown on the remote side */
+
+ if (r == 0) {
+ /* FIXME: later */
+ }
+
+ /* fall thourgh */
+ default:
+ while((ssl_err = ERR_get_error())) {
+ /* get all errors from the error-queue */
+ log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
+ r, ERR_error_string(ssl_err, NULL));
+ }
+ break;
}
- b = chunkqueue_get_append_buffer(con->read_queue);
- buffer_prepare_copy(b, toread);
+
+ connection_set_state(srv, con, CON_STATE_ERROR);
- len = read(con->fd, b->ptr, b->size - 1);
+ buffer_free(b);
+
+ return -1;
+ } else if (len == 0) {
+ con->is_readable = 0;
+ /* the other end close the connection -> KEEP-ALIVE */
+
+ /* pipelining */
+ buffer_free(b);
+
+ return -2;
+ }
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+static int connection_handle_read(server *srv, connection *con) {
+ int len;
+ buffer *b;
+ int toread;
+
+ if (con->conf.is_ssl) {
+ return connection_handle_read_ssl(srv, con);
}
-#elif defined(__WIN32)
+
+#if defined(__WIN32)
b = chunkqueue_get_append_buffer(con->read_queue);
buffer_prepare_copy(b, 4 * 1024);
len = recv(con->fd, b->ptr, b->size - 1, 0);
@@ -254,73 +332,6 @@ static int connection_handle_read(server *srv, connection *con) {
if (len < 0) {
con->is_readable = 0;
-#ifdef USE_OPENSSL
- if (srv_sock->is_ssl) {
- int r, ssl_err;
-
- switch ((r = SSL_get_error(con->ssl, len))) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- con->is_ssl_error_want = 1;
- return 0;
- case SSL_ERROR_SYSCALL:
- /**
- * man SSL_get_error()
- *
- * SSL_ERROR_SYSCALL
- * Some I/O error occurred. The OpenSSL error queue may contain more
- * information on the error. If the error queue is empty (i.e.
- * ERR_get_error() returns 0), ret can be used to find out more about
- * the error: If ret == 0, an EOF was observed that violates the
- * protocol. If ret == -1, the underlying BIO reported an I/O error
- * (for socket I/O on Unix systems, consult errno for details).
- *
- */
- while((ssl_err = ERR_get_error())) {
- /* get all errors from the error-queue */
- log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
- r, ERR_error_string(ssl_err, NULL));
- }
-
- switch(errno) {
- default:
- log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
- len, r, errno,
- strerror(errno));
- break;
- }
-
- break;
- case SSL_ERROR_ZERO_RETURN:
- /* clean shutdown on the remote side */
-
- if (r == 0) {
- /* FIXME: later */
- }
-
- /* fall thourgh */
- default:
- while((ssl_err = ERR_get_error())) {
- /* get all errors from the error-queue */
- log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
- r, ERR_error_string(ssl_err, NULL));
- }
- break;
- }
- } else {
- if (errno == EAGAIN) return 0;
- if (errno == EINTR) {
- /* we have been interrupted before we could read */
- con->is_readable = 1;
- return 0;
- }
-
- if (errno != ECONNRESET) {
- /* expected for keep-alive */
- log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
- }
- }
-#else
if (errno == EAGAIN) return 0;
if (errno == EINTR) {
/* we have been interrupted before we could read */
@@ -332,7 +343,7 @@ static int connection_handle_read(server *srv, connection *con) {
/* expected for keep-alive */
log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
}
-#endif
+
connection_set_state(srv, con, CON_STATE_ERROR);
return -1;
@@ -803,7 +814,10 @@ int connection_reset(server *srv, connection *con) {
#endif
#ifdef USE_OPENSSL
- con->is_ssl_error_want = 0;
+ if (con->ssl_error_want_reuse_buffer) {
+ buffer_free(con->ssl_error_want_reuse_buffer);
+ con->ssl_error_want_reuse_buffer = NULL;
+ }
#endif
con->header_len = 0;
@@ -815,59 +829,17 @@ int connection_reset(server *srv, connection *con) {
}
/**
- *
- * search for \r\n\r\n
- *
- * this is a special 32bit version which is using a sliding window for
- * the comparisions
- *
- * how it works:
- *
- * b: 'abcdefg'
- * rnrn: 'cdef'
- *
- * cmpbuf: abcd != cdef
- * cmpbuf: bcde != cdef
- * cmpbuf: cdef == cdef -> return &c
- *
- * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
- * maintain cmpbuf and rnrn
- *
- */
-
-char *buffer_search_rnrn(buffer *b) {
- uint32_t cmpbuf, rnrn;
- char *cp;
- size_t i;
-
- if (b->used < 4) return NULL;
-
- rnrn = ('\r' << 24) | ('\n' << 16) |
- ('\r' << 8) | ('\n' << 0);
-
- cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
- (b->ptr[2] << 8) | (b->ptr[3] << 0);
-
- cp = b->ptr + 4;
- for (i = 0; i < b->used - 4; i++) {
- if (cmpbuf == rnrn) return cp - 4;
-
- cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
- }
-
- return NULL;
-}
-/**
* handle all header and content read
*
* we get called by the state-engine and by the fdevent-handler
*/
int connection_handle_read_state(server *srv, connection *con) {
int ostate = con->state;
- char *h_term = NULL;
- chunk *c;
+ chunk *c, *last_chunk;
+ off_t last_offset;
chunkqueue *cq = con->read_queue;
chunkqueue *dst_cq = con->request_content_queue;
+ int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */
if (con->is_readable) {
con->read_idle_ts = srv->cur_ts;
@@ -876,15 +848,8 @@ int connection_handle_read_state(server *srv, connection *con) {
case -1:
return -1;
case -2:
- /* remote side closed the connection
- * if we still have content, handle it, if not leave here */
-
- if (cq->first == cq->last &&
- cq->first->mem->used == 0) {
-
- /* conn-closed, leave here */
- connection_set_state(srv, con, CON_STATE_ERROR);
- }
+ is_closed = 1;
+ break;
default:
break;
}
@@ -927,99 +892,107 @@ int connection_handle_read_state(server *srv, connection *con) {
}
}
- /* nothing to handle */
- if (cq->first == NULL) return 0;
+ /* we might have got several packets at once
+ */
switch(ostate) {
case CON_STATE_READ:
- /* prepare con->request.request */
- c = cq->first;
-
- /* check if we need the full package */
- if (con->request.request->used == 0) {
+ /* if there is a \r\n\r\n in the chunkqueue
+ *
+ * scan the chunk-queue twice
+ * 1. to find the \r\n\r\n
+ * 2. to copy the header-packet
+ *
+ */
+
+ last_chunk = NULL;
+ last_offset = 0;
+
+ for (c = cq->first; !last_chunk && c; c = c->next) {
buffer b;
+ size_t i;
b.ptr = c->mem->ptr + c->offset;
b.used = c->mem->used - c->offset;
-
- if (NULL != (h_term = buffer_search_rnrn(&b))) {
- /* \r\n\r\n found
- * - copy everything incl. the terminator to request.request
- */
-
- buffer_copy_string_len(con->request.request,
- b.ptr,
- h_term - b.ptr + 4);
-
- /* the buffer has been read up to the terminator */
- c->offset += h_term - b.ptr + 4;
- } else {
- /* not found, copy everything */
- buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
- c->offset = c->mem->used - 1;
+
+ for (i = 0; !last_chunk && i < b.used; i++) {
+ char ch = b.ptr[i];
+ size_t have_chars = 0;
+
+ switch (ch) {
+ case '\r':
+ /* we have to do a 4 char lookup */
+ have_chars = b.used - i - 1;
+
+ if (have_chars >= 4) {
+ /* all chars are in this buffer */
+
+ if (0 == strncmp(b.ptr + i, "\r\n\r\n", 4)) {
+ /* found */
+ last_chunk = c;
+ last_offset = i + 4;
+
+ break;
+ }
+ } else {
+ chunk *lookahead_chunk = c->next;
+ size_t missing_chars;
+ /* looks like the following chars are not in the same chunk */
+
+ missing_chars = 4 - have_chars;
+
+ if (lookahead_chunk && lookahead_chunk->type == MEM_CHUNK) {
+ /* is the chunk long enough to contain the other chars ? */
+
+ if (lookahead_chunk->mem->used > missing_chars) {
+ if (0 == strncmp(b.ptr + i, "\r\n\r\n", have_chars) &&
+ 0 == strncmp(lookahead_chunk->mem->ptr, "\r\n\r\n" + have_chars, missing_chars)) {
+
+ last_chunk = lookahead_chunk;
+ last_offset = missing_chars + 1;
+
+ break;
+ }
+ } else {
+ /* a splited \r \n */
+ return -1;
+ }
+ }
+ }
+
+ break;
+ }
}
- } else {
- /* have to take care of overlapping header terminators */
-
- size_t l = con->request.request->used - 2;
- char *s = con->request.request->ptr;
- buffer b;
-
- b.ptr = c->mem->ptr + c->offset;
- b.used = c->mem->used - c->offset;
+ }
+
+ /* found */
+ if (last_chunk) {
+ buffer_reset(con->request.request);
+
+ for (c = cq->first; c; c = c->next) {
+ buffer b;
- if (con->request.request->used - 1 > 3 &&
- c->mem->used > 1 &&
- s[l-2] == '\r' &&
- s[l-1] == '\n' &&
- s[l-0] == '\r' &&
- c->mem->ptr[0] == '\n') {
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
- c->offset += 1;
-
- h_term = con->request.request->ptr;
- } else if (con->request.request->used - 1 > 2 &&
- c->mem->used > 2 &&
- s[l-1] == '\r' &&
- s[l-0] == '\n' &&
- c->mem->ptr[0] == '\r' &&
- c->mem->ptr[1] == '\n') {
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
- c->offset += 2;
-
- h_term = con->request.request->ptr;
- } else if (con->request.request->used - 1 > 1 &&
- c->mem->used > 3 &&
- s[l-0] == '\r' &&
- c->mem->ptr[0] == '\n' &&
- c->mem->ptr[1] == '\r' &&
- c->mem->ptr[2] == '\n') {
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
- c->offset += 3;
+ b.ptr = c->mem->ptr + c->offset;
+ b.used = c->mem->used - c->offset;
- h_term = con->request.request->ptr;
- } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
- /* \r\n\r\n found
- * - copy everything incl. the terminator to request.request
- */
-
- buffer_append_string_len(con->request.request,
- c->mem->ptr + c->offset,
- c->offset + h_term - b.ptr + 4);
+ if (c == last_chunk) {
+ b.used = last_offset + 1;
+ }
+
+ buffer_append_string_buffer(con->request.request, &b);
- /* the buffer has been read up to the terminator */
- c->offset += h_term - b.ptr + 4;
- } else {
- /* not found, copy everything */
- buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
- c->offset = c->mem->used - 1;
+ if (c == last_chunk) {
+ c->offset += last_offset;
+
+ break;
+ } else {
+ /* the whole packet was copied */
+ c->offset = c->mem->used - 1;
+ }
}
- }
- /* con->request.request is setup up */
- if (h_term) {
connection_set_state(srv, con, CON_STATE_REQUEST_END);
- } else if (con->request.request->used > 64 * 1024) {
+ } else if (chunkqueue_length(cq) > 64 * 1024) {
log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414");
con->http_status = 414; /* Request-URI too large */
@@ -1143,6 +1116,12 @@ int connection_handle_read_state(server *srv, connection *con) {
break;
}
+ /* the connection got closed and we didn't got enough data to leave one of the READ states
+ * the only way is to leave here */
+ if (is_closed && ostate == con->state) {
+ connection_set_state(srv, con, CON_STATE_ERROR);
+ }
+
chunkqueue_remove_finished_chunks(cq);
return 0;
@@ -1261,8 +1240,17 @@ connection *connection_accept(server *srv, server_socket *srv_socket) {
cnt_len = sizeof(cnt_addr);
if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
- if ((errno != EAGAIN) &&
- (errno != EINTR)) {
+ switch (errno) {
+ case EAGAIN:
+#if EWOULDBLOCK != EAGAIN
+ case EWOULDBLOCK:
+#endif
+ case EINTR:
+ /* we were stopped _before_ we had a connection */
+ case ECONNABORTED: /* this is a FreeBSD thingy */
+ /* we were stopped _after_ we had a connection */
+ break;
+ default:
log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
}
return NULL;
@@ -1354,6 +1342,12 @@ int connection_state_machine(server *srv, connection *con) {
con->loops_per_request = 0;
connection_set_state(srv, con, CON_STATE_READ);
+
+ /* patch con->conf.is_ssl if the connection is a ssl-socket already */
+
+#ifdef USE_OPENSSL
+ con->conf.is_ssl = srv_sock->is_ssl;
+#endif
break;
case CON_STATE_REQUEST_END: /* transient */
diff --git a/src/data_config.c b/src/data_config.c
index 8b3735e..03595a3 100644
--- a/src/data_config.c
+++ b/src/data_config.c
@@ -58,13 +58,13 @@ static void data_config_print(const data_unset *d, int depth) {
size_t maxlen;
if (0 == ds->context_ndx) {
- fprintf(stderr, "config {\n");
+ fprintf(stdout, "config {\n");
}
else {
- fprintf(stderr, "$%s %s \"%s\" {\n",
+ fprintf(stdout, "$%s %s \"%s\" {\n",
ds->comp_key->ptr, ds->op->ptr, ds->string->ptr);
array_print_indent(depth + 1);
- fprintf(stderr, "# block %d\n", ds->context_ndx);
+ fprintf(stdout, "# block %d\n", ds->context_ndx);
}
depth ++;
@@ -75,42 +75,42 @@ static void data_config_print(const data_unset *d, int depth) {
size_t j;
array_print_indent(depth);
- fprintf(stderr, "%s", du->key->ptr);
+ fprintf(stdout, "%s", du->key->ptr);
for (j = maxlen - len; j > 0; j --) {
- fprintf(stderr, " ");
+ fprintf(stdout, " ");
}
- fprintf(stderr, " = ");
+ fprintf(stdout, " = ");
du->print(du, depth);
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
}
if (ds->childs) {
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
for (i = 0; i < ds->childs->used; i ++) {
data_unset *du = ds->childs->data[i];
/* only the 1st block of chaining */
if (NULL == ((data_config *)du)->prev) {
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
array_print_indent(depth);
du->print(du, depth);
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
}
}
}
depth --;
array_print_indent(depth);
- fprintf(stderr, "}");
+ fprintf(stdout, "}");
if (0 != ds->context_ndx) {
- fprintf(stderr, " # end of $%s %s \"%s\"",
+ fprintf(stdout, " # end of $%s %s \"%s\"",
ds->comp_key->ptr, ds->op->ptr, ds->string->ptr);
}
if (ds->next) {
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
array_print_indent(depth);
- fprintf(stderr, "else ");
+ fprintf(stdout, "else ");
ds->next->print((data_unset *)ds->next, depth);
}
}
diff --git a/src/data_count.c b/src/data_count.c
index ca51f67..fbc35e0 100644
--- a/src/data_count.c
+++ b/src/data_count.c
@@ -45,7 +45,7 @@ static void data_count_print(const data_unset *d, int depth) {
data_count *ds = (data_count *)d;
UNUSED(depth);
- fprintf(stderr, "count(%d)", ds->count);
+ fprintf(stdout, "count(%d)", ds->count);
}
diff --git a/src/data_fastcgi.c b/src/data_fastcgi.c
index 714b290..ad981bf 100644
--- a/src/data_fastcgi.c
+++ b/src/data_fastcgi.c
@@ -44,7 +44,7 @@ static void data_fastcgi_print(const data_unset *d, int depth) {
data_fastcgi *ds = (data_fastcgi *)d;
UNUSED(depth);
- fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
+ fprintf(stdout, "fastcgi(%s)", ds->host->ptr);
}
diff --git a/src/data_integer.c b/src/data_integer.c
index 96d1d0a..c557b90 100644
--- a/src/data_integer.c
+++ b/src/data_integer.c
@@ -42,7 +42,7 @@ static void data_integer_print(const data_unset *d, int depth) {
data_integer *ds = (data_integer *)d;
UNUSED(depth);
- fprintf(stderr, "%d", ds->value);
+ fprintf(stdout, "%d", ds->value);
}
diff --git a/src/data_string.c b/src/data_string.c
index d9325da..391af9e 100644
--- a/src/data_string.c
+++ b/src/data_string.c
@@ -71,7 +71,7 @@ static void data_string_print(const data_unset *d, int depth) {
data_string *ds = (data_string *)d;
UNUSED(depth);
- fprintf(stderr, "\"%s\"", ds->value->used ? ds->value->ptr : "");
+ fprintf(stdout, "\"%s\"", ds->value->used ? ds->value->ptr : "");
}
diff --git a/src/http_auth.c b/src/http_auth.c
index d4de212..0d4637e 100644
--- a/src/http_auth.c
+++ b/src/http_auth.c
@@ -37,17 +37,6 @@
# include "md5.h"
#endif
-
-#ifdef USE_PAM
-#include <security/pam_appl.h>
-#include <security/pam_misc.h>
-
-static struct pam_conv conv = {
- misc_conv,
- NULL
-};
-#endif
-
handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
static const char base64_pad = '=';
@@ -509,33 +498,6 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p
if (0 == strcmp(password->ptr, pw)) {
return 0;
}
- } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) {
-#ifdef USE_PAM
- pam_handle_t *pamh=NULL;
- int retval;
-
- retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
-
- if (retval == PAM_SUCCESS)
- retval = pam_authenticate(pamh, 0); /* is user really user? */
-
- if (retval == PAM_SUCCESS)
- retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
-
- /* This is where we have been authorized or not. */
-
- if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
- pamh = NULL;
- log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
- }
-
- if (retval == PAM_SUCCESS) {
- log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
- return 0;
- } else {
- log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
- }
-#endif
} else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
#ifdef USE_LDAP
LDAP *ldap;
diff --git a/src/http_auth.h b/src/http_auth.h
index 0b664fa..b69007e 100644
--- a/src/http_auth.h
+++ b/src/http_auth.h
@@ -9,9 +9,13 @@
# include <ldap.h>
#endif
-typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN,
- AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD,
- AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
+typedef enum {
+ AUTH_BACKEND_UNSET,
+ AUTH_BACKEND_PLAIN,
+ AUTH_BACKEND_LDAP,
+ AUTH_BACKEND_HTPASSWD,
+ AUTH_BACKEND_HTDIGEST
+} auth_backend_t;
typedef struct {
/* auth */
diff --git a/src/http_chunk.c b/src/http_chunk.c
index c128bf1..281e86b 100644
--- a/src/http_chunk.c
+++ b/src/http_chunk.c
@@ -100,8 +100,7 @@ int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t
if (len == 0) {
if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
- http_chunk_append_len(srv, con, 0);
- chunkqueue_append_mem(cq, "\r\n", 2 + 1);
+ chunkqueue_append_mem(cq, "0\r\n\r\n", 5 + 1);
} else {
chunkqueue_append_mem(cq, "", 1);
}
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 7810437..b075a2b 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -193,20 +193,20 @@ 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++) {
- buffer *req = p->conf.auth_require->data[k]->key;
+ buffer *require = p->conf.auth_require->data[k]->key;
- if (req->used == 0) continue;
- if (con->uri.path->used < req->used) continue;
+ if (require->used == 0) continue;
+ if (con->uri.path->used < require->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)) {
+ if (0 == strncasecmp(con->uri.path->ptr, require->ptr, require->used - 1)) {
auth_required = 1;
break;
}
} else {
- if (0 == strncmp(con->uri.path->ptr, req->ptr, req->used - 1)) {
+ if (0 == strncmp(con->uri.path->ptr, require->ptr, require->used - 1)) {
auth_required = 1;
break;
}
diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c
index 76e979f..ded53b8 100644
--- a/src/mod_cml_lua.c
+++ b/src/mod_cml_lua.c
@@ -31,6 +31,7 @@ typedef char HASHHEX[HASHHEXLEN+1];
#include <lua.h>
#include <lualib.h>
+#include <lauxlib.h>
typedef struct {
stream st;
@@ -220,14 +221,9 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
stream_open(&rm.st, fn);
/* push the lua file to the interpreter and see what happends */
- L = lua_open();
-
- luaopen_base(L);
- luaopen_table(L);
- luaopen_string(L);
- luaopen_math(L);
- luaopen_io(L);
-
+ L = luaL_newstate();
+ luaL_openlibs(L);
+
/* register functions */
lua_register(L, "md5", f_crypto_md5);
lua_register(L, "file_mtime", f_file_mtime);
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index e64351a..4f7260b 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -23,6 +23,7 @@
#include "inet_ntop_cache.h"
#include "stat_cache.h"
+#include "status_counter.h"
#include <fastcgi.h>
#include <stdio.h>
@@ -363,49 +364,6 @@ typedef struct {
/* ok, we need a prototype */
static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
-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);
diff --git a/src/mod_magnet.c b/src/mod_magnet.c
new file mode 100644
index 0000000..a2f6185
--- /dev/null
+++ b/src/mod_magnet.c
@@ -0,0 +1,746 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <setjmp.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "mod_magnet_cache.h"
+#include "response.h"
+#include "stat_cache.h"
+#include "status_counter.h"
+
+#ifdef HAVE_LUA_H
+#include <lua.h>
+#include <lauxlib.h>
+
+#define MAGNET_CONFIG_RAW_URL "magnet.attract-raw-url-to"
+#define MAGNET_CONFIG_PHYSICAL_PATH "magnet.attract-physical-path-to"
+#define MAGNET_RESTART_REQUEST 99
+
+/* plugin config for all request/connections */
+
+static jmp_buf exceptionjmp;
+
+typedef struct {
+ array *url_raw;
+ array *physical_path;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ script_cache *cache;
+
+ buffer *encode_buf;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+/* init the plugin data */
+INIT_FUNC(mod_magnet_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ p->cache = script_cache_init();
+ p->encode_buf = buffer_init();
+
+ return p;
+}
+
+/* detroy the plugin data */
+FREE_FUNC(mod_magnet_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];
+
+ if (!s) continue;
+
+ array_free(s->url_raw);
+ array_free(s->physical_path);
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ script_cache_free(p->cache);
+ buffer_free(p->encode_buf);
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+/* handle plugin config and check values */
+
+SETDEFAULTS_FUNC(mod_magnet_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { MAGNET_CONFIG_RAW_URL, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { MAGNET_CONFIG_PHYSICAL_PATH, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ if (!p) return HANDLER_ERROR;
+
+ 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->url_raw = array_init();
+ s->physical_path = array_init();
+
+ cv[0].destination = s->url_raw;
+ cv[1].destination = s->physical_path;
+
+ 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_magnet_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(url_raw);
+ PATCH(physical_path);
+
+ /* 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(MAGNET_CONFIG_RAW_URL))) {
+ PATCH(url_raw);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_PHYSICAL_PATH))) {
+ PATCH(physical_path);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+static int magnet_print(lua_State *L) {
+ const char *s = luaL_checkstring(L, 1);
+ server *srv;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "(lua-print)", s);
+
+ return 0;
+}
+
+static int magnet_atpanic(lua_State *L) {
+ const char *s = luaL_checkstring(L, 1);
+ server *srv;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "(lua-atpanic)", s);
+
+ longjmp(exceptionjmp, 1);
+}
+
+static int magnet_reqhdr_get(lua_State *L) {
+ server *srv;
+ connection *con;
+ data_string *ds;
+
+ const char *key = luaL_checkstring(L, 2);
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, key))) {
+ if (ds->value->used) {
+ lua_pushlstring(L, ds->value->ptr, ds->value->used - 1);
+ } else {
+ lua_pushnil(L);
+ }
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int magnet_status_get(lua_State *L) {
+ data_integer *di;
+ server *srv;
+ size_t key_len = 0;
+
+ const char *key = luaL_checklstring(L, 2, &key_len);
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ di = status_counter_get_counter(srv, key, key_len);
+
+ lua_pushnumber(L, (double)di->value);
+
+ return 1;
+}
+
+static int magnet_status_set(lua_State *L) {
+ size_t key_len = 0;
+ server *srv;
+
+ const char *key = luaL_checklstring(L, 2, &key_len);
+ int counter = luaL_checkint(L, 3);
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ status_counter_set(srv, key, key_len, counter);
+
+ return 0;
+}
+
+typedef struct {
+ const char *name;
+ enum {
+ MAGNET_ENV_UNSET,
+
+ MAGNET_ENV_PHYICAL_PATH,
+ MAGNET_ENV_PHYICAL_REL_PATH,
+ MAGNET_ENV_PHYICAL_DOC_ROOT,
+
+ MAGNET_ENV_URI_PATH,
+ MAGNET_ENV_URI_PATH_RAW,
+ MAGNET_ENV_URI_SCHEME,
+ MAGNET_ENV_URI_AUTHORITY,
+ MAGNET_ENV_URI_QUERY,
+
+ MAGNET_ENV_REQUEST_METHOD,
+ MAGNET_ENV_REQUEST_URI,
+ MAGNET_ENV_REQUEST_PROTOCOL
+ } type;
+} magnet_env_t;
+
+static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *key) {
+ buffer *dest = NULL;
+ size_t i;
+
+ const magnet_env_t env[] = {
+ { "physical.path", MAGNET_ENV_PHYICAL_PATH },
+ { "physical.rel-path", MAGNET_ENV_PHYICAL_REL_PATH },
+ { "physical.doc-root", MAGNET_ENV_PHYICAL_DOC_ROOT },
+
+ { "uri.path", MAGNET_ENV_URI_PATH },
+ { "uri.path-raw", MAGNET_ENV_URI_PATH_RAW },
+ { "uri.scheme", MAGNET_ENV_URI_SCHEME },
+ { "uri.authority", MAGNET_ENV_URI_AUTHORITY },
+ { "uri.query", MAGNET_ENV_URI_QUERY },
+
+ { "request.method", MAGNET_ENV_REQUEST_METHOD },
+ { "request.uri", MAGNET_ENV_REQUEST_URI },
+ { "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL },
+
+ { NULL, MAGNET_ENV_UNSET }
+ };
+
+
+ /**
+ * map all internal variables to lua
+ *
+ */
+
+ for (i = 0; env[i].name; i++) {
+ if (0 == strcmp(key, env[i].name)) break;
+ }
+
+ switch (env[i].type) {
+ case MAGNET_ENV_PHYICAL_PATH: dest = con->physical.path; break;
+ case MAGNET_ENV_PHYICAL_REL_PATH: dest = con->physical.rel_path; break;
+ case MAGNET_ENV_PHYICAL_DOC_ROOT: dest = con->physical.doc_root; break;
+
+ case MAGNET_ENV_URI_PATH: dest = con->uri.path; break;
+ case MAGNET_ENV_URI_PATH_RAW: dest = con->uri.path_raw; break;
+ case MAGNET_ENV_URI_SCHEME: dest = con->uri.scheme; break;
+ case MAGNET_ENV_URI_AUTHORITY: dest = con->uri.authority; break;
+ case MAGNET_ENV_URI_QUERY: dest = con->uri.query; break;
+
+ case MAGNET_ENV_REQUEST_METHOD: break;
+ case MAGNET_ENV_REQUEST_URI: dest = con->request.uri; break;
+ case MAGNET_ENV_REQUEST_PROTOCOL: break;
+
+ case MAGNET_ENV_UNSET: break;
+ }
+
+ return dest;
+}
+
+static int magnet_env_get(lua_State *L) {
+ server *srv;
+ connection *con;
+
+ const char *key = luaL_checkstring(L, 2);
+ buffer *dest = NULL;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ dest = magnet_env_get_buffer(srv, con, key);
+
+ if (dest && dest->used) {
+ lua_pushlstring(L, dest->ptr, dest->used - 1);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+}
+
+static int magnet_env_set(lua_State *L) {
+ server *srv;
+ connection *con;
+
+ const char *key = luaL_checkstring(L, 2);
+ const char *val = luaL_checkstring(L, 3);
+ buffer *dest = NULL;
+
+ lua_pushstring(L, "lighty.srv");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ srv = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "lighty.con");
+ lua_gettable(L, LUA_REGISTRYINDEX);
+ con = lua_touserdata(L, -1);
+ lua_pop(L, 1);
+
+ if (NULL != (dest = magnet_env_get_buffer(srv, con, key))) {
+ buffer_copy_string(dest, val);
+ } else {
+ /* couldn't save */
+
+ return luaL_error(L, "couldn't store '%s' in lighty.env[]", key);
+ }
+
+ return 0;
+}
+
+
+static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) {
+ /**
+ * get the environment of the function
+ */
+
+ lua_getfenv(L, -1); /* -1 is the function */
+
+ /* lighty.header */
+
+ lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
+ assert(lua_istable(L, -1));
+
+ lua_getfield(L, -1, "header"); /* lighty.header */
+ if (lua_istable(L, -1)) {
+ /* header is found, and is a table */
+
+ lua_pushnil(L);
+ while (lua_next(L, -2) != 0) {
+ if (lua_isstring(L, -1) && lua_isstring(L, -2)) {
+ const char *key, *val;
+ size_t key_len, val_len;
+
+ key = lua_tolstring(L, -2, &key_len);
+ val = lua_tolstring(L, -1, &val_len);
+
+ response_header_overwrite(srv, con, key, key_len, val, val_len);
+ }
+
+ lua_pop(L, 1);
+ }
+ }
+
+ lua_pop(L, 1); /* pop the header-table */
+ lua_pop(L, 1); /* pop the lighty-env */
+ lua_pop(L, 1); /* pop the function env */
+
+ return 0;
+}
+
+/**
+ * walk through the content array
+ *
+ * content = { "<pre>", { file = "/content" } , "</pre>" }
+ *
+ * header["Content-Type"] = "text/html"
+ *
+ * return 200
+ */
+static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) {
+ /**
+ * get the environment of the function
+ */
+
+ assert(lua_isfunction(L, -1));
+ lua_getfenv(L, -1); /* -1 is the function */
+
+ lua_getfield(L, -1, "lighty"); /* lighty.* from the env */
+ assert(lua_istable(L, -1));
+
+ lua_getfield(L, -1, "content"); /* lighty.content */
+ if (lua_istable(L, -1)) {
+ int i;
+ /* header is found, and is a table */
+
+ for (i = 1; ; i++) {
+ lua_rawgeti(L, -1, i);
+
+ /* -1 is the value and should be the value ... aka a table */
+ if (lua_isstring(L, -1)) {
+ size_t s_len = 0;
+ const char *s = lua_tolstring(L, -1, &s_len);
+
+ chunkqueue_append_mem(con->write_queue, s, s_len + 1);
+ } else if (lua_istable(L, -1)) {
+ lua_getfield(L, -1, "filename");
+ lua_getfield(L, -2, "length");
+ lua_getfield(L, -3, "offset");
+
+ if (lua_isstring(L, -3)) { /* filename has to be a string */
+ buffer *fn = buffer_init();
+ stat_cache_entry *sce;
+
+ buffer_copy_string(fn, lua_tostring(L, -3));
+
+ if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, fn, &sce)) {
+ off_t off = 0;
+ off_t len = 0;
+
+ if (lua_isnumber(L, -1)) {
+ off = lua_tonumber(L, -1);
+ }
+
+ if (lua_isnumber(L, -2)) {
+ len = lua_tonumber(L, -2);
+ } else {
+ len = sce->st.st_size;
+ }
+
+ if (off < 0) {
+ return luaL_error(L, "offset for '%s' is negative", fn->ptr);
+ }
+
+ if (len < off) {
+ return luaL_error(L, "offset > length for '%s'", fn->ptr);
+ }
+
+ chunkqueue_append_file(con->write_queue, fn, off, len - off);
+ }
+
+ buffer_free(fn);
+ } else {
+ lua_pop(L, 3 + 2); /* correct the stack */
+
+ return luaL_error(L, "content[%d] is a table and requires the field \"filename\"", i);
+ }
+
+ lua_pop(L, 3);
+ } else if (lua_isnil(L, -1)) {
+ /* oops, end of list */
+
+ lua_pop(L, 1);
+
+ break;
+ } else {
+ lua_pop(L, 4);
+
+ return luaL_error(L, "content[%d] is neither a string nor a table: ", i);
+ }
+
+ lua_pop(L, 1); /* pop the content[...] table */
+ }
+ } else {
+ return luaL_error(L, "lighty.content has to be a table");
+ }
+ lua_pop(L, 1); /* pop the header-table */
+ lua_pop(L, 1); /* pop the lighty-table */
+ lua_pop(L, 1); /* php the function env */
+
+ return 0;
+}
+
+static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, buffer *name) {
+ lua_State *L;
+ int lua_return_value = -1;
+ /* get the script-context */
+
+
+ L = script_cache_get_script(srv, con, p->cache, name);
+
+ if (lua_isstring(L, -1)) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "sbss",
+ "loading script",
+ name,
+ "failed:",
+ lua_tostring(L, -1));
+
+ lua_pop(L, 1);
+
+ assert(lua_gettop(L) == 0); /* only the function should be on the stack */
+
+ con->http_status = 500;
+
+ return HANDLER_FINISHED;
+ }
+
+ lua_pushstring(L, "lighty.srv");
+ lua_pushlightuserdata(L, srv);
+ lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */
+
+ lua_pushstring(L, "lighty.con");
+ lua_pushlightuserdata(L, con);
+ lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */
+
+ lua_atpanic(L, magnet_atpanic);
+
+ /**
+ * we want to create empty environment for our script
+ *
+ * setmetatable({}, {__index = _G})
+ *
+ * if a function, symbol is not defined in our env, __index will lookup
+ * in the global env.
+ *
+ * all variables created in the script-env will be thrown
+ * away at the end of the script run.
+ */
+ lua_newtable(L); /* my empty environment aka {} (sp += 1) */
+
+ /* we have to overwrite the print function */
+ lua_pushcfunction(L, magnet_print); /* (sp += 1) */
+ lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */
+
+ /**
+ * lighty.request[] has the HTTP-request headers
+ * lighty.content[] is a table of string/file
+ * lighty.header[] is a array to set response headers
+ */
+
+ lua_newtable(L); /* lighty.* (sp += 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
+ lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
+ lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
+ lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */
+ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
+ lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */
+ lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* (sp -= 1) */
+ lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */
+ lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */
+ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */
+ lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */
+
+ /* add empty 'content' and 'header' tables */
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_setfield(L, -2, "content"); /* content = {} (sp -= 1) */
+
+ lua_newtable(L); /* {} (sp += 1) */
+ lua_setfield(L, -2, "header"); /* header = {} (sp -= 1) */
+
+ lua_pushinteger(L, MAGNET_RESTART_REQUEST);
+ lua_setfield(L, -2, "RESTART_REQUEST");
+
+ lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */
+
+ lua_newtable(L); /* the meta-table for the new env (sp += 1) */
+ lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */
+ lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */
+ lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */
+
+
+ lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */
+
+ if (lua_pcall(L, 0, 1, 0)) {
+ log_error_write(srv, __FILE__, __LINE__,
+ "ss",
+ "lua_pcall():",
+ lua_tostring(L, -1));
+ lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */
+
+ assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ con->http_status = 500;
+
+ return HANDLER_FINISHED;
+ }
+
+ /* we should have the function-copy and the return value on the stack */
+ assert(lua_gettop(L) == 2);
+
+ if (lua_isnumber(L, -1)) {
+ /* if the ret-value is a number, take it */
+ lua_return_value = (int)lua_tonumber(L, -1);
+ }
+ lua_pop(L, 1); /* pop the ret-value */
+
+ magnet_copy_response_header(srv, con, p, L);
+
+ if (lua_return_value > 99) {
+ con->http_status = lua_return_value;
+ con->file_finished = 1;
+
+ /* try { ...*/
+ if (0 == setjmp(exceptionjmp)) {
+ magnet_attach_content(srv, con, p, L);
+ } else {
+ /* } catch () { */
+ con->http_status = 500;
+ }
+
+ assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ /* we are finished */
+ return HANDLER_FINISHED;
+ } else if (MAGNET_RESTART_REQUEST == lua_return_value) {
+ assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ return HANDLER_COMEBACK;
+ } else {
+ assert(lua_gettop(L) == 1); /* only the function should be on the stack */
+
+ return HANDLER_GO_ON;
+ }
+}
+
+static handler_t magnet_attract_array(server *srv, connection *con, plugin_data *p, array *files) {
+ size_t i;
+
+ /* no filename set */
+ if (files->used == 0) return HANDLER_GO_ON;
+
+ /**
+ * execute all files and jump out on the first !HANDLER_GO_ON
+ */
+ for (i = 0; i < files->used; i++) {
+ data_string *ds = (data_string *)files->data[i];
+ handler_t ret;
+
+ if (buffer_is_empty(ds->value)) continue;
+
+ ret = magnet_attract(srv, con, p, ds->value);
+
+ if (ret != HANDLER_GO_ON) return ret;
+ }
+
+ return HANDLER_GO_ON;
+}
+
+URIHANDLER_FUNC(mod_magnet_uri_handler) {
+ plugin_data *p = p_d;
+
+ mod_magnet_patch_connection(srv, con, p);
+
+ return magnet_attract_array(srv, con, p, p->conf.url_raw);
+}
+
+URIHANDLER_FUNC(mod_magnet_physical) {
+ plugin_data *p = p_d;
+
+ mod_magnet_patch_connection(srv, con, p);
+
+ return magnet_attract_array(srv, con, p, p->conf.physical_path);
+}
+
+
+/* this function is called at dlopen() time and inits the callbacks */
+
+int mod_magnet_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("magnet");
+
+ p->init = mod_magnet_init;
+ p->handle_uri_clean = mod_magnet_uri_handler;
+ p->handle_physical = mod_magnet_physical;
+ p->set_defaults = mod_magnet_set_defaults;
+ p->cleanup = mod_magnet_free;
+
+ p->data = NULL;
+
+ return 0;
+}
+
+#else
+int mod_magnet_plugin_init(plugin *p) {
+ return -1;
+}
+#endif
diff --git a/src/mod_magnet_cache.c b/src/mod_magnet_cache.c
new file mode 100644
index 0000000..e2f5d84
--- /dev/null
+++ b/src/mod_magnet_cache.c
@@ -0,0 +1,137 @@
+#include <stdlib.h>
+#include <time.h>
+#include <assert.h>
+
+#include "mod_magnet_cache.h"
+#include "stat_cache.h"
+
+#ifdef HAVE_LUA_H
+#include <lualib.h>
+#include <lauxlib.h>
+
+script *script_init() {
+ script *sc;
+
+ sc = calloc(1, sizeof(*sc));
+ sc->name = buffer_init();
+ sc->etag = buffer_init();
+
+ return sc;
+}
+
+void script_free(script *sc) {
+ if (!sc) return;
+
+ lua_pop(sc->L, 1); /* the function copy */
+
+ buffer_free(sc->name);
+ buffer_free(sc->etag);
+
+ lua_close(sc->L);
+
+ free(sc);
+}
+
+script_cache *script_cache_init() {
+ script_cache *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+void script_cache_free(script_cache *p) {
+ size_t i;
+
+ if (!p) return;
+
+ for (i = 0; i < p->used; i++) {
+ script_free(p->ptr[i]);
+ }
+
+ free(p->ptr);
+
+ free(p);
+}
+
+lua_State *script_cache_get_script(server *srv, connection *con, script_cache *cache, buffer *name) {
+ size_t i;
+ script *sc = NULL;
+ stat_cache_entry *sce;
+
+ for (i = 0; i < cache->used; i++) {
+ sc = cache->ptr[i];
+
+ if (buffer_is_equal(name, sc->name)) {
+ sc->last_used = time(NULL);
+
+ /* oops, the script failed last time */
+
+ if (lua_gettop(sc->L) == 0) break;
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, sc->name, &sce)) {
+ lua_pop(sc->L, 1); /* pop the old function */
+ break;
+ }
+
+ if (!buffer_is_equal(sce->etag, sc->etag)) {
+ /* the etag is outdated, reload the function */
+ lua_pop(sc->L, 1);
+ break;
+ }
+
+ assert(lua_isfunction(sc->L, -1));
+ lua_pushvalue(sc->L, -1); /* copy the function-reference */
+
+ return sc->L;
+ }
+
+ sc = NULL;
+ }
+
+ /* if the script was script already loaded but either got changed or
+ * failed to load last time */
+ if (sc == NULL) {
+ sc = script_init();
+
+ if (cache->size == 0) {
+ cache->size = 16;
+ cache->ptr = malloc(cache->size * sizeof(*(cache->ptr)));
+ } else if (cache->used == cache->size) {
+ cache->size += 16;
+ cache->ptr = realloc(cache->ptr, cache->size * sizeof(*(cache->ptr)));
+ }
+
+ cache->ptr[cache->used++] = sc;
+
+ buffer_copy_string_buffer(sc->name, name);
+
+ sc->L = luaL_newstate();
+ luaL_openlibs(sc->L);
+ }
+
+ sc->last_used = time(NULL);
+
+ if (0 != luaL_loadfile(sc->L, name->ptr)) {
+ /* oops, an error, return it */
+
+ return sc->L;
+ }
+
+ if (HANDLER_GO_ON == stat_cache_get_entry(srv, con, sc->name, &sce)) {
+ buffer_copy_string_buffer(sc->etag, sce->etag);
+ }
+
+ /**
+ * pcall() needs the function on the stack
+ *
+ * as pcall() will pop the script from the stack when done, we have to
+ * duplicate it here
+ */
+ assert(lua_isfunction(sc->L, -1));
+ lua_pushvalue(sc->L, -1); /* copy the function-reference */
+
+ return sc->L;
+}
+
+#endif
diff --git a/src/mod_magnet_cache.h b/src/mod_magnet_cache.h
new file mode 100644
index 0000000..50c9e44
--- /dev/null
+++ b/src/mod_magnet_cache.h
@@ -0,0 +1,33 @@
+#ifndef _MOD_MAGNET_CACHE_H_
+#define _MOD_MAGNET_CACHE_H_
+
+#include "buffer.h"
+#include "base.h"
+
+#ifdef HAVE_LUA_H
+#include <lua.h>
+
+typedef struct {
+ buffer *name;
+ buffer *etag;
+
+ lua_State *L;
+
+ time_t last_used; /* LRU */
+} script;
+
+typedef struct {
+ script **ptr;
+
+ size_t used;
+ size_t size;
+} script_cache;
+
+script_cache *script_cache_init(void);
+void script_cache_free(script_cache *cache);
+
+lua_State *script_cache_get_script(server *srv, connection *con,
+ script_cache *cache, buffer *name);
+
+#endif
+#endif
diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
index bf13e09..524071e 100644
--- a/src/mod_mysql_vhost.c
+++ b/src/mod_mysql_vhost.c
@@ -105,6 +105,7 @@ SERVER_FUNC(mod_mysql_vhost_cleanup) {
buffer_free(s->mysock);
buffer_free(s->mysql_pre);
buffer_free(s->mysql_post);
+ buffer_free(s->hostname);
free(s);
}
diff --git a/src/mod_ssi.c b/src/mod_ssi.c
index d1e1b25..4fdae2f 100644
--- a/src/mod_ssi.c
+++ b/src/mod_ssi.c
@@ -722,6 +722,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
close(from_exec_fds[1]);
/* wait for the client to end */
+
+ /*
+ * FIXME: if we get interrupted by a SIGCHILD we count this as error
+ *
+ * for now it only happened on OpenBSD.
+ *
+ * that leads to zombies and missing output
+ */
if (-1 == waitpid(pid, &status, 0)) {
log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
} else if (WIFEXITED(status)) {
diff --git a/src/mod_webdav.c b/src/mod_webdav.c
index 2e67c96..3fd021f 100644
--- a/src/mod_webdav.c
+++ b/src/mod_webdav.c
@@ -668,7 +668,7 @@ static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physic
return 403;
}
- if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
+ if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) {
/* opening the destination failed for some reason */
switch(errno) {
case EEXIST:
@@ -1651,7 +1651,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
return HANDLER_FINISHED;
}
- if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
+ if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) {
switch (errno) {
case ENOENT:
con->http_status = 404; /* not found */
@@ -1675,9 +1675,9 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
/* take what we have in the request-body and write it to a file */
/* if the file doesn't exist, create it */
- if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
+ if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) {
if (errno == ENOENT &&
- -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
+ -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) {
/* we can't open the file */
con->http_status = 403;
@@ -1704,14 +1704,14 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
- return -1;
+ return HANDLER_ERROR;
}
if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
strerror(errno), c->file.name, c->file.fd);
- return -1;
+ return HANDLER_ERROR;
}
c->file.mmap.length = c->file.length;
diff --git a/src/network.c b/src/network.c
index 6ba2743..5b21b83 100644
--- a/src/network.c
+++ b/src/network.c
@@ -381,7 +381,7 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
return -1;
}
SSL_CTX_set_default_read_ahead(s->ssl_ctx, 1);
- SSL_CTX_set_mode(s->ssl_ctx, SSL_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+ SSL_CTX_set_mode(s->ssl_ctx, SSL_CTX_get_mode(s->ssl_ctx) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
srv_socket->ssl_ctx = s->ssl_ctx;
#else
diff --git a/src/network_freebsd_sendfile.c b/src/network_freebsd_sendfile.c
index a6994c0..f6f4d82 100644
--- a/src/network_freebsd_sendfile.c
+++ b/src/network_freebsd_sendfile.c
@@ -89,6 +89,7 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f
case EINTR:
r = 0;
break;
+ case ENOTCONN:
case EPIPE:
case ECONNRESET:
return -2;
diff --git a/src/network_openssl.c b/src/network_openssl.c
index e624739..86043fa 100644
--- a/src/network_openssl.c
+++ b/src/network_openssl.c
@@ -58,6 +58,31 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu
SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
}
+ /* evil hack for opera 9.01 and 8.54 and earlier
+ *
+ * opera hangs if the trainling 0\r\n\r\n is in a seperate SSL-packet
+ *
+ * we try to move the packet into the previous mem-chunk if possible
+ */
+ if ((cq == con->write_queue) &&
+ (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) &&
+ (con->file_finished)) {
+ /* merge the last chunk into the previous chunk */
+
+ for(c = cq->first; c && c->next && c->next->next; c = c->next);
+
+ if (c &&
+ c->type == MEM_CHUNK &&
+ c->next &&
+ c->next->type == MEM_CHUNK &&
+ c->next->mem->used == sizeof("0\r\n\r\n") &&
+ 0 == strcmp(c->next->mem->ptr, "0\r\n\r\n")) {
+ buffer_append_string_buffer(c->mem, c->next->mem);
+
+ c->next->mem->used = 0;
+ }
+ }
+
for(c = cq->first; c; c = c->next) {
int chunk_finished = 0;
diff --git a/src/network_writev.c b/src/network_writev.c
index 96a2a4a..5fdec8c 100644
--- a/src/network_writev.c
+++ b/src/network_writev.c
@@ -26,27 +26,6 @@
#include "log.h"
#include "stat_cache.h"
-#ifndef UIO_MAXIOV
-# if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
-/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
-# define UIO_MAXIOV 1024
-# elif defined(__sgi)
-/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
-# define UIO_MAXIOV 512
-# elif defined(__sun)
-/* Solaris (and SunOS?) defines IOV_MAX instead */
-# ifndef IOV_MAX
-# define UIO_MAXIOV 16
-# else
-# define UIO_MAXIOV IOV_MAX
-# endif
-# elif defined(IOV_MAX)
-# define UIO_MAXIOV IOV_MAX
-# else
-# error UIO_MAXIOV nor IOV_MAX are defined
-# endif
-#endif
-
#if 0
#define LOCAL_BUFFERING 1
#endif
@@ -65,18 +44,31 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
ssize_t r;
size_t num_chunks, i;
- struct iovec chunks[UIO_MAXIOV];
+ struct iovec *chunks;
chunk *tc;
size_t num_bytes = 0;
-
+#if defined(_SC_IOV_MAX) /* IRIX, MacOS X, FreeBSD, Solaris, ... */
+ const size_t max_chunks = sysconf(_SC_IOV_MAX);
+#elif defined(IOV_MAX) /* Linux x86 (glibc-2.3.6-3) */
+ const size_t max_chunks = IOV_MAX;
+#elif defined(MAX_IOVEC) /* Linux ia64 (glibc-2.3.3-98.28) */
+ const size_t max_chunks = MAX_IOVEC;
+#elif defined(UIO_MAXIOV) /* Linux x86 (glibc-2.2.5-233) */
+ const size_t max_chunks = UIO_MAXIOV;
+#else
+#error "sysconf() doesnt return _SC_IOV_MAX ..., check the output of 'man writev' for the EINVAL error and send the output to jan@kneschke.de"
+#endif
+
/* we can't send more then SSIZE_MAX bytes in one chunk */
/* build writev list
*
- * 1. limit: num_chunks < UIO_MAXIOV
+ * 1. limit: num_chunks < max_chunks
* 2. limit: num_bytes < SSIZE_MAX
*/
- for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
+ for (num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < max_chunks; num_chunks++, tc = tc->next);
+
+ chunks = calloc(num_chunks, sizeof(*chunks));
for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
if (tc->mem->used == 0) {
@@ -111,11 +103,13 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
break;
case EPIPE:
case ECONNRESET:
+ free(chunks);
return -2;
default:
log_error_write(srv, __FILE__, __LINE__, "ssd",
"writev failed:", strerror(errno), fd);
+ free(chunks);
return -1;
}
}
@@ -147,6 +141,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq
break;
}
}
+ free(chunks);
break;
}
diff --git a/src/server.c b/src/server.c
index 5a29a75..0222a22 100644
--- a/src/server.c
+++ b/src/server.c
@@ -286,9 +286,7 @@ static void show_version (void) {
}
static void show_features (void) {
- show_version();
- printf("\nEvent Handlers:\n\n%s",
-
+ const char features[] = ""
#ifdef USE_SELECT
"\t+ select (generic)\n"
#else
@@ -355,11 +353,6 @@ static void show_features (void) {
#else
"\t- crypt support\n"
#endif
-#ifdef USE_PAM
- "\t+ PAM support\n"
-#else
- "\t- PAM support\n"
-#endif
#ifdef USE_OPENSSL
"\t+ SSL Support\n"
#else
@@ -410,8 +403,9 @@ static void show_features (void) {
#else
"\t- GDBM support\n"
#endif
- "\n"
- );
+ "\n";
+ show_version();
+ printf("\nEvent Handlers:\n\n%s", features);
}
static void show_help (void) {
@@ -518,7 +512,7 @@ int main (int argc, char **argv) {
data_unset *dc = srv->config_context->data[0];
if (dc) {
dc->print(dc, 0);
- fprintf(stderr, "\n");
+ fprintf(stdout, "\n");
} else {
/* shouldn't happend */
fprintf(stderr, "global config not found\n");
@@ -953,8 +947,9 @@ int main (int argc, char **argv) {
}
} else {
int status;
- wait(&status);
- num_childs++;
+
+ /* ignore EINTR */
+ if (-1 != wait(&status)) num_childs++;
}
}
if (srv_shutdown) {
diff --git a/src/stat_cache.c b/src/stat_cache.c
index 623e5ea..a4f31a4 100644
--- a/src/stat_cache.c
+++ b/src/stat_cache.c
@@ -39,7 +39,7 @@
#define lstat stat
#endif
-#if 1
+#if 0
/* enables debug code for testing if all nodes in the stat-cache as accessable */
#define DEBUG_STAT_CACHE
#endif
@@ -109,6 +109,7 @@ stat_cache *stat_cache_init(void) {
fc = calloc(1, sizeof(*fc));
fc->dir_name = buffer_init();
+ fc->hash_key = buffer_init();
#ifdef HAVE_FAM_H
fc->fam = calloc(1, sizeof(*fc->fam));
#endif
@@ -182,6 +183,7 @@ void stat_cache_free(stat_cache *sc) {
}
buffer_free(sc->dir_name);
+ buffer_free(sc->hash_key);
#ifdef HAVE_FAM_H
while (sc->dirs) {
@@ -256,7 +258,7 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) {
FAMEvent fe;
fam_dir_entry *fam_dir;
splay_tree *node;
- int ndx;
+ int ndx, j;
FAMNextEvent(sc->fam, &fe);
@@ -274,20 +276,25 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) {
/* file/dir is still here */
if (fe.code == FAMChanged) break;
- buffer_copy_string(sc->dir_name, fe.filename);
+ /* we have 2 versions, follow and no-follow-symlink */
- ndx = hashme(sc->dir_name);
+ for (j = 0; j < 2; j++) {
+ buffer_copy_string(sc->hash_key, fe.filename);
+ buffer_append_long(sc->hash_key, j);
- sc->dirs = splaytree_splay(sc->dirs, ndx);
- node = sc->dirs;
-
- if (node && (node->key == ndx)) {
- int osize = splaytree_size(sc->dirs);
-
- fam_dir_entry_free(node->data);
- sc->dirs = splaytree_delete(sc->dirs, ndx);
+ ndx = hashme(sc->hash_key);
- assert(osize - 1 == splaytree_size(sc->dirs));
+ sc->dirs = splaytree_splay(sc->dirs, ndx);
+ node = sc->dirs;
+
+ if (node && (node->key == ndx)) {
+ int osize = splaytree_size(sc->dirs);
+
+ fam_dir_entry_free(node->data);
+ sc->dirs = splaytree_delete(sc->dirs, ndx);
+
+ assert(osize - 1 == splaytree_size(sc->dirs));
+ }
}
break;
default:
@@ -329,12 +336,12 @@ static int buffer_copy_dirname(buffer *dst, buffer *file) {
#endif
#ifdef HAVE_LSTAT
-static int stat_cache_lstat(server *srv, char *dname, struct stat *lst) {
- if (lstat(dname, lst) == 0) {
+static int stat_cache_lstat(server *srv, buffer *dname, struct stat *lst) {
+ if (lstat(dname->ptr, lst) == 0) {
return S_ISLNK(lst->st_mode) ? 0 : 1;
}
else {
- log_error_write(srv, __FILE__, __LINE__, "sss",
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
"lstat failed for:",
dname, strerror(errno));
};
@@ -362,6 +369,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
struct stat st;
size_t k;
int fd;
+ struct stat lst;
#ifdef DEBUG_STAT_CACHE
size_t i;
#endif
@@ -377,7 +385,10 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
sc = srv->stat_cache;
- file_ndx = hashme(name);
+ buffer_copy_string_buffer(sc->hash_key, name);
+ buffer_append_long(sc->hash_key, con->conf.follow_symlink);
+
+ file_ndx = hashme(sc->hash_key);
sc->files = splaytree_splay(sc->files, file_ndx);
#ifdef DEBUG_STAT_CACHE
@@ -436,8 +447,11 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
if (0 != buffer_copy_dirname(sc->dir_name, name)) {
SEGFAULT();
}
+
+ buffer_copy_string_buffer(sc->hash_key, sc->dir_name);
+ buffer_append_long(sc->hash_key, con->conf.follow_symlink);
- dir_ndx = hashme(sc->dir_name);
+ dir_ndx = hashme(sc->hash_key);
sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
@@ -522,49 +536,57 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
* and keeping the file open for the rest of the time. But this can
* only be done at network level.
*
-+ * per default it is not a symlink
+ * per default it is not a symlink
* */
#ifdef HAVE_LSTAT
sce->is_symlink = 0;
- struct stat lst;
- if (stat_cache_lstat(srv, name->ptr, &lst) == 0) {
+
+ /* we want to only check for symlinks if we should block symlinks.
+ */
+ if (!con->conf.follow_symlink) {
+ if (stat_cache_lstat(srv, name, &lst) == 0) {
#ifdef DEBUG_STAT_CACHE
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "found symlink", name);
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "found symlink", name);
#endif
- sce->is_symlink = 1;
- }
+ sce->is_symlink = 1;
+ }
- /*
- * we assume "/" can not be symlink, so
- * skip the symlink stuff if our path is /
- **/
- else if ((name->used > 2)) {
- char *dname, *s_cur;
-
- dname = strndup(name->ptr, name->used);
- while ((s_cur = strrchr(dname,'/'))) {
- *s_cur = '\0';
- if (dname == s_cur) {
+ /*
+ * we assume "/" can not be symlink, so
+ * skip the symlink stuff if our path is /
+ **/
+ else if ((name->used > 2)) {
+ buffer *dname;
+ char *s_cur;
+
+ dname = buffer_init();
+ buffer_copy_string_buffer(dname, name);
+
+ while ((s_cur = strrchr(dname->ptr,'/'))) {
+ *s_cur = '\0';
+ dname->used = s_cur - dname->ptr + 1;
+ if (dname->ptr == s_cur) {
#ifdef DEBUG_STAT_CACHE
- log_error_write(srv, __FILE__, __LINE__, "s", "reached /");
+ log_error_write(srv, __FILE__, __LINE__, "s", "reached /");
#endif
- break;
- }
+ break;
+ }
#ifdef DEBUG_STAT_CACHE
- log_error_write(srv, __FILE__, __LINE__, "sss",
- "checking if", dname, "is a symlink");
+ log_error_write(srv, __FILE__, __LINE__, "sbs",
+ "checking if", dname, "is a symlink");
#endif
- if (stat_cache_lstat(srv, dname, &lst) == 0) {
- sce->is_symlink = 1;
+ if (stat_cache_lstat(srv, dname, &lst) == 0) {
+ sce->is_symlink = 1;
#ifdef DEBUG_STAT_CACHE
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "found symlink", dname);
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "found symlink", dname);
#endif
- break;
+ break;
+ };
};
+ buffer_free(dname);
};
- free(dname);
};
#endif
@@ -592,6 +614,8 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
stat_cache_attr_get(sce->content_type, name->ptr);
}
#endif
+ } else if (S_ISDIR(st.st_mode)) {
+ etag_create(sce->etag, &(sce->st));
}
#ifdef HAVE_FAM_H
diff --git a/src/status_counter.c b/src/status_counter.c
new file mode 100644
index 0000000..3b345cd
--- /dev/null
+++ b/src/status_counter.c
@@ -0,0 +1,60 @@
+#include <stdlib.h>
+
+#include "status_counter.h"
+/**
+ * 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 = ...
+ */
+
+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;
+}
+
diff --git a/src/status_counter.h b/src/status_counter.h
new file mode 100644
index 0000000..431bd9c
--- /dev/null
+++ b/src/status_counter.h
@@ -0,0 +1,14 @@
+#ifndef _STATUS_COUNTER_H_
+#define _STATUS_COUNTER_H_
+
+#include <sys/types.h>
+
+#include "array.h"
+#include "base.h"
+
+data_integer *status_counter_get_counter(server *srv, const char *s, size_t len);
+int status_counter_inc(server *srv, const char *s, size_t len);
+int status_counter_dec(server *srv, const char *s, size_t len);
+int status_counter_set(server *srv, const char *s, size_t len, int val);
+
+#endif
diff --git a/tests/LightyTest.pm b/tests/LightyTest.pm
index 81f9292..0426d45 100755
--- a/tests/LightyTest.pm
+++ b/tests/LightyTest.pm
@@ -90,10 +90,12 @@ sub start_proc {
$ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
unlink($self->{LIGHTTPD_PIDFILE});
- if (1) {
- system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
+ if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
+ system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
+ } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
+ system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --log-file=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
} else {
- system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=foo ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH}." &");
+ system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
}
select(undef, undef, undef, 0.1);
@@ -195,6 +197,9 @@ sub handle_http {
}
}
+ $t->{etag} = $resp_hdr{'etag'};
+ $t->{date} = $resp_hdr{'date'};
+
# check length
if (defined $resp_hdr{"content-length"}) {
$resp_body = substr($lines, 0, $resp_hdr{"content-length"});
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d4a9b10..584d9c9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -42,7 +42,10 @@ CONFS=fastcgi-10.conf \
request.t \
mod-ssi.t \
LightyTest.pm \
- mod-setenv.t
+ mod-setenv.t \
+ lowercase.t \
+ lowercase.conf \
+ cachable.t
TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir)
diff --git a/tests/Makefile.in b/tests/Makefile.in
index feea307..93ac0f6 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -257,7 +257,10 @@ CONFS = fastcgi-10.conf \
request.t \
mod-ssi.t \
LightyTest.pm \
- mod-setenv.t
+ mod-setenv.t \
+ lowercase.t \
+ lowercase.conf \
+ cachable.t
TESTS_ENVIRONMENT = $(srcdir)/wrapper.sh $(srcdir) $(top_builddir)
EXTRA_DIST = wrapper.sh lighttpd.conf \
diff --git a/tests/cachable.t b/tests/cachable.t
new file mode 100755
index 0000000..74d9a4b
--- /dev/null
+++ b/tests/cachable.t
@@ -0,0 +1,112 @@
+#!/usr/bin/env perl
+BEGIN {
+ # add current source dir to the include-path
+ # we need this for make distcheck
+ (my $srcdir = $0) =~ s#/[^/]+$#/#;
+ unshift @INC, $srcdir;
+}
+
+use strict;
+use IO::Socket;
+use Test::More tests => 12;
+use LightyTest;
+
+my $tf = LightyTest->new();
+my $t;
+
+$tf->{CONFIGFILE} = 'lighttpd.conf';
+
+ok($tf->start_proc == 0, "Starting lighttpd") or die();
+
+## check if If-Modified-Since, If-None-Match works
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
+
+my $now = $t->{date};
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-Modified-Since: $now
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-Modified-Since: $now; foo
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-None-Match: foo
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
+
+my $etag = $t->{etag};
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-None-Match: $etag
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-None-Match: $etag
+If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-None-Match: $etag
+If-Modified-Since: $now; foo
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-None-Match: Foo
+If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-None-Match: $etag
+If-Modified-Since: $now foo
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
+
+ok($tf->stop_proc == 0, "Stopping lighttpd");
+
diff --git a/tests/lowercase.conf b/tests/lowercase.conf
new file mode 100644
index 0000000..60eb40f
--- /dev/null
+++ b/tests/lowercase.conf
@@ -0,0 +1,80 @@
+server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
+server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
+
+## bind to port (default: 80)
+server.port = 2048
+
+## bind to localhost (default: all interfaces)
+server.bind = "localhost"
+server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
+
+server.force-lowercase-filenames = "enable"
+
+server.dir-listing = "enable"
+
+server.modules = (
+ "mod_rewrite",
+ "mod_setenv",
+ "mod_secdownload",
+ "mod_access",
+ "mod_auth",
+ "mod_status",
+ "mod_expire",
+ "mod_redirect",
+ "mod_fastcgi",
+ "mod_cgi" )
+
+server.indexfiles = ( "index.php", "index.html",
+ "index.htm", "default.htm" )
+
+
+######################## MODULE CONFIG ############################
+
+mimetype.assign = ( ".png" => "image/png",
+ ".jpg" => "image/jpeg",
+ ".jpeg" => "image/jpeg",
+ ".gif" => "image/gif",
+ ".html" => "text/html",
+ ".htm" => "text/html",
+ ".pdf" => "application/pdf",
+ ".swf" => "application/x-shockwave-flash",
+ ".spl" => "application/futuresplash",
+ ".txt" => "text/plain",
+ ".tar.gz" => "application/x-tgz",
+ ".tgz" => "application/x-tgz",
+ ".gz" => "application/x-gzip",
+ ".c" => "text/plain",
+ ".conf" => "text/plain" )
+
+fastcgi.debug = 0
+fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
+ "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
+ )
+
+
+cgi.assign = ( ".pl" => "/usr/bin/perl",
+ ".cgi" => "/usr/bin/perl",
+ ".py" => "/usr/bin/python" )
+
+auth.backend = "plain"
+auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
+
+auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
+
+$HTTP["host"] == "lowercase-auth" {
+ auth.require = ( "/image.jpg" =>
+ (
+ "method" => "digest",
+ "realm" => "download archiv",
+ "require" => "valid-user"
+ )
+ )
+}
+
+$HTTP["host"] == "lowercase-deny" {
+ url.access-deny = ( ".jpg")
+}
+
+$HTTP["host"] == "lowercase-exclude" {
+ static-file.exclude-extensions = ( ".jpg" )
+}
diff --git a/tests/lowercase.t b/tests/lowercase.t
new file mode 100755
index 0000000..e127cdd
--- /dev/null
+++ b/tests/lowercase.t
@@ -0,0 +1,94 @@
+#!/usr/bin/env perl
+BEGIN {
+ # add current source dir to the include-path
+ # we need this for make distcheck
+ (my $srcdir = $0) =~ s#/[^/]+$#/#;
+ unshift @INC, $srcdir;
+}
+
+use strict;
+use IO::Socket;
+use Test::More tests => 10;
+use LightyTest;
+
+my $tf = LightyTest->new();
+my $t;
+
+$tf->{CONFIGFILE} = 'lowercase.conf';
+
+ok($tf->start_proc == 0, "Starting lighttpd") or die();
+
+## check if lower-casing works
+
+$t->{REQUEST} = ( <<EOF
+GET /image.JPG HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'uppercase access');
+
+$t->{REQUEST} = ( <<EOF
+GET /image.jpg HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'lowercase access');
+
+## check that mod-auth works
+
+$t->{REQUEST} = ( <<EOF
+GET /image.JPG HTTP/1.0
+Host: lowercase-auth
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
+ok($tf->handle_http($t) == 0, 'uppercase access');
+
+$t->{REQUEST} = ( <<EOF
+GET /image.jpg HTTP/1.0
+Host: lowercase-auth
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
+ok($tf->handle_http($t) == 0, 'lowercase access');
+
+
+## check that mod-staticfile exclude works
+$t->{REQUEST} = ( <<EOF
+GET /image.JPG HTTP/1.0
+Host: lowercase-exclude
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
+ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
+
+$t->{REQUEST} = ( <<EOF
+GET /image.jpg HTTP/1.0
+Host: lowercase-exclude
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
+ok($tf->handle_http($t) == 0, 'lowercase access');
+
+
+## check that mod-access exclude works
+$t->{REQUEST} = ( <<EOF
+GET /image.JPG HTTP/1.0
+Host: lowercase-deny
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
+ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
+
+$t->{REQUEST} = ( <<EOF
+GET /image.jpg HTTP/1.0
+Host: lowercase-deny
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
+ok($tf->handle_http($t) == 0, 'lowercase access');
+
+
+
+ok($tf->stop_proc == 0, "Stopping lighttpd");
+