summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArno Töll <arno@debian.org>2012-11-21 23:03:49 +0100
committerArno Töll <arno@debian.org>2012-11-21 23:03:49 +0100
commitec0b51649cd99420792df2352b02dc949f8f293b (patch)
treea31d192b419dc5c20445983d4aff2c0a88c28d40
parenta4197a3a45fd2b20d05c079d49af9fbef5fd4e2e (diff)
downloadlighttpd-ec0b51649cd99420792df2352b02dc949f8f293b.tar.gz
Imported Upstream version 1.4.17upstream/1.4.17
-rw-r--r--Makefile.in3
-rw-r--r--NEWS30
-rw-r--r--aclocal.m434
-rwxr-xr-xcompile142
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure192
-rw-r--r--configure.in3
-rw-r--r--cygwin/lighttpd.README10
-rw-r--r--doc/lighttpd.conf35
-rw-r--r--lighttpd.spec2
-rw-r--r--openwrt/control4
-rw-r--r--openwrt/lighttpd.mk2
-rw-r--r--src/array.h4
-rw-r--r--src/base.h4
-rw-r--r--src/buffer.c13
-rw-r--r--src/buffer.h2
-rw-r--r--src/configfile-glue.c84
-rw-r--r--src/configfile.c2
-rw-r--r--src/configfile.h6
-rw-r--r--src/connections.c113
-rw-r--r--src/etag.c6
-rw-r--r--src/http-header-glue.c14
-rw-r--r--src/http_auth.c4
-rw-r--r--src/log.c4
-rw-r--r--src/mod_alias.c2
-rw-r--r--src/mod_auth.c39
-rw-r--r--src/mod_cgi.c149
-rw-r--r--src/mod_compress.c7
-rw-r--r--src/mod_dirlisting.c22
-rw-r--r--src/mod_extforward.c69
-rw-r--r--src/mod_fastcgi.c14
-rw-r--r--src/mod_mysql_vhost.c8
-rw-r--r--src/mod_proxy.c2
-rw-r--r--src/mod_scgi.c14
-rw-r--r--src/mod_ssi.c4
-rw-r--r--src/mod_staticfile.c1
-rw-r--r--src/mod_status.c7
-rw-r--r--src/mod_usertrack.c4
-rw-r--r--src/network_freebsd_sendfile.c45
-rw-r--r--src/request.c16
-rw-r--r--src/server.c57
-rw-r--r--src/spawn-fcgi.c8
-rw-r--r--src/stat_cache.c5
-rw-r--r--tests/404-handler.conf49
-rwxr-xr-xtests/LightyTest.pm32
-rw-r--r--tests/Makefile.am4
-rw-r--r--tests/Makefile.in4
-rwxr-xr-xtests/cachable.t11
-rw-r--r--tests/core-404-handler.t76
-rwxr-xr-xtests/docroot/www/404.fcgi27
-rw-r--r--tests/docroot/www/404.html1
-rwxr-xr-xtests/docroot/www/404.pl33
-rw-r--r--tests/docroot/www/Makefile.am2
-rw-r--r--tests/docroot/www/Makefile.in2
-rw-r--r--tests/docroot/www/crlfcrash.pl4
-rwxr-xr-xtests/docroot/www/nph-status.pl8
-rwxr-xr-xtests/docroot/www/send404.pl5
-rw-r--r--tests/fastcgi-13.conf2
-rw-r--r--tests/lighttpd.conf5
-rwxr-xr-xtests/mod-cgi.t28
-rwxr-xr-xtests/mod-fastcgi.t8
-rwxr-xr-xtests/request.t53
62 files changed, 1167 insertions, 376 deletions
diff --git a/Makefile.in b/Makefile.in
index 54a342e..b50af37 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -37,7 +37,8 @@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in $(srcdir)/config.h.in \
$(srcdir)/distribute.sh.in $(srcdir)/lighttpd.spec.in \
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
- config.guess config.sub depcomp install-sh ltmain.sh missing
+ compile config.guess config.sub depcomp install-sh ltmain.sh \
+ missing
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
diff --git a/NEWS b/NEWS
index f4f54d1..cbbc60f 100644
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,35 @@
NEWS
====
-- 1.4.16 -
+- 1.4.17 - 2007-08-29
+ * added dir-listing.set-footer in mod_dirlisting (#1277)
+ * added sending UID and PID for SIGTERM and SIGINT to the logs
+ * fixed hardcoded font-sizes in mod_dirlisting (#1267)
+ * fixed different ETag length on 32/64 platforms (#1279)
+ * fixed compression of files < 128 bytes by disabling compression (#1241)
+ * fixed mysql server reconnects (#518)
+ * fixed disabled keep-alive for dynamic content with HTTP/1.0 (#1166)
+ * fixed crash on mixed EOL sequences in mod_cgi
+ * fixed key compare (#1287)
+ * fixed invalid char in header values (#1286)
+ * fixed invalid "304 Not Modified" on broken timestamps
+ * fixed endless loop on shrinked files with sendfile() on BSD (#1289)
+ * fixed counter overrun in ?auto in mod_status (#909)
+ * fixed too aggresive caching of nested conditionals (#41)
+ * fixed possible overflow in unix-socket path checks on BSD (#713)
+ * fixed extra Content-Length header on 1xx, 204 and 304 (#1002)
+ * fixed handling of duplicate If-Modified-Since to return 304
+ * fixed extracting status code from NPH scripts (#1125)
+ * fixed prctl() usage (#1310)
+ * removed config-check if passwd files exist (#1188)
+ * fixed crash when etags are disabled but the client sends one (#1322)
+ * fixed crash when freeing the config in mod_alias
+ * fixed server.error-handler-404 breakage from 1.4.16 (#1270)
+ * fixed entering 404-handler from dynamic content (#948)
+ * added more debug infos for FAM based stat-cache
+ * use more LSB like paths in the sample config (#1242)
+
+- 1.4.16 - 2007-07-25
* added static-file.etags, etag.use-inode, etag.use-mtime, etag.use-size
to customize the generation of ETags for static files. (#1209)
diff --git a/aclocal.m4 b/aclocal.m4
index d386e7e..35d24fb 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -7140,6 +7140,40 @@ AC_MSG_RESULT([$_am_result])
rm -f confinc confmf
])
+# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_PROG_CC_C_O
+# --------------
+# Like AC_PROG_CC_C_O, but changed for automake.
+AC_DEFUN([AM_PROG_CC_C_O],
+[AC_REQUIRE([AC_PROG_CC_C_O])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+ac_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+dnl Make sure AC_PROG_CC is never called again, or it will override our
+dnl setting of CC.
+m4_define([AC_PROG_CC],
+ [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])])
+])
+
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005
diff --git a/compile b/compile
new file mode 100755
index 0000000..1b1d232
--- /dev/null
+++ b/compile
@@ -0,0 +1,142 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand `-c -o'.
+
+scriptversion=2005-05-14.22
+
+# Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try \`$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand `-c -o'.
+Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file `INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+esac
+
+ofile=
+cfile=
+eat=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as `compile cc -o foo foo.c'.
+ # So we strip `-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no `-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # `.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use `[/.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-end: "$"
+# End:
diff --git a/config.h.in b/config.h.in
index bbbae54..33347ba 100644
--- a/config.h.in
+++ b/config.h.in
@@ -374,6 +374,9 @@
slash. */
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
/* Name of package */
#undef PACKAGE
diff --git a/configure b/configure
index b04e93f..332f872 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for lighttpd 1.4.16.
+# Generated by GNU Autoconf 2.61 for lighttpd 1.4.17.
#
# Report bugs to <jan@kneschke.de>.
#
@@ -728,8 +728,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='lighttpd'
PACKAGE_TARNAME='lighttpd'
-PACKAGE_VERSION='1.4.16'
-PACKAGE_STRING='lighttpd 1.4.16'
+PACKAGE_VERSION='1.4.17'
+PACKAGE_STRING='lighttpd 1.4.17'
PACKAGE_BUGREPORT='jan@kneschke.de'
ac_unique_file="src/server.c"
@@ -1440,7 +1440,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures lighttpd 1.4.16 to adapt to many kinds of systems.
+\`configure' configures lighttpd 1.4.17 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1511,7 +1511,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of lighttpd 1.4.16:";;
+ short | recursive ) echo "Configuration of lighttpd 1.4.17:";;
esac
cat <<\_ACEOF
@@ -1645,7 +1645,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-lighttpd configure 1.4.16
+lighttpd configure 1.4.17
generated by GNU Autoconf 2.61
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1659,7 +1659,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by lighttpd $as_me 1.4.16, which was
+It was created by lighttpd $as_me 1.4.17, which was
generated by GNU Autoconf 2.61. Invocation command line was
$ $0 $@
@@ -2478,7 +2478,7 @@ fi
# Define the identity of the package.
PACKAGE='lighttpd'
- VERSION='1.4.16'
+ VERSION='1.4.17'
cat >>confdefs.h <<_ACEOF
@@ -3741,6 +3741,132 @@ else
fi
+if test "x$CC" != xcc; then
+ { echo "$as_me:$LINENO: checking whether $CC and cc understand -c and -o together" >&5
+echo $ECHO_N "checking whether $CC and cc understand -c and -o together... $ECHO_C" >&6; }
+else
+ { echo "$as_me:$LINENO: checking whether cc understands -c and -o together" >&5
+echo $ECHO_N "checking whether cc understands -c and -o together... $ECHO_C" >&6; }
+fi
+set dummy $CC; ac_cc=`echo $2 |
+ sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+# Make sure it works both with $CC and with simple cc.
+# We do the test twice because some compilers refuse to overwrite an
+# existing .o file with -o, though they will create one.
+ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+rm -f conftest2.*
+if { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ test -f conftest2.$ac_objext && { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); };
+then
+ eval ac_cv_prog_cc_${ac_cc}_c_o=yes
+ if test "x$CC" != xcc; then
+ # Test first that cc exists at all.
+ if { ac_try='cc -c conftest.$ac_ext >&5'
+ { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+ rm -f conftest2.*
+ if { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ test -f conftest2.$ac_objext && { (case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); };
+ then
+ # cc works too.
+ :
+ else
+ # cc exists but doesn't like -o.
+ eval ac_cv_prog_cc_${ac_cc}_c_o=no
+ fi
+ fi
+ fi
+else
+ eval ac_cv_prog_cc_${ac_cc}_c_o=no
+fi
+rm -f core conftest*
+
+fi
+if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then
+ { echo "$as_me:$LINENO: result: yes" >&5
+echo "${ECHO_T}yes" >&6; }
+else
+ { echo "$as_me:$LINENO: result: no" >&5
+echo "${ECHO_T}no" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define NO_MINUS_C_MINUS_O 1
+_ACEOF
+
+fi
+
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+ac_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+
+
{ echo "$as_me:$LINENO: checking for a sed that does not truncate output" >&5
echo $ECHO_N "checking for a sed that does not truncate output... $ECHO_C" >&6; }
if test "${lt_cv_path_SED+set}" = set; then
@@ -5542,7 +5668,7 @@ ia64-*-hpux*)
;;
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5545 "configure"' > conftest.$ac_ext
+ echo '#line 5671 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -7799,11 +7925,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:7802: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:7928: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:7806: \$? = $ac_status" >&5
+ echo "$as_me:7932: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -8067,11 +8193,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8070: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8196: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:8074: \$? = $ac_status" >&5
+ echo "$as_me:8200: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -8171,11 +8297,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:8174: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:8300: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:8178: \$? = $ac_status" >&5
+ echo "$as_me:8304: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -10479,7 +10605,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10482 "configure"
+#line 10608 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -10579,7 +10705,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 10582 "configure"
+#line 10708 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12915,11 +13041,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:12918: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13044: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:12922: \$? = $ac_status" >&5
+ echo "$as_me:13048: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -13019,11 +13145,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:13022: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:13148: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:13026: \$? = $ac_status" >&5
+ echo "$as_me:13152: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -14589,11 +14715,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14592: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14718: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:14596: \$? = $ac_status" >&5
+ echo "$as_me:14722: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -14693,11 +14819,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:14696: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:14822: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:14700: \$? = $ac_status" >&5
+ echo "$as_me:14826: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -16891,11 +17017,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:16894: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:17020: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:16898: \$? = $ac_status" >&5
+ echo "$as_me:17024: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -17159,11 +17285,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:17162: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:17288: $lt_compile\"" >&5)
(eval "$lt_compile" 2>conftest.err)
ac_status=$?
cat conftest.err >&5
- echo "$as_me:17166: \$? = $ac_status" >&5
+ echo "$as_me:17292: \$? = $ac_status" >&5
if (exit $ac_status) && test -s "$ac_outfile"; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings other than the usual output.
@@ -17263,11 +17389,11 @@ else
-e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
-e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
-e 's:$: $lt_compiler_flag:'`
- (eval echo "\"\$as_me:17266: $lt_compile\"" >&5)
+ (eval echo "\"\$as_me:17392: $lt_compile\"" >&5)
(eval "$lt_compile" 2>out/conftest.err)
ac_status=$?
cat out/conftest.err >&5
- echo "$as_me:17270: \$? = $ac_status" >&5
+ echo "$as_me:17396: \$? = $ac_status" >&5
if (exit $ac_status) && test -s out/conftest2.$ac_objext
then
# The compiler can only warn and ignore the option if not recognized
@@ -28493,7 +28619,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by lighttpd $as_me 1.4.16, which was
+This file was extended by lighttpd $as_me 1.4.17, which was
generated by GNU Autoconf 2.61. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -28546,7 +28672,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-lighttpd config.status 1.4.16
+lighttpd config.status 1.4.17
configured by $0, generated by GNU Autoconf 2.61,
with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/configure.in b/configure.in
index 40338b2..2dd6cb1 100644
--- a/configure.in
+++ b/configure.in
@@ -1,7 +1,7 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.57)
-AC_INIT(lighttpd, 1.4.16, jan@kneschke.de)
+AC_INIT(lighttpd, 1.4.17, jan@kneschke.de)
AC_CONFIG_SRCDIR([src/server.c])
AC_CANONICAL_TARGET
@@ -14,6 +14,7 @@ AM_MAINTAINER_MODE
# Checks for programs.
AC_PROG_CC
+AM_PROG_CC_C_O
AC_PROG_LD
AC_PROG_INSTALL
AC_PROG_AWK
diff --git a/cygwin/lighttpd.README b/cygwin/lighttpd.README
index 9044b58..bfa3631 100644
--- a/cygwin/lighttpd.README
+++ b/cygwin/lighttpd.README
@@ -31,17 +31,17 @@ Canonical download:
------------------------------------
Build instructions:
- unpack lighttpd-1.4.16-<REL>-src.tar.bz2
+ unpack lighttpd-1.4.17-<REL>-src.tar.bz2
if you use setup to install this src package, it will be
unpacked under /usr/src automatically
cd /usr/src
- ./lighttpd-1.4.16-<REL>.sh all
+ ./lighttpd-1.4.17-<REL>.sh all
This will create:
- /usr/src/lighttpd-1.4.16-<REL>.tar.bz2
- /usr/src/lighttpd-1.4.16-<REL>-src.tar.bz2
+ /usr/src/lighttpd-1.4.17-<REL>.tar.bz2
+ /usr/src/lighttpd-1.4.17-<REL>-src.tar.bz2
-Or use './lighttpd-1.4.16-<REL>.sh prep' to get a patched source directory
+Or use './lighttpd-1.4.17-<REL>.sh prep' to get a patched source directory
-------------------------------------------
diff --git a/doc/lighttpd.conf b/doc/lighttpd.conf
index 6a273cf..767e100 100644
--- a/doc/lighttpd.conf
+++ b/doc/lighttpd.conf
@@ -37,10 +37,10 @@ server.modules = (
## a static document-root, for virtual-hosting take look at the
## server.virtual-* options
-server.document-root = "/www/pages/"
+server.document-root = "/srv/www/htdocs/"
## where to send error-messages to
-server.errorlog = "/www/logs/lighttpd.error.log"
+server.errorlog = "/var/log/lighttpd/error.log"
# files to check for if .../ is requested
index-file.names = ( "index.php", "index.html",
@@ -101,7 +101,9 @@ mimetype.assign = (
".wmv" => "video/x-ms-wmv",
".bz2" => "application/x-bzip",
".tbz" => "application/x-bzip-compressed-tar",
- ".tar.bz2" => "application/x-bzip-compressed-tar"
+ ".tar.bz2" => "application/x-bzip-compressed-tar",
+ # default mime type
+ "" => "application/octet-stream",
)
# Use the "Content-Type" extended attribute to obtain mime type if possible
@@ -113,7 +115,7 @@ mimetype.assign = (
# server.tag = "lighttpd"
#### accesslog module
-accesslog.filename = "/www/logs/access.log"
+accesslog.filename = "/var/log/lighttpd/access.log"
## deny access the file-extensions
#
@@ -138,7 +140,7 @@ static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
#server.port = 81
## bind to localhost (default: all interfaces)
-#server.bind = "grisu.home.kneschke.de"
+#server.bind = "127.0.0.1"
## error-handler for status 404
#server.error-handler-404 = "/error-handler.html"
@@ -158,15 +160,16 @@ static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
## or
## virtual-server-root + http-host + virtual-server-docroot
##
-#simple-vhost.server-root = "/home/weigon/wwwroot/servers/"
-#simple-vhost.default-host = "grisu.home.kneschke.de"
-#simple-vhost.document-root = "/pages/"
+#simple-vhost.server-root = "/srv/www/vhosts/"
+#simple-vhost.default-host = "www.example.org"
+#simple-vhost.document-root = "/htdocs/"
##
## Format: <errorfile-prefix><status-code>.html
## -> ..../status-404.html for 'File not found'
-#server.errorfile-prefix = "/home/weigon/projects/lighttpd/doc/status-"
+#server.errorfile-prefix = "/usr/share/lighttpd/errors/status-"
+#server.errorfile-prefix = "/srv/www/errors/status-"
## virtual directory listings
#dir-listing.activate = "enable"
@@ -189,7 +192,7 @@ static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
#server.groupname = "wwwrun"
#### compress module
-#compress.cache-dir = "/tmp/lighttpd/cache/compress/"
+#compress.cache-dir = "/var/cache/lighttpd/compress/"
#compress.filetype = ("text/plain", "text/html")
#### proxy module
@@ -209,8 +212,8 @@ static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
#fastcgi.server = ( ".php" =>
# ( "localhost" =>
# (
-# "socket" => "/tmp/php-fastcgi.socket",
-# "bin-path" => "/usr/local/bin/php"
+# "socket" => "/var/run/lighttpd/php-fastcgi.socket",
+# "bin-path" => "/usr/local/bin/php-cgi"
# )
# )
# )
@@ -222,7 +225,7 @@ static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
#### SSL engine
#ssl.engine = "enable"
-#ssl.pemfile = "server.pem"
+#ssl.pemfile = "/etc/ssl/private/lighttpd.pem"
#### status module
#status.status-url = "/server-status"
@@ -269,7 +272,7 @@ static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
# %3 => subdomain 1 name
# %4 => subdomain 2 name
#
-#evhost.path-pattern = "/home/storage/dev/www/%3/htdocs/"
+#evhost.path-pattern = "/srv/www/vhosts/%3/htdocs/"
#### expire module
#expire.url = ( "/buggy/" => "access 2 hours", "/asdhas/" => "access plus 1 seconds 2 minutes")
@@ -279,14 +282,14 @@ static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
#### rrdtool
#rrdtool.binary = "/usr/bin/rrdtool"
-#rrdtool.db-name = "/var/www/lighttpd.rrd"
+#rrdtool.db-name = "/var/lib/lighttpd/lighttpd.rrd"
#### setenv
#setenv.add-request-header = ( "TRAV_ENV" => "mysql://user@host/db" )
#setenv.add-response-header = ( "X-Secret-Message" => "42" )
## for mod_trigger_b4_dl
-# trigger-before-download.gdbm-filename = "/home/weigon/testbase/trigger.db"
+# trigger-before-download.gdbm-filename = "/var/lib/lighttpd/trigger.db"
# trigger-before-download.memcache-hosts = ( "127.0.0.1:11211" )
# trigger-before-download.trigger-url = "^/trigger/"
# trigger-before-download.download-url = "^/download/"
diff --git a/lighttpd.spec b/lighttpd.spec
index 4967e16..6f5543f 100644
--- a/lighttpd.spec
+++ b/lighttpd.spec
@@ -1,6 +1,6 @@
Summary: A fast webserver with minimal memory-footprint (lighttpd)
Name: lighttpd
-Version: 1.4.16
+Version: 1.4.17
Release: 1
Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz
Packager: Jan Kneschke <jan@kneschke.de>
diff --git a/openwrt/control b/openwrt/control
index 028de2c..21be30a 100644
--- a/openwrt/control
+++ b/openwrt/control
@@ -1,8 +1,8 @@
Package: lighttpd
-Version: 1.4.16
+Version: 1.4.17
Architecture: mipsel
Maintainer: Jan Kneschke <jan@kneschke.de>
-Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.16.tar.gz
+Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.17.tar.gz
Section: net
Priority: optional
Depends:
diff --git a/openwrt/lighttpd.mk b/openwrt/lighttpd.mk
index 33e7711..eb917c3 100644
--- a/openwrt/lighttpd.mk
+++ b/openwrt/lighttpd.mk
@@ -10,7 +10,7 @@
# For this example we'll use a fairly simple package that compiles easily
# and has sources available for download at sourceforge
-LIGHTTPD=lighttpd-1.4.16
+LIGHTTPD=lighttpd-1.4.17
LIGHTTPD_TARGET=.built
LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD)
LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk
diff --git a/src/array.h b/src/array.h
index 862295c..b8a8345 100644
--- a/src/array.h
+++ b/src/array.h
@@ -89,7 +89,9 @@ typedef enum {
COMP_HTTP_USERAGENT,
COMP_HTTP_COOKIE,
COMP_HTTP_REMOTEIP,
- COMP_HTTP_QUERYSTRING
+ COMP_HTTP_QUERYSTRING,
+
+ COMP_LAST_ELEMENT
} comp_key_t;
/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
diff --git a/src/base.h b/src/base.h
index bff7f91..abedf79 100644
--- a/src/base.h
+++ b/src/base.h
@@ -324,6 +324,8 @@ typedef struct {
int patterncount;
int matches[3 * 10];
buffer *comp_value; /* just a pointer */
+
+ comp_key_t comp_type;
} cond_cache_t;
typedef struct {
@@ -416,6 +418,8 @@ typedef struct {
#endif
/* etag handling */
etag_flags_t etag_flags;
+
+ int conditional_is_valid[COMP_LAST_ELEMENT];
} connection;
typedef struct {
diff --git a/src/buffer.c b/src/buffer.c
index 094cee2..ddd1c59 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -281,7 +281,7 @@ int buffer_append_long_hex(buffer *b, unsigned long value) {
return 0;
}
-int ltostr(char *buf, long val) {
+int LI_ltostr(char *buf, long val) {
char swap;
char *end;
int len = 1;
@@ -320,7 +320,7 @@ int buffer_append_long(buffer *b, long val) {
if (b->used == 0)
b->used++;
- b->used += ltostr(b->ptr + (b->used - 1), val);
+ b->used += LI_ltostr(b->ptr + (b->used - 1), val);
return 0;
}
@@ -503,6 +503,7 @@ buffer *buffer_init_string(const char *str) {
}
int buffer_is_empty(buffer *b) {
+ if (!b) return 1;
return (b->used == 0);
}
@@ -574,7 +575,13 @@ int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b
}
}
- return 0;
+ /* all chars are the same, and the length match too
+ *
+ * they are the same */
+ if (a_len == b_len) return 0;
+
+ /* if a is shorter then b, then b is larger */
+ return (a_len - b_len);
}
diff --git a/src/buffer.h b/src/buffer.h
index af82d45..571506e 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -103,7 +103,7 @@ int buffer_to_lower(buffer *b);
int buffer_to_upper(buffer *b);
/** deprecated */
-int ltostr(char *buf, long val);
+int LI_ltostr(char *buf, long val);
char hex2int(unsigned char c);
char int2hex(char i);
diff --git a/src/configfile-glue.c b/src/configfile-glue.c
index d783689..f6ead92 100644
--- a/src/configfile-glue.c
+++ b/src/configfile-glue.c
@@ -6,6 +6,8 @@
#include "log.h"
#include "plugin.h"
+#include "configfile.h"
+
/**
* like all glue code this file contains functions which
* are the external interface of lighttpd. The functions
@@ -133,6 +135,7 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t
break;
}
}
+
return 0;
}
@@ -174,28 +177,62 @@ static cond_result_t config_check_cond_cached(server *srv, connection *con, data
static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
buffer *l;
server_socket *srv_sock = con->srv_socket;
+
/* check parent first */
if (dc->parent && dc->parent->context_ndx) {
+ /**
+ * a nested conditional
+ *
+ * if the parent is not decided yet or false, we can't be true either
+ */
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "sb", "go parent", dc->parent->key);
}
- if (config_check_cond_cached(srv, con, dc->parent) == COND_RESULT_FALSE) {
+
+ switch (config_check_cond_cached(srv, con, dc->parent)) {
+ case COND_RESULT_FALSE:
return COND_RESULT_FALSE;
+ case COND_RESULT_UNSET:
+ return COND_RESULT_UNSET;
+ default:
+ break;
}
}
if (dc->prev) {
+ /**
+ * a else branch
+ *
+ * we can only be executed, if all of our previous brothers
+ * are false
+ */
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "sb", "go prev", dc->prev->key);
}
+
/* make sure prev is checked first */
config_check_cond_cached(srv, con, dc->prev);
+
/* one of prev set me to FALSE */
- if (COND_RESULT_FALSE == con->cond_cache[dc->context_ndx].result) {
- return COND_RESULT_FALSE;
+ switch (con->cond_cache[dc->context_ndx].result) {
+ case COND_RESULT_FALSE:
+ return con->cond_cache[dc->context_ndx].result;
+ default:
+ break;
}
}
+ if (!con->conditional_is_valid[dc->comp]) {
+ if (con->conf.log_condition_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "dss",
+ dc->comp,
+ dc->key->ptr,
+ con->conditional_is_valid[dc->comp] ? "yeah" : "nej");
+ }
+
+ return COND_RESULT_UNSET;
+ }
+
/* pass the rules */
switch (dc->comp) {
@@ -385,6 +422,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat
cache->patterncount = n;
if (n > 0) {
cache->comp_value = l;
+ cache->comp_type = dc->comp;
return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
} else {
/* cache is already cleared */
@@ -417,32 +455,54 @@ static cond_result_t config_check_cond_cached(server *srv, connection *con, data
}
}
}
+ caches[dc->context_ndx].comp_type = dc->comp;
+
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
"(uncached) result:",
- caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
+ caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
+ (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
}
} else {
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
"(cached) result:",
- caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
+ caches[dc->context_ndx].result == COND_RESULT_UNSET ? "unknown" :
+ (caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false"));
}
}
return caches[dc->context_ndx].result;
}
+/**
+ * reset the config-cache for a named item
+ *
+ * if the item is COND_LAST_ELEMENT we reset all items
+ */
+void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item) {
+ size_t i;
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ if (item == COMP_LAST_ELEMENT ||
+ con->cond_cache[i].comp_type == item) {
+ con->cond_cache[i].result = COND_RESULT_UNSET;
+ con->cond_cache[i].patterncount = 0;
+ con->cond_cache[i].comp_value = NULL;
+ }
+ }
+}
+
+/**
+ * reset the config cache to its initial state at connection start
+ */
void config_cond_cache_reset(server *srv, connection *con) {
-#if COND_RESULT_UNSET
size_t i;
- for (i = srv->config_context->used - 1; i >= 0; i --) {
- con->cond_cache[i].result = COND_RESULT_UNSET;
- con->cond_cache[i].patterncount = 0;
+ config_cond_cache_reset_all_items(srv, con);
+
+ for (i = 0; i < COMP_LAST_ELEMENT; i++) {
+ con->conditional_is_valid[i] = 0;
}
-#else
- memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
-#endif
}
int config_check_cond(server *srv, connection *con, data_config *dc) {
diff --git a/src/configfile.c b/src/configfile.c
index 921109f..09fe87d 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -298,6 +298,8 @@ int config_setup_connection(server *srv, connection *con) {
int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
size_t i, j;
+ con->conditional_is_valid[comp] = 1;
+
/* 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];
diff --git a/src/configfile.h b/src/configfile.h
index 600297f..f46e869 100644
--- a/src/configfile.h
+++ b/src/configfile.h
@@ -21,4 +21,10 @@ int config_parse_file(server *srv, config_t *context, const char *fn);
int config_parse_cmd(server *srv, config_t *context, const char *cmd);
data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2);
+void config_cond_cache_reset(server *srv, connection *con);
+void config_cond_cache_reset_item(server *srv, connection *con, comp_key_t item);
+
+#define config_cond_cache_reset_all_items(srv, con) \
+ config_cond_cache_reset_item(srv, con, COMP_LAST_ELEMENT);
+
#endif
diff --git a/src/connections.c b/src/connections.c
index 2f715ef..62b4d5e 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -505,6 +505,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
case 206: /* write_queue is already prepared */
break;
+ case 204:
case 205: /* class: header only */
case 304:
default:
@@ -524,39 +525,51 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
(con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
off_t qlen = chunkqueue_length(con->write_queue);
- /* if we have no content for a GET/PORT request, send Content-Length: 0
- * if it is a HEAD request, don't generate a Content-Length as
- * the backend might have already cut it off */
- if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) {
+ /**
+ * The Content-Length header only can be sent if we have content:
+ * - HEAD doesn't have a content-body (but have a content-length)
+ * - 1xx, 204 and 304 don't have a content-body (RFC 2616 Section 4.3)
+ *
+ * Otherwise generate a Content-Length header as chunked encoding is not
+ * available
+ */
+ if ((con->http_status >= 100 && con->http_status < 200) ||
+ con->http_status == 204 ||
+ con->http_status == 304) {
+ /* no Content-Body, no Content-Length */
+ } else if (qlen > 0) {
buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
}
}
} else {
- /* disable keep-alive if size-info for the body is missing */
- if ((con->parsed_response & HTTP_CONTENT_LENGTH) &&
+ /**
+ * the file isn't finished yet, but we have all headers
+ *
+ * to get keep-alive we either need:
+ * - Content-Length: ... (HTTP/1.0 and HTTP/1.0) or
+ * - Transfer-Encoding: chunked (HTTP/1.1)
+ */
+
+ if (((con->parsed_response & HTTP_CONTENT_LENGTH) == 0) &&
((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
con->keep_alive = 0;
}
- if (0 == (con->parsed_response & HTTP_CONNECTION)) {
- /* (f)cgi did'nt send Connection: header
- *
- * shall we ?
- */
- if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
- (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
- /* without content_length, no keep-alive */
-
- con->keep_alive = 0;
- }
- } else {
+ /**
+ * if the backend sent a Connection: close, follow the wish
+ *
+ * NOTE: if the backend sent Connection: Keep-Alive, but no Content-Length, we
+ * will close the connection. That's fine. We can always decide the close
+ * the connection
+ *
+ * FIXME: to be nice we should remove the Connection: ...
+ */
+ if (con->parsed_response & HTTP_CONNECTION) {
/* a subrequest disable keep-alive although the client wanted it */
if (con->keep_alive && !con->response.keep_alive) {
con->keep_alive = 0;
-
- /* FIXME: we have to drop the Connection: Header from the subrequest */
}
}
}
@@ -1412,42 +1425,42 @@ int connection_state_machine(server *srv, connection *con) {
switch (r = http_response_prepare(srv, con)) {
case HANDLER_FINISHED:
- if (con->http_status == 404 ||
- con->http_status == 403) {
- /* 404 error-handler */
-
- if (con->in_error_handler == 0 &&
- (!buffer_is_empty(con->conf.error_handler) ||
- !buffer_is_empty(con->error_handler))) {
- /* call error-handler */
-
- con->error_handler_saved_status = con->http_status;
- con->http_status = 0;
-
- if (buffer_is_empty(con->error_handler)) {
- buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
- } else {
- buffer_copy_string_buffer(con->request.uri, con->error_handler);
- }
- buffer_reset(con->physical.path);
+ if (con->mode == DIRECT) {
+ if (con->http_status == 404 ||
+ con->http_status == 403) {
+ /* 404 error-handler */
- con->in_error_handler = 1;
+ if (con->in_error_handler == 0 &&
+ (!buffer_is_empty(con->conf.error_handler) ||
+ !buffer_is_empty(con->error_handler))) {
+ /* call error-handler */
- connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+ con->error_handler_saved_status = con->http_status;
+ con->http_status = 0;
- done = -1;
- break;
- } else if (con->in_error_handler) {
- /* error-handler is a 404 */
+ if (buffer_is_empty(con->error_handler)) {
+ buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
+ } else {
+ buffer_copy_string_buffer(con->request.uri, con->error_handler);
+ }
+ buffer_reset(con->physical.path);
- con->http_status = con->error_handler_saved_status;
+ con->in_error_handler = 1;
+
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
+
+ done = -1;
+ break;
+ } else if (con->in_error_handler) {
+ /* error-handler is a 404 */
+
+ con->http_status = con->error_handler_saved_status;
+ }
+ } else if (con->in_error_handler) {
+ /* error-handler is back and has generated content */
+ /* if Status: was set, take it otherwise use 200 */
}
- } else if (con->in_error_handler) {
- /* error-handler is back and has generated content */
- /* if Status: was set, take it otherwise use 200 */
- con->http_status = con->error_handler_saved_status;
}
-
if (con->http_status == 0) con->http_status = 200;
/* we have something to send, go on */
diff --git a/src/etag.c b/src/etag.c
index 91207ca..c1146c3 100644
--- a/src/etag.c
+++ b/src/etag.c
@@ -1,10 +1,11 @@
#include <string.h>
+#include <stdint.h>
#include "buffer.h"
#include "etag.h"
int etag_is_equal(buffer *etag, const char *matches) {
- if (0 == strcmp(etag->ptr, matches)) return 1;
+ if (etag && !buffer_is_empty(etag) && 0 == strcmp(etag->ptr, matches)) return 1;
return 0;
}
@@ -31,7 +32,8 @@ int etag_create(buffer *etag, struct stat *st,etag_flags_t flags) {
}
int etag_mutate(buffer *mut, buffer *etag) {
- size_t h, i;
+ size_t i;
+ uint32_t h;
for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
diff --git a/src/http-header-glue.c b/src/http-header-glue.c
index 359efe9..7903c05 100644
--- a/src/http-header-glue.c
+++ b/src/http-header-glue.c
@@ -279,7 +279,10 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
strncpy(buf, con->request.http_if_modified_since, used_len);
buf[used_len] = '\0';
- strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
+ if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
+ con->http_status = 412;
+ return HANDLER_FINISHED;
+ }
t_header = mktime(&tm);
strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
@@ -323,7 +326,14 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) {
strncpy(buf, con->request.http_if_modified_since, used_len);
buf[used_len] = '\0';
- strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
+ if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) {
+ /**
+ * parsing failed, let's get out of here
+ */
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "strptime() failed on", buf);
+ return HANDLER_GO_ON;
+ }
t_header = mktime(&tm);
strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
diff --git a/src/http_auth.c b/src/http_auth.c
index abb69f5..b95b79b 100644
--- a/src/http_auth.c
+++ b/src/http_auth.c
@@ -1174,9 +1174,9 @@ int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer
MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
/* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
- ltostr(hh, srv->cur_ts);
+ LI_ltostr(hh, srv->cur_ts);
MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
- ltostr(hh, rand());
+ LI_ltostr(hh, rand());
MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
MD5_Final(h, &Md5Ctx);
diff --git a/src/log.c b/src/log.c
index d1e0c7d..899d14a 100644
--- a/src/log.c
+++ b/src/log.c
@@ -126,14 +126,10 @@ int log_error_cycle(server *srv) {
}
}
- log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
-
return 0;
}
int log_error_close(server *srv) {
- log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
-
switch(srv->errorlog_mode) {
case ERRORLOG_FILE:
close(srv->errorlog_fd);
diff --git a/src/mod_alias.c b/src/mod_alias.c
index 43b11c2..a7d9b7e 100644
--- a/src/mod_alias.c
+++ b/src/mod_alias.c
@@ -45,6 +45,8 @@ FREE_FUNC(mod_alias_free) {
for (i = 0; i < srv->config_context->used; i++) {
plugin_config *s = p->config_storage[i];
+ if(!s) continue;
+
array_free(s->alias);
free(s);
diff --git a/src/mod_auth.c b/src/mod_auth.c
index ef4f6c8..19ed387 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -503,45 +503,6 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) {
}
switch(s->auth_backend) {
- case AUTH_BACKEND_PLAIN:
- if (s->auth_plain_userfile->used) {
- int fd;
- /* try to read */
- if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
- "failed:", strerror(errno));
- return HANDLER_ERROR;
- }
- close(fd);
- }
- break;
- case AUTH_BACKEND_HTPASSWD:
- if (s->auth_htpasswd_userfile->used) {
- int fd;
- /* try to read */
- if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
- "failed:", strerror(errno));
- return HANDLER_ERROR;
- }
- close(fd);
- }
- break;
- case AUTH_BACKEND_HTDIGEST:
- if (s->auth_htdigest_userfile->used) {
- int fd;
- /* try to read */
- if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "sbss",
- "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
- "failed:", strerror(errno));
- return HANDLER_ERROR;
- }
- close(fd);
- }
- break;
case AUTH_BACKEND_LDAP: {
handler_t ret = auth_ldap_init(srv, s);
if (ret == HANDLER_ERROR)
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index 7da9815..f5e5b3a 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -222,7 +222,7 @@ static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
return 0;
}
-static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
+static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
char *ns;
const char *s;
int line = 0;
@@ -232,14 +232,17 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff
buffer_copy_string_buffer(p->parse_response, in);
for (s = p->parse_response->ptr;
- NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
- s = ns + (eol == EOL_RN ? 2 : 1), line++) {
+ NULL != (ns = strchr(s, '\n'));
+ s = ns + 1, line++) {
const char *key, *value;
int key_len;
data_string *ds;
+ /* strip the \n */
ns[0] = '\0';
+ if (ns > s && ns[-1] == '\r') ns[-1] = '\0';
+
if (line == 0 &&
0 == strncmp(s, "HTTP/1.", 7)) {
/* non-parsed header ... we parse them anyway */
@@ -252,15 +255,15 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff
status = strtol(s+9, NULL, 10);
- if (con->http_status >= 100 &&
- con->http_status < 1000) {
+ if (status >= 100 &&
+ status < 1000) {
/* we expected 3 digits and didn't got them */
con->parsed_response |= HTTP_STATUS;
con->http_status = status;
}
}
} else {
-
+ /* parse the headers */
key = s;
if (NULL == (value = strchr(s, ':'))) {
/* we expect: "<key>: <value>\r\n" */
@@ -362,63 +365,76 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
/* split header from body */
if (con->file_started == 0) {
- char *c;
- int in_header = 0;
- int header_end = 0;
- int cp, eol = EOL_UNSET;
- size_t used = 0;
+ int is_header = 0;
+ int is_header_end = 0;
+ size_t last_eol = 0;
+ size_t i;
buffer_append_string_buffer(hctx->response_header, hctx->response);
+ /**
+ * we have to handle a few cases:
+ *
+ * nph:
+ *
+ * HTTP/1.0 200 Ok\n
+ * Header: Value\n
+ * \n
+ *
+ * CGI:
+ * Header: Value\n
+ * Status: 200\n
+ * \n
+ *
+ * and different mixes of \n and \r\n combinations
+ *
+ * Some users also forget about CGI and just send a response and hope
+ * we handle it. No headers, no header-content seperator
+ *
+ */
+
/* nph (non-parsed headers) */
- if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
-
- /* search for the \r\n\r\n or \n\n in the string */
- for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
- if (*c == ':') in_header = 1;
- else if (*c == '\n') {
- if (in_header == 0) {
- /* got a response without a response header */
-
- c = NULL;
- header_end = 1;
- break;
- }
+ if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) is_header = 1;
+
+ for (i = 0; !is_header_end && i < hctx->response_header->used - 1; i++) {
+ char c = hctx->response_header->ptr[i];
+
+ switch (c) {
+ case ':':
+ /* we found a colon
+ *
+ * looks like we have a normal header
+ */
+ is_header = 1;
+ break;
+ case '\n':
+ /* EOL */
+ if (is_header == 0) {
+ /* we got a EOL but we don't seem to got a HTTP header */
- if (eol == EOL_UNSET) eol = EOL_N;
+ is_header_end = 1;
- if (*(c+1) == '\n') {
- header_end = 1;
break;
}
- } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
- if (in_header == 0) {
- /* got a response without a response header */
-
- c = NULL;
- header_end = 1;
+ /**
+ * check if we saw a \n(\r)?\n sequence
+ */
+ if (last_eol > 0 &&
+ ((i - last_eol == 1) ||
+ (i - last_eol == 2 && hctx->response_header->ptr[i - 1] == '\r'))) {
+ is_header_end = 1;
break;
}
- if (eol == EOL_UNSET) eol = EOL_RN;
+ last_eol = i;
- if (used > 3 &&
- *(c+2) == '\r' &&
- *(c+3) == '\n') {
- header_end = 1;
- break;
- }
-
- /* skip the \n */
- c++;
- cp++;
- used--;
+ break;
}
}
- if (header_end) {
- if (c == NULL) {
+ if (is_header_end) {
+ if (!is_header) {
/* no header, but a body */
if (con->request.http_version == HTTP_VERSION_1_1) {
@@ -428,15 +444,30 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
joblist_append(srv, con);
} else {
- size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
- size_t blen = hctx->response_header->used - hlen - 1;
-
- /* a small hack: terminate after at the second \r */
- hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
- hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
+ const char *bstart;
+ size_t blen;
+
+ /**
+ * i still points to the char after the terminating EOL EOL
+ *
+ * put it on the last \n again
+ */
+ i--;
+
+ /* the body starts after the EOL */
+ bstart = hctx->response_header->ptr + (i + 1);
+ blen = (hctx->response_header->used - 1) - (i + 1);
+
+ /* string the last \r?\n */
+ if (i > 0 && (hctx->response_header->ptr[i - 1] == '\r')) {
+ i--;
+ }
+ hctx->response_header->ptr[i] = '\0';
+ hctx->response_header->used = i + 1; /* the string + \0 */
+
/* parse the response header */
- cgi_response_parse(srv, con, p, hctx->response_header, eol);
+ cgi_response_parse(srv, con, p, hctx->response_header);
/* enable chunked-transfer-encoding */
if (con->request.http_version == HTTP_VERSION_1_1 &&
@@ -444,8 +475,8 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) {
con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
}
- if ((hctx->response->used != hlen) && blen > 0) {
- http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
+ if (blen > 0) {
+ http_chunk_append_mem(srv, con, bstart, blen + 1);
joblist_append(srv, con);
}
}
@@ -782,7 +813,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
- ltostr(buf,
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
@@ -828,7 +859,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
#endif
cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
- ltostr(buf,
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
@@ -849,7 +880,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *
#endif
/* request.content_length < SSIZE_MAX, see request.c */
- ltostr(buf, con->request.content_length);
+ LI_ltostr(buf, con->request.content_length);
cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
diff --git a/src/mod_compress.c b/src/mod_compress.c
index b528ebf..464945e 100644
--- a/src/mod_compress.c
+++ b/src/mod_compress.c
@@ -589,6 +589,13 @@ PHYSICALPATH_FUNC(mod_compress_physical) {
/* don't compress files that are too large as we need to much time to handle them */
if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
+ /* don't try to compress files less than 128 bytes
+ *
+ * - extra overhead for compression
+ * - mmap() fails for st_size = 0 :)
+ */
+ if (sce->st.st_size < 128) return HANDLER_GO_ON;
+
/* check if mimetype is in compress-config */
for (m = 0; m < p->conf.compress->used; m++) {
data_string *compress_ds = (data_string *)p->conf.compress->data[m];
diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
index bd23f09..50d3046 100644
--- a/src/mod_dirlisting.c
+++ b/src/mod_dirlisting.c
@@ -59,6 +59,7 @@ typedef struct {
buffer *external_css;
buffer *encoding;
+ buffer *set_footer;
} plugin_config;
typedef struct {
@@ -173,6 +174,7 @@ FREE_FUNC(mod_dirlisting_free) {
excludes_buffer_free(s->excludes);
buffer_free(s->external_css);
buffer_free(s->encoding);
+ buffer_free(s->set_footer);
free(s);
}
@@ -240,6 +242,8 @@ static int parse_config_entry(server *srv, plugin_config *s, array *ca, const ch
#define CONFIG_SHOW_HEADER "dir-listing.show-header"
#define CONFIG_HIDE_HEADER_FILE "dir-listing.hide-header-file"
#define CONFIG_DIR_LISTING "server.dir-listing"
+#define CONFIG_SET_FOOTER "dir-listing.set-footer"
+
SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
plugin_data *p = p_d;
@@ -256,6 +260,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
{ CONFIG_SHOW_HEADER, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
{ CONFIG_HIDE_HEADER_FILE, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
{ CONFIG_DIR_LISTING, NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
+ { CONFIG_SET_FOOTER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -278,6 +283,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
s->show_header = 0;
s->hide_header_file = 0;
s->encoding = buffer_init();
+ s->set_footer = buffer_init();
cv[0].destination = s->excludes;
cv[1].destination = &(s->dir_listing);
@@ -289,6 +295,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
cv[7].destination = &(s->show_header);
cv[8].destination = &(s->hide_header_file);
cv[9].destination = &(s->dir_listing); /* old name */
+ cv[10].destination = s->set_footer;
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
@@ -318,6 +325,7 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH(show_header);
PATCH(hide_header_file);
PATCH(excludes);
+ PATCH(set_footer);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
@@ -348,6 +356,8 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH(show_header);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_HIDE_HEADER_FILE))) {
PATCH(hide_header_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_SET_FOOTER))) {
+ PATCH(set_footer);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_EXCLUDE))) {
PATCH(excludes);
}
@@ -432,7 +442,7 @@ static int http_list_directory_sizefmt(char *buf, off_t size) {
u++;
}
- out += ltostr(out, size);
+ out += LI_ltostr(out, size);
out[0] = '.';
out[1] = remain + '0';
out[2] = *u;
@@ -467,8 +477,7 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
"h2 {margin-bottom: 12px;}\n"
"table {margin-left: 12px;}\n"
"th, td {"
- " font-family: \"Courier New\", Courier, monospace;"
- " font-size: 10pt;"
+ " font: 90% monospace;"
" text-align: left;"
"}\n"
"th {"
@@ -488,8 +497,7 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
" padding-bottom: 14px;"
"}\n"
"div.foot {"
- " font-family: \"Courier New\", Courier, monospace;"
- " font-size: 10pt;"
+ " font: 90% monospace;"
" color: #787878;"
" padding-top: 4px;"
"}\n"
@@ -569,7 +577,9 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data
"<div class=\"foot\">"
);
- if (buffer_is_empty(con->conf.server_tag)) {
+ if (p->conf.set_footer->used > 1) {
+ buffer_append_string_buffer(out, p->conf.set_footer);
+ } else if (buffer_is_empty(con->conf.server_tag)) {
BUFFER_APPEND_STRING_CONST(out, PACKAGE_NAME "/" PACKAGE_VERSION);
} else {
buffer_append_string_buffer(out, con->conf.server_tag);
diff --git a/src/mod_extforward.c b/src/mod_extforward.c
index 23c367d..8ed336d 100644
--- a/src/mod_extforward.c
+++ b/src/mod_extforward.c
@@ -1,3 +1,7 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -11,9 +15,7 @@
#include "plugin.h"
#include "inet_ntop_cache.h"
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
+#include "configfile.h"
/**
* mod_extforward.c for lighttpd, by comman.kang <at> gmail <dot> com
@@ -181,17 +183,6 @@ static int mod_extforward_patch_connection(server *srv, connection *con, plugin_
PATCH(forwarder);
- /* LEM: The purpose of this seems to match extforward configuration
- stanzas that are not in the global context, but in some sub-context.
- I fear this will break contexts of the form HTTP['remote'] = .
- (in the form that they do not work with the real remote, but matching on
- the proxy instead).
-
- I'm not sure this this is all thread-safe. Is the p we are passed different
- for each connection or is it global?
-
- mod_fastcgi does the same, so it must be safe.
- */
/* 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];
@@ -312,19 +303,9 @@ struct addrinfo *ipstr_to_sockaddr(const char *host)
}
-static void clean_cond_cache(server *srv, connection *con)
-{
- size_t i;
-
- for (i = 0; i < srv->config_context->used; i++) {
- data_config *dc = (data_config *)srv->config_context->data[i];
- if (dc->comp == COMP_HTTP_REMOTEIP)
- {
- con->cond_cache[i].result = COND_RESULT_UNSET;
- con->cond_cache[i].patterncount = 0;
- }
- }
+static void clean_cond_cache(server *srv, connection *con) {
+ config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTEIP);
}
URIHANDLER_FUNC(mod_extforward_uri_handler) {
@@ -457,28 +438,22 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) {
CONNECTION_FUNC(mod_extforward_restore) {
plugin_data *p = p_d;
- UNUSED(srv);
+ handler_ctx *hctx = con->plugin_ctx[p->id];
+
+ if (!hctx) return HANDLER_GO_ON;
+
+ con->dst_addr = hctx->saved_remote_addr;
+ buffer_free(con->dst_addr_buf);
+
+ con->dst_addr_buf = hctx->saved_remote_addr_buf;
+
+ handler_ctx_free(hctx);
+
+ con->plugin_ctx[p->id] = NULL;
+
+ /* Now, clean the conf_cond cache, because we may have changed the results of tests */
+ clean_cond_cache(srv, con);
- /* LEM: This seems completely unuseful, as we are not using
- p->conf in this function. Furthermore, it brings a
- segfault if one of the conditional configuration
- blocks is "SERVER['socket'] == foo", because the
- socket is not known yet in the srv/con structure.
- */
- /* mod_extforward_patch_connection(srv, con, p); */
-
- /* restore this connection's remote ip */
- if (con->plugin_ctx[p->id]) {
- handler_ctx *hctx = con->plugin_ctx[p->id];
- con->dst_addr = hctx->saved_remote_addr;
- buffer_free(con->dst_addr_buf);
- con->dst_addr_buf = hctx->saved_remote_addr_buf;
-/* log_error_write(srv, __FILE__, __LINE__,"s","LEM: Reset dst_addr_buf"); */
- handler_ctx_free(hctx);
- con->plugin_ctx[p->id] = NULL;
- /* Now, clean the conf_cond cache, because we may have changed the results of tests */
- clean_cond_cache(srv, con);
- }
return HANDLER_GO_ON;
}
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index 2e7f339..e0dda30 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -42,11 +42,6 @@
#include "sys-socket.h"
-
-#ifndef UNIX_PATH_MAX
-# define UNIX_PATH_MAX 108
-#endif
-
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
@@ -1254,8 +1249,9 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if (!buffer_is_empty(host->unixsocket)) {
/* unix domain socket */
+ struct sockaddr_un un;
- if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
+ if (host->unixsocket->used > sizeof(un.sun_path) - 2) {
log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
"unixsocket is too long in:",
da->key, "= (",
@@ -1848,7 +1844,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
- ltostr(buf,
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
@@ -1868,7 +1864,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
}
fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
- ltostr(buf,
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
@@ -1918,7 +1914,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) {
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
/* request.content_length < SSIZE_MAX, see request.c */
- ltostr(buf, con->request.content_length);
+ LI_ltostr(buf, con->request.content_length);
fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
}
diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
index a33eecb..65e7ce9 100644
--- a/src/mod_mysql_vhost.c
+++ b/src/mod_mysql_vhost.c
@@ -244,7 +244,7 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
/* all have to be set */
if (!(buffer_is_empty(s->myuser) ||
buffer_is_empty(s->mydb))) {
-
+ my_bool reconnect = 1;
int fd;
if (NULL == (s->mysql = mysql_init(NULL))) {
@@ -252,6 +252,12 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) {
return HANDLER_ERROR;
}
+
+#if MYSQL_VERSION_ID >= 50013
+ /* in mysql versions above 5.0.3 the reconnect flag is off by default */
+ mysql_options(s->mysql, MYSQL_OPT_RECONNECT, &reconnect);
+#endif
+
#define FOO(x) (s->x->used ? s->x->ptr : NULL)
if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index c61f68b..c4ac15f 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -63,7 +63,7 @@ typedef enum {
typedef struct {
array *extensions;
- int debug;
+ unsigned short debug;
proxy_balance_t balance;
} plugin_config;
diff --git a/src/mod_scgi.c b/src/mod_scgi.c
index 5680091..bc487c5 100644
--- a/src/mod_scgi.c
+++ b/src/mod_scgi.c
@@ -31,11 +31,6 @@
#include "sys-socket.h"
-
-#ifndef UNIX_PATH_MAX
-# define UNIX_PATH_MAX 108
-#endif
-
#ifdef HAVE_SYS_UIO_H
#include <sys/uio.h>
#endif
@@ -1027,8 +1022,9 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) {
if (!buffer_is_empty(df->unixsocket)) {
/* unix domain socket */
+ struct sockaddr_un un;
- if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
+ if (df->unixsocket->used > sizeof(un.sun_path) - 2) {
log_error_write(srv, __FILE__, __LINE__, "s",
"path of the unixdomain socket is too large");
return HANDLER_ERROR;
@@ -1430,7 +1426,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
/* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
/* request.content_length < SSIZE_MAX, see request.c */
- ltostr(buf, con->request.content_length);
+ LI_ltostr(buf, con->request.content_length);
scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
scgi_env_add(p->scgi_env, CONST_STR_LEN("SCGI"), CONST_STR_LEN("1"));
@@ -1454,7 +1450,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
- ltostr(buf,
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
@@ -1474,7 +1470,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) {
}
scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
- ltostr(buf,
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
#else
diff --git a/src/mod_ssi.c b/src/mod_ssi.c
index 6621f9d..e706e8f 100644
--- a/src/mod_ssi.c
+++ b/src/mod_ssi.c
@@ -225,7 +225,7 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
- ltostr(buf,
+ LI_ltostr(buf,
#ifdef HAVE_IPV6
ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
#else
@@ -247,7 +247,7 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
/* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
/* request.content_length < SSIZE_MAX, see request.c */
- ltostr(buf, con->request.content_length);
+ LI_ltostr(buf, con->request.content_length);
ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
}
diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
index e371410..59fafee 100644
--- a/src/mod_staticfile.c
+++ b/src/mod_staticfile.c
@@ -506,6 +506,7 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
*/
http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
+ con->http_status = 200;
con->file_finished = 1;
return HANDLER_FINISHED;
diff --git a/src/mod_status.c b/src/mod_status.c
index e64cb29..80c0040 100644
--- a/src/mod_status.c
+++ b/src/mod_status.c
@@ -559,19 +559,22 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
buffer *b;
double avg;
time_t ts;
+ char buf[32];
b = chunkqueue_get_append_buffer(con->write_queue);
/* output total number of requests */
BUFFER_APPEND_STRING_CONST(b, "Total Accesses: ");
avg = p->abs_requests;
- buffer_append_long(b, avg);
+ snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
+ buffer_append_string(b, buf);
BUFFER_APPEND_STRING_CONST(b, "\n");
/* output total traffic out in kbytes */
BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
avg = p->abs_traffic_out / 1024;
- buffer_append_long(b, avg);
+ snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
+ buffer_append_string(b, buf);
BUFFER_APPEND_STRING_CONST(b, "\n");
/* output uptime */
diff --git a/src/mod_usertrack.c b/src/mod_usertrack.c
index fb1839d..6c228b3 100644
--- a/src/mod_usertrack.c
+++ b/src/mod_usertrack.c
@@ -227,9 +227,9 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) {
MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
/* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
- ltostr(hh, srv->cur_ts);
+ LI_ltostr(hh, srv->cur_ts);
MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
- ltostr(hh, rand());
+ LI_ltostr(hh, rand());
MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
MD5_Final(h, &Md5Ctx);
diff --git a/src/network_freebsd_sendfile.c b/src/network_freebsd_sendfile.c
index b6b1abe..6150834 100644
--- a/src/network_freebsd_sendfile.c
+++ b/src/network_freebsd_sendfile.c
@@ -136,7 +136,6 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f
off_t offset, r;
size_t toSend;
stat_cache_entry *sce = NULL;
- int ifd;
if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
log_error_write(srv, __FILE__, __LINE__, "sb",
@@ -149,35 +148,55 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f
toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
((1 << 30) - 1) : c->file.length - c->offset;
- if (offset > sce->st.st_size) {
- log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
+ if (-1 == c->file.fd) {
+ if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
+ log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
- return -1;
- }
-
- if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
- log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
+ return -1;
+ }
- return -1;
+#ifdef FD_CLOEXEC
+ fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
+#endif
}
r = 0;
/* FreeBSD sendfile() */
- if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
+ if (-1 == sendfile(c->file.fd, fd, offset, toSend, NULL, &r, 0)) {
switch(errno) {
case EAGAIN:
break;
case ENOTCONN:
- close(ifd);
return -2;
default:
log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
- close(ifd);
return -1;
}
}
- close(ifd);
+
+ if (r == 0) {
+ int oerrno = errno;
+ /* We got an event to write but we wrote nothing
+ *
+ * - the file shrinked -> error
+ * - the remote side closed inbetween -> remote-close */
+
+ if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
+ /* file is gone ? */
+ return -1;
+ }
+
+ if (offset >= sce->st.st_size) {
+ /* file shrinked, close the connection */
+ errno = oerrno;
+
+ return -1;
+ }
+
+ errno = oerrno;
+ return -2;
+ }
c->offset += r;
cq->bytes_out += r;
diff --git a/src/request.c b/src/request.c
index 92660a0..4298873 100644
--- a/src/request.c
+++ b/src/request.c
@@ -922,6 +922,9 @@ int http_request_parse(server *srv, connection *con) {
} else if (0 == strcasecmp(con->request.http_if_modified_since,
ds->value->ptr)) {
/* ignore it if they are the same */
+
+ ds->free((data_unset *)ds);
+ ds = NULL;
} else {
con->http_status = 400;
con->keep_alive = 0;
@@ -977,7 +980,7 @@ int http_request_parse(server *srv, connection *con) {
}
}
- array_insert_unique(con->request.headers, (data_unset *)ds);
+ if (ds) array_insert_unique(con->request.headers, (data_unset *)ds);
} else {
/* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
}
@@ -1011,6 +1014,17 @@ int http_request_parse(server *srv, connection *con) {
/* strip leading WS */
if (value == cur) value = cur+1;
default:
+ if (*cur >= 0 && *cur < 32) {
+ if (srv->srvconf.log_request_header_on_error) {
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "invalid char in header", (int)*cur, "-> 400");
+ }
+
+ con->http_status = 400;
+ con->keep_alive = 0;
+
+ return 0;
+ }
break;
}
}
diff --git a/src/server.c b/src/server.c
index 7eaae3e..b610cdc 100644
--- a/src/server.c
+++ b/src/server.c
@@ -70,20 +70,35 @@ static volatile sig_atomic_t handle_sig_alarm = 1;
static volatile sig_atomic_t handle_sig_hup = 0;
#if defined(HAVE_SIGACTION) && defined(SA_SIGINFO)
+static volatile siginfo_t last_sigterm_info;
+static volatile siginfo_t last_sighup_info;
+
static void sigaction_handler(int sig, siginfo_t *si, void *context) {
- UNUSED(si);
UNUSED(context);
switch (sig) {
- case SIGTERM: srv_shutdown = 1; break;
+ case SIGTERM:
+ srv_shutdown = 1;
+ memcpy(&last_sigterm_info, si, sizeof(*si));
+ break;
case SIGINT:
- if (graceful_shutdown) srv_shutdown = 1;
- else graceful_shutdown = 1;
-
- break;
- case SIGALRM: handle_sig_alarm = 1; break;
- case SIGHUP: handle_sig_hup = 1; break;
- case SIGCHLD: break;
+ if (graceful_shutdown) {
+ srv_shutdown = 1;
+ } else {
+ graceful_shutdown = 1;
+ }
+ memcpy(&last_sigterm_info, si, sizeof(*si));
+
+ break;
+ case SIGALRM:
+ handle_sig_alarm = 1;
+ break;
+ case SIGHUP:
+ handle_sig_hup = 1;
+ memcpy(&last_sighup_info, si, sizeof(*si));
+ break;
+ case SIGCHLD:
+ break;
}
}
#elif defined(HAVE_SIGNAL) || defined(HAVE_SIGACTION)
@@ -760,7 +775,7 @@ int main (int argc, char **argv) {
setuid(pwd->pw_uid);
}
#endif
-#ifdef HAVE_PRCTL
+#ifdef HAVE_SYS_PRCTL_H
if (srv->srvconf.enable_cores) {
prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
}
@@ -1079,6 +1094,17 @@ int main (int argc, char **argv) {
log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
return -1;
+ } else {
+#ifdef HAVE_SIGACTION
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ "logfiles cycled UID =",
+ last_sigterm_info.si_uid,
+ "PID =",
+ last_sigterm_info.si_pid);
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "logfiles cycled");
+#endif
}
}
@@ -1378,6 +1404,17 @@ int main (int argc, char **argv) {
}
}
+#ifdef HAVE_SIGACTION
+ log_error_write(srv, __FILE__, __LINE__, "sdsd",
+ "server stopped by UID =",
+ last_sigterm_info.si_uid,
+ "PID =",
+ last_sigterm_info.si_pid);
+#else
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "server stopped");
+#endif
+
/* clean-up */
log_error_close(srv);
network_close(srv);
diff --git a/src/spawn-fcgi.c b/src/spawn-fcgi.c
index 0aaac14..8237e79 100644
--- a/src/spawn-fcgi.c
+++ b/src/spawn-fcgi.c
@@ -25,10 +25,6 @@
#define FCGI_LISTENSOCK_FILENO 0
-#ifndef UNIX_PATH_MAX
-# define UNIX_PATH_MAX 108
-#endif
-
#include "sys-socket.h"
#ifdef HAVE_SYS_WAIT_H
@@ -273,6 +269,8 @@ int main(int argc, char **argv) {
int i_am_root, o;
int pid_fd = -1;
int nofork = 0;
+ struct sockaddr_un un;
+ const size_t sun_path_len = sizeof(un.sun_path);
i_am_root = (getuid() == 0);
@@ -309,7 +307,7 @@ int main(int argc, char **argv) {
return -1;
}
- if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
+ if (unixsocket && strlen(unixsocket) > sun_path_len - 1) {
fprintf(stderr, "%s.%d: %s\n",
__FILE__, __LINE__,
"path of the unix socket is too long\n");
diff --git a/src/stat_cache.c b/src/stat_cache.c
index 6fbf1ba..9325693 100644
--- a/src/stat_cache.c
+++ b/src/stat_cache.c
@@ -635,9 +635,10 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_
if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
fam_dir->req, fam_dir)) {
- log_error_write(srv, __FILE__, __LINE__, "sbs",
+ log_error_write(srv, __FILE__, __LINE__, "sbsbs",
"monitoring dir failed:",
- fam_dir->name,
+ fam_dir->name,
+ "file:", name,
FamErrlist[FAMErrno]);
fam_dir_entry_free(fam_dir);
diff --git a/tests/404-handler.conf b/tests/404-handler.conf
new file mode 100644
index 0000000..65f2e5e
--- /dev/null
+++ b/tests/404-handler.conf
@@ -0,0 +1,49 @@
+debug.log-request-handling = "enable"
+debug.log-response-header = "enable"
+debug.log-request-header = "enable"
+
+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.name = "www.example.org"
+server.tag = "Apache 1.3.29"
+
+
+server.modules = (
+ "mod_fastcgi",
+ "mod_cgi",
+ "mod_accesslog" )
+
+######################## MODULE CONFIG ############################
+
+
+accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
+
+mimetype.assign = ( ".html" => "text/html" )
+
+cgi.assign = (".pl" => "/usr/bin/perl" )
+
+# fastcgi.server += ( "/404.pl" =>
+# ( "404-handler" =>
+# (
+# "socket" => env.SRCDIR + "/tmp/pl-404-fastcgi-1.socket",
+# "bin-path" => server.document-root + "/404.pl",
+# "max-procs" => 1,
+# "check-local" => "disable",
+# "broken-scriptfilename" => "enable",
+# )
+# ),
+# )
+
+$HTTP["url"] =~ "^/static/" {
+ server.error-handler-404 = "/404.html"
+}
+else $HTTP["url"] =~ "." {
+ server.error-handler-404 = "/404.pl"
+}
diff --git a/tests/LightyTest.pm b/tests/LightyTest.pm
index 0426d45..33eca61 100755
--- a/tests/LightyTest.pm
+++ b/tests/LightyTest.pm
@@ -235,9 +235,7 @@ sub handle_http {
diag(sprintf("body failed: expected '%s', got '%s'\n", $href->{'HTTP-Content'}, $resp_body));
return -1;
}
- }
-
- if (defined $href->{'-HTTP-Content'}) {
+ } elsif (defined $href->{'-HTTP-Content'}) {
if (defined $resp_body && $resp_body ne '') {
diag(sprintf("body failed: expected empty body, got '%s'\n", $resp_body));
return -1;
@@ -245,6 +243,7 @@ sub handle_http {
}
foreach (keys %{ $href }) {
+ ## filter special keys
next if $_ eq 'HTTP-Protocol';
next if $_ eq 'HTTP-Status';
next if $_ eq 'HTTP-Content';
@@ -252,20 +251,33 @@ sub handle_http {
(my $k = $_) =~ tr/[A-Z]/[a-z]/;
- my $no_val = 0;
+ my $verify_value = 1;
+ my $key_inverted = 0;
if (substr($k, 0, 1) eq '+') {
+ ## the key has to exist, but the value is ignored
$k = substr($k, 1);
- $no_val = 1;
-
+ $verify_value = 0;
+ } elsif (substr($k, 0, 1) eq '-') {
+ ## the key should NOT exist
+ $k = substr($k, 1);
+ $key_inverted = 1;
+ $verify_value = 0; ## skip the value check
}
- if (!defined $resp_hdr{$k}) {
- diag(sprintf("required header '%s' is missing\n", $k));
- return -1;
+ if ($key_inverted) {
+ if (defined $resp_hdr{$k}) {
+ diag(sprintf("required header '%s' is missing\n", $k));
+ return -1;
+ }
+ } else {
+ if (not defined $resp_hdr{$k}) {
+ diag(sprintf("required header '%s' is missing\n", $k));
+ return -1;
+ }
}
- if ($no_val == 0) {
+ if ($verify_value) {
if ($href->{$_} =~ /^\/(.+)\/$/) {
if ($resp_hdr{$k} !~ /$1/) {
diag(sprintf("response-header failed: expected '%s', got '%s', regex: %s\n",
diff --git a/tests/Makefile.am b/tests/Makefile.am
index c83026a..dfdf06b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -45,7 +45,9 @@ CONFS=fastcgi-10.conf \
mod-setenv.t \
lowercase.t \
lowercase.conf \
- cachable.t
+ cachable.t \
+ core-404-handler.t \
+ 404-handler.conf
TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir)
diff --git a/tests/Makefile.in b/tests/Makefile.in
index 5268cd9..429efd1 100644
--- a/tests/Makefile.in
+++ b/tests/Makefile.in
@@ -258,7 +258,9 @@ CONFS = fastcgi-10.conf \
mod-setenv.t \
lowercase.t \
lowercase.conf \
- cachable.t
+ cachable.t \
+ core-404-handler.t \
+ 404-handler.conf
TESTS_ENVIRONMENT = $(srcdir)/wrapper.sh $(srcdir) $(top_builddir)
EXTRA_DIST = wrapper.sh lighttpd.conf \
diff --git a/tests/cachable.t b/tests/cachable.t
index 9dc1121..0d1e1b4 100755
--- a/tests/cachable.t
+++ b/tests/cachable.t
@@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
-use Test::More tests => 12;
+use Test::More tests => 13;
use LightyTest;
my $tf = LightyTest->new();
@@ -108,5 +108,14 @@ EOF
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-None-Match: $etag
+Host: etag.example.org
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + disabled etags on server side');
+
ok($tf->stop_proc == 0, "Stopping lighttpd");
diff --git a/tests/core-404-handler.t b/tests/core-404-handler.t
new file mode 100644
index 0000000..b9c5df1
--- /dev/null
+++ b/tests/core-404-handler.t
@@ -0,0 +1,76 @@
+#!/usr/bin/env perl
+#
+# combinations we have to test:
+# plain 404 case
+# 404-handler -> static file (verify content)
+# 404-handler -> fastcgi
+# returning 200
+# returning 302 + Location
+# returning 404
+# returning no status -> 200
+#
+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 => 8;
+use LightyTest;
+
+my $tf = LightyTest->new();
+my $t;
+$tf->{CONFIGFILE} = '404-handler.conf';
+
+ok($tf->start_proc == 0, "Starting lighttpd") or die();
+
+$t->{REQUEST} = ( <<EOF
+GET /static/notfound HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "static not found\n" } ];
+ok($tf->handle_http($t) == 0, '404 handler => static');
+
+#
+#
+#
+$t->{REQUEST} = ( <<EOF
+GET /dynamic/200/notfound HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "found here\n" } ];
+ok($tf->handle_http($t) == 0, '404 handler => dynamic(200)');
+
+$t->{REQUEST} = ( <<EOF
+GET /dynamic/302/notfound HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 302, 'Location' => "http://www.example.org/" } ];
+ok($tf->handle_http($t) == 0, '404 handler => dynamic(302)');
+
+$t->{REQUEST} = ( <<EOF
+GET /dynamic/404/notfound HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'HTTP-Content' => "Not found here\n" } ];
+ok($tf->handle_http($t) == 0, '404 handler => dynamic(404)');
+
+$t->{REQUEST} = ( <<EOF
+GET /dynamic/nostatus/notfound HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => "found here\n" } ];
+ok($tf->handle_http($t) == 0, '404 handler => dynamic(nostatus)');
+
+$t->{REQUEST} = ( <<EOF
+GET /send404.pl HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'HTTP-Content' => "send404\n" } ];
+ok($tf->handle_http($t) == 0, '404 generated by CGI should stay 404');
+
+ok($tf->stop_proc == 0, "Stopping lighttpd");
+
diff --git a/tests/docroot/www/404.fcgi b/tests/docroot/www/404.fcgi
new file mode 100755
index 0000000..468089f
--- /dev/null
+++ b/tests/docroot/www/404.fcgi
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+#use CGI qw/:standard/;
+use CGI::Fast qw(:standard);
+my $cgi = new CGI;
+while (new CGI::Fast) {
+ my $request_uri = $ENV{'REQUEST_URI'};
+ print (STDERR "REQUEST_URI: $request_uri\n");
+ if ($request_uri =~ m/^\/dynamic\/200\// ) {
+ print header ( -status => 200,
+ -type => 'text/plain' );
+ print ("found here\n");
+ }
+ elsif ($request_uri =~ m|^/dynamic/302/| ) {
+ print header( -status=>302,
+ -location => 'http://www.example.org/');
+ }
+ elsif ($request_uri =~ m/^\/dynamic\/404\// ) {
+ print header ( -status => 404
+ -type => 'text/plain' );
+ print ("Not found here\n");
+ }
+ else {
+ print header ( -status => 500,
+ -type => 'text/plain');
+ print ("huh\n");
+ };
+};
diff --git a/tests/docroot/www/404.html b/tests/docroot/www/404.html
new file mode 100644
index 0000000..ce72e89
--- /dev/null
+++ b/tests/docroot/www/404.html
@@ -0,0 +1 @@
+static not found
diff --git a/tests/docroot/www/404.pl b/tests/docroot/www/404.pl
new file mode 100755
index 0000000..0f743d0
--- /dev/null
+++ b/tests/docroot/www/404.pl
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+use CGI qw/:standard/;
+my $cgi = new CGI;
+my $request_uri = $ENV{'REQUEST_URI'};
+print (STDERR "REQUEST_URI: $request_uri\n");
+
+if ($request_uri =~ m/^\/dynamic\/200\// ) {
+ print header ( -status => 200,
+ -type => 'text/plain' );
+ print ("found here\n");
+}
+elsif ($request_uri =~ m|^/dynamic/302/| ) {
+ print header( -status=>302,
+ -location => 'http://www.example.org/');
+}
+elsif ($request_uri =~ m/^\/dynamic\/404\// ) {
+ print header ( -status => 404
+ -type => 'text/plain' );
+ print ("Not found here\n");
+}
+elsif ($request_uri =~ m/^\/send404\.pl/ ) {
+ print header ( -status => 404
+ -type => 'text/plain' );
+ print ("Not found here (send404)\n");
+}
+elsif ($request_uri =~ m/^\/dynamic\/nostatus\// ) {
+ print ("found here\n");
+}
+else {
+ print header ( -status => 500,
+ -type => 'text/plain');
+ print ("huh\n");
+};
diff --git a/tests/docroot/www/Makefile.am b/tests/docroot/www/Makefile.am
index bcbd39c..7c8aa55 100644
--- a/tests/docroot/www/Makefile.am
+++ b/tests/docroot/www/Makefile.am
@@ -1,5 +1,5 @@
EXTRA_DIST=cgi.php cgi.pl dummydir index.html index.txt phpinfo.php \
redirect.php cgi-pathinfo.pl get-env.php get-server-env.php \
nph-status.pl prefix.fcgi get-header.pl ssi.shtml get-post-len.pl \
- exec-date.shtml index.html~
+ exec-date.shtml index.html~ 404.fcgi 404.html 404.pl send404.pl crlfcrash.pl
SUBDIRS=go indexfile expire
diff --git a/tests/docroot/www/Makefile.in b/tests/docroot/www/Makefile.in
index 393c611..7597926 100644
--- a/tests/docroot/www/Makefile.in
+++ b/tests/docroot/www/Makefile.in
@@ -196,7 +196,7 @@ top_srcdir = @top_srcdir@
EXTRA_DIST = cgi.php cgi.pl dummydir index.html index.txt phpinfo.php \
redirect.php cgi-pathinfo.pl get-env.php get-server-env.php \
nph-status.pl prefix.fcgi get-header.pl ssi.shtml get-post-len.pl \
- exec-date.shtml index.html~
+ exec-date.shtml index.html~ 404.fcgi 404.html 404.pl send404.pl crlfcrash.pl
SUBDIRS = go indexfile expire
all: all-recursive
diff --git a/tests/docroot/www/crlfcrash.pl b/tests/docroot/www/crlfcrash.pl
new file mode 100644
index 0000000..f90bc86
--- /dev/null
+++ b/tests/docroot/www/crlfcrash.pl
@@ -0,0 +1,4 @@
+#!/usr/bin/env perl
+#
+print "Location: http://www.example.org/\r\n\n\n";
+exit;
diff --git a/tests/docroot/www/nph-status.pl b/tests/docroot/www/nph-status.pl
index 528791b..d817c7f 100755
--- a/tests/docroot/www/nph-status.pl
+++ b/tests/docroot/www/nph-status.pl
@@ -1,4 +1,10 @@
#!/usr/bin/perl
-print "HTTP/1.0 30 FooBar\r\n";
+my $status = 200;
+
+if (defined $ENV{"QUERY_STRING"}) {
+ $status = $ENV{"QUERY_STRING"};
+}
+
+print "HTTP/1.0 ".$status." FooBar\r\n";
print "\r\n";
diff --git a/tests/docroot/www/send404.pl b/tests/docroot/www/send404.pl
new file mode 100755
index 0000000..a92dfa6
--- /dev/null
+++ b/tests/docroot/www/send404.pl
@@ -0,0 +1,5 @@
+#!/usr/bin/perl
+use CGI qw/:standard/;
+print header ( -status => 404
+ -type => 'text/plain' );
+print ("send404\n");
diff --git a/tests/fastcgi-13.conf b/tests/fastcgi-13.conf
index c4adf62..6ef0386 100644
--- a/tests/fastcgi-13.conf
+++ b/tests/fastcgi-13.conf
@@ -85,7 +85,7 @@ fastcgi.server = ( ".php" => (
"grisu" => (
"host" => "127.0.0.1",
"port" => 1048,
- "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
+ "bin-path" => "/usr/bin/php-cgi",
"bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
)
)
diff --git a/tests/lighttpd.conf b/tests/lighttpd.conf
index 878cb1f..71a37fe 100644
--- a/tests/lighttpd.conf
+++ b/tests/lighttpd.conf
@@ -1,4 +1,6 @@
debug.log-request-handling = "enable"
+debug.log-request-header = "enable"
+debug.log-response-header = "enable"
debug.log-condition-handling = "enable"
server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
@@ -214,3 +216,6 @@ $HTTP["cookie"] =~ "empty-ref" {
}
+$HTTP["host"] == "etag.example.org" {
+ static-file.etags = "disable"
+}
diff --git a/tests/mod-cgi.t b/tests/mod-cgi.t
index a42bcd5..b89a1af 100755
--- a/tests/mod-cgi.t
+++ b/tests/mod-cgi.t
@@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
-use Test::More tests => 15;
+use Test::More tests => 18;
use LightyTest;
my $tf = LightyTest->new();
@@ -40,11 +40,25 @@ $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-
ok($tf->handle_http($t) == 0, 'perl via cgi + pathinfo');
$t->{REQUEST} = ( <<EOF
-GET /nph-status.pl HTTP/1.0
+GET /nph-status.pl?30 HTTP/1.0
EOF
);
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
-ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
+ok($tf->handle_http($t) == 0, 'NPH + perl, invalid status-code (#14)');
+
+$t->{REQUEST} = ( <<EOF
+GET /nph-status.pl?304 HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
+ok($tf->handle_http($t) == 0, 'NPH + perl, setting status-code (#1125)');
+
+$t->{REQUEST} = ( <<EOF
+GET /nph-status.pl?200 HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'NPH + perl, setting status-code');
$t->{REQUEST} = ( <<EOF
GET /get-header.pl?GATEWAY_INTERFACE HTTP/1.0
@@ -116,5 +130,13 @@ EOF
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.1', 'HTTP-Status' => 200, '+Content-Length' => '' } ];
ok($tf->handle_http($t) == 0, 'cgi-env: HTTP_HOST');
+# broken header crash
+$t->{REQUEST} = ( <<EOF
+GET /crlfcrash.pl HTTP/1.0
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 302, 'Location' => 'http://www.example.org/' } ];
+ok($tf->handle_http($t) == 0, 'broken header via perl cgi');
+
ok($tf->stop_proc == 0, "Stopping lighttpd");
diff --git a/tests/mod-fastcgi.t b/tests/mod-fastcgi.t
index 291bf69..2c1dedb 100755
--- a/tests/mod-fastcgi.t
+++ b/tests/mod-fastcgi.t
@@ -7,7 +7,7 @@ BEGIN {
}
use strict;
-use Test::More tests => 47;
+use Test::More tests => 46;
use LightyTest;
my $tf = LightyTest->new();
@@ -15,7 +15,7 @@ my $tf = LightyTest->new();
my $t;
SKIP: {
- skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
+ skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
ok($tf->start_proc == 0, "Starting lighttpd") or die();
@@ -60,7 +60,7 @@ EOF
ok($tf->handle_http($t) == 0, '$_SERVER["PHP_SELF"]');
$t->{REQUEST} = ( <<EOF
-GET /get-server-env.php/foo?env=PHP_SELF HTTP/1.0
+GET /get-server-env.php/foo?env=SCRIPT_NAME HTTP/1.0
Host: www.example.org
EOF
);
@@ -223,7 +223,7 @@ EOF
}
SKIP: {
- skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php";
+ skip "no php found", 4 unless -x "/usr/bin/php-cgi";
$tf->{CONFIGFILE} = 'fastcgi-13.conf';
ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
$t->{REQUEST} = ( <<EOF
diff --git a/tests/request.t b/tests/request.t
index 64e48cc..c153b21 100755
--- a/tests/request.t
+++ b/tests/request.t
@@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
-use Test::More tests => 34;
+use Test::More tests => 41;
use LightyTest;
my $tf = LightyTest->new();
@@ -338,15 +338,56 @@ EOF
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
ok($tf->handle_http($t) == 0, 'HEAD with Content-Length');
-
$t->{REQUEST} = ( <<EOF
-GET / HTTP/1.0
-If-Modified-Since: Sun, 1970 Jan 01 00:00:01 GMT
-If-Modified-Since: Sun, 1970 Jan 01 00:00:01 GMT
+GET /index.html HTTP/1.0
+If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
+If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
EOF
);
-$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
ok($tf->handle_http($t) == 0, 'Duplicate If-Mod-Since, with equal timestamps');
+$t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: \0\r\n\r\n" );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
+ok($tf->handle_http($t) == 0, 'invalid chars in Header values (bug #1286)');
+
+$t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: \r\n\r\n" );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'empty If-Modified-Since');
+
+$t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: foobar\r\n\r\n" );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'broken If-Modified-Since');
+
+$t->{REQUEST} = ( "GET / HTTP/1.0\r\nIf-Modified-Since: this string is too long to be a valid timestamp\r\n\r\n" );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'broken If-Modified-Since');
+
+
+$t->{REQUEST} = ( <<EOF
+GET /index.html HTTP/1.0
+If-Modified-Since2: Sun, 01 Jan 2036 00:00:03 GMT
+If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
+ok($tf->handle_http($t) == 0, 'Similar Headers (bug #1287)');
+
+$t->{REQUEST} = ( <<EOF
+GET /index.html HTTP/1.0
+If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, 'Content-Type' => 'text/html' } ];
+ok($tf->handle_http($t) == 0, 'If-Modified-Since');
+
+$t->{REQUEST} = ( <<EOF
+GET /index.html HTTP/1.0
+If-Modified-Since: Sun, 01 Jan 2036 00:00:02 GMT
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, '-Content-Length' => '' } ];
+ok($tf->handle_http($t) == 0, 'Status 304 has no Content-Length (#1002)');
+
ok($tf->stop_proc == 0, "Stopping lighttpd");