From ec0b51649cd99420792df2352b02dc949f8f293b Mon Sep 17 00:00:00 2001 From: Arno Töll Date: Wed, 21 Nov 2012 23:03:49 +0100 Subject: Imported Upstream version 1.4.17 --- Makefile.in | 3 +- NEWS | 30 ++++++- aclocal.m4 | 34 +++++++ compile | 142 +++++++++++++++++++++++++++++ config.h.in | 3 + configure | 192 +++++++++++++++++++++++++++++++++------- configure.in | 3 +- cygwin/lighttpd.README | 10 +-- doc/lighttpd.conf | 35 ++++---- lighttpd.spec | 2 +- openwrt/control | 4 +- openwrt/lighttpd.mk | 2 +- src/array.h | 4 +- src/base.h | 4 + src/buffer.c | 13 ++- src/buffer.h | 2 +- src/configfile-glue.c | 84 +++++++++++++++--- src/configfile.c | 2 + src/configfile.h | 6 ++ src/connections.c | 113 ++++++++++++----------- src/etag.c | 6 +- src/http-header-glue.c | 14 ++- src/http_auth.c | 4 +- src/log.c | 4 - src/mod_alias.c | 2 + src/mod_auth.c | 39 -------- src/mod_cgi.c | 149 +++++++++++++++++++------------ src/mod_compress.c | 7 ++ src/mod_dirlisting.c | 22 +++-- src/mod_extforward.c | 69 +++++---------- src/mod_fastcgi.c | 14 ++- src/mod_mysql_vhost.c | 8 +- src/mod_proxy.c | 2 +- src/mod_scgi.c | 14 ++- src/mod_ssi.c | 4 +- src/mod_staticfile.c | 1 + src/mod_status.c | 7 +- src/mod_usertrack.c | 4 +- src/network_freebsd_sendfile.c | 45 +++++++--- src/request.c | 16 +++- src/server.c | 57 +++++++++--- src/spawn-fcgi.c | 8 +- src/stat_cache.c | 5 +- tests/404-handler.conf | 49 ++++++++++ tests/LightyTest.pm | 32 ++++--- tests/Makefile.am | 4 +- tests/Makefile.in | 4 +- tests/cachable.t | 11 ++- tests/core-404-handler.t | 76 ++++++++++++++++ tests/docroot/www/404.fcgi | 27 ++++++ tests/docroot/www/404.html | 1 + tests/docroot/www/404.pl | 33 +++++++ tests/docroot/www/Makefile.am | 2 +- tests/docroot/www/Makefile.in | 2 +- tests/docroot/www/crlfcrash.pl | 4 + tests/docroot/www/nph-status.pl | 8 +- tests/docroot/www/send404.pl | 5 ++ tests/fastcgi-13.conf | 2 +- tests/lighttpd.conf | 5 ++ tests/mod-cgi.t | 28 +++++- tests/mod-fastcgi.t | 8 +- tests/request.t | 53 +++++++++-- 62 files changed, 1167 insertions(+), 376 deletions(-) create mode 100755 compile create mode 100644 tests/404-handler.conf create mode 100644 tests/core-404-handler.t create mode 100755 tests/docroot/www/404.fcgi create mode 100644 tests/docroot/www/404.html create mode 100755 tests/docroot/www/404.pl create mode 100644 tests/docroot/www/crlfcrash.pl create mode 100755 tests/docroot/www/send404.pl 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 . +# +# 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 or send patches to +# . + +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 . +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 . # @@ -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 < conftest.$ac_ext <&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 ." _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--src.tar.bz2 + unpack lighttpd-1.4.17--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-.sh all + ./lighttpd-1.4.17-.sh all This will create: - /usr/src/lighttpd-1.4.16-.tar.bz2 - /usr/src/lighttpd-1.4.16--src.tar.bz2 + /usr/src/lighttpd-1.4.17-.tar.bz2 + /usr/src/lighttpd-1.4.17--src.tar.bz2 -Or use './lighttpd-1.4.16-.sh prep' to get a patched source directory +Or use './lighttpd-1.4.17-.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: .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 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 -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 +#include #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: ": \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 "
" ); - 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 #include #include @@ -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 gmail 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 #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 #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} = ( <{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} = ( <{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} = ( <{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} = ( <{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} = ( <{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} = ( <{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} = ( <{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} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; +ok($tf->handle_http($t) == 0, 'NPH + perl, setting status-code (#1125)'); + +$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'NPH + perl, setting status-code'); $t->{REQUEST} = ( <{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} = ( <{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} = ( <{CONFIGFILE} = 'fastcgi-13.conf'; ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die(); $t->{REQUEST} = ( < 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} = ( <{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} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ]; +ok($tf->handle_http($t) == 0, 'Similar Headers (bug #1287)'); + +$t->{REQUEST} = ( <{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304, 'Content-Type' => 'text/html' } ]; +ok($tf->handle_http($t) == 0, 'If-Modified-Since'); + +$t->{REQUEST} = ( <{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"); -- cgit v1.2.3