diff options
78 files changed, 2049 insertions, 650 deletions
diff --git a/Makefile.am b/Makefile.am index 3ed6331..252cbfe 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,3 @@ SUBDIRS=src doc tests cygwin openwrt -EXTRA_DIST=lighttpd.spec +EXTRA_DIST=lighttpd.spec autogen.sh SConstruct diff --git a/Makefile.in b/Makefile.in index b50af37..a9b2eea 100644 --- a/Makefile.in +++ b/Makefile.in @@ -211,7 +211,7 @@ target_vendor = @target_vendor@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = src doc tests cygwin openwrt -EXTRA_DIST = lighttpd.spec +EXTRA_DIST = lighttpd.spec autogen.sh SConstruct all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -3,6 +3,55 @@ NEWS ==== +- 1.4.19 - + + * added support for If-Range: <date> (#1346) + * added support for matching $HTTP["scheme"] in configs + * fixed initgroups() called after chroot (#1384) + * fixed case-sensitive check for Auth-Method (#1456) + * execute fcgi app without /bin/sh if used as argument to spawn-fcgi (#1428) + * fixed a bug that made /-prefixed extensions being handled also when + matching the end of the uri in fcgi,scgi and proxy modules (#1489) + * print error if X-LIGHTTPD-send-file cannot be done; reset header + Content-Length for send-file. Patches by Stefan Buehler + * prevent crash in certain php-fcgi configurations (#841) + * add IdleServers and Scoreboard directives in ?auto mode for mod_status (#1507) + * open log immediately after daemonizing, fixes SIGPIPEs on startup (#165) + * HTTPS env var should be "on" when using mod_extforward and the X-Forwarded-Proto header is set. (#1499) + * generate ETag and Last-Modified headers for mod_ssi based on newest modified include (#1491) + * support letterhomes in mod_userdir (#1473) + * support chained proxies in mod_extforward (#1528) + * fixed bogus "cgi died ?" if we kill the CGI process on shutdown + * fixed ECONNRESET handling in network-openssl + * fixed handling of EAGAIN in network-linux-sendfile (#657) + * reset conditional cache (#1164) + * create directories in mod_compress (was broken with alias/userdir) (#1027) + * fixed out of range access in fd array (#1562, #372) (CVE-2008-0983) + * mod_compress should check if the request is already handled, e.g. by fastcgi (#1565) + * remove broken workaround for buggy Opera version with ssl/chunked encoding (#285) + * generate etag/last-modified header for on-the-fly-compressed files (#1171) + * req-method OPTIONS: do not insert default response if request was denied, do not deny OPTIONS by default (#1324) + * fixed memory leak on windows (#1347) + * fixed building outside of the src dir (#1349) + * fixed including of stdint.h/inttypes.h in etag.c (#1413) + * do not add Accept-Ranges header if range-request is disabled (#1449) + * log the ip of failed auth tries in error.log (enhancement #1544) + * fixed RoundRobin in mod_proxy (#516) + * check for symlinks after successful pathinfo matching (#1574) + * fixed mod-proxy.t to run with a builddir outside of the src dir + * do not suppress content on "307 Temporary Redirect" (#1412) + * fixed Content-Length header if response body gets removed in connections.c (#1412, part 2) + * do not generate a "Content-Length: 0" header for HEAD requests, added test too + * remove compress cache file if compression or write failed (#1150) + * fixed body handling of status 300 requests + * spawn-fcgi: only try to connect to unix socket (not tcp) before spawning (#1575) + * fix sending source of cgi script instead of 500 error if fork fails (CVE-2008-1111) + * fix min-procs handling in mod_scgi.c, just set to max-procs (patch from #623) + * fix sending "408 - Timeout" instead of "410 - Gone" for timedout urls in mod_secdownload (#1440) + * workaround #1587: require userdir.path to be set to enable mod_userdir (empty string allowed) (CVE-2008-1270) + * make configure checks for --with-pcre, --with-zlib and --with-bzip2 failing if the headers aren't found + * fixed handling of waitpid() == EINTR mod_ssi on solaris + - 1.4.18 - 2007-09-09 * fixed compile error on IRIX 6.5.x on prctl() (#1333) diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..04eb15a --- /dev/null +++ b/SConstruct @@ -0,0 +1,277 @@ +import os +import sys +import re +import string +from stat import * + +package = 'lighttpd' +version = '1.4.19' + +def checkCHeaders(autoconf, hdrs): + p = re.compile('[^A-Z0-9]') + for hdr in hdrs: + if not hdr: + continue + _hdr = Split(hdr) + if autoconf.CheckCHeader(_hdr): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_' + p.sub('_', _hdr[-1].upper()) ]) + +def checkFuncs(autoconf, funcs): + p = re.compile('[^A-Z0-9]') + for func in funcs: + if autoconf.CheckFunc(func): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_' + p.sub('_', func.upper()) ]) + +def checkTypes(autoconf, types): + p = re.compile('[^A-Z0-9]') + for type in types: + if autoconf.CheckType(type, '#include <sys/types.h>'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_' + p.sub('_', type.upper()) ]) + +def checkProgram(env, withname, progname): + withname = 'with_' + withname + binpath = None + + if env[withname] != 1: + binpath = env[withname] + else: + prog = env.Detect(progname) + if prog: + binpath = env.WhereIs(prog) + + if binpath: + mode = os.stat(binpath)[ST_MODE] + if S_ISDIR(mode): + print >> sys.stderr, "* error: path `%s' is a directory" % (binpath) + env.Exit(-1) + if not S_ISREG(mode): + print >> sys.stderr, "* error: path `%s' is not a file or not exists" % (binpath) + env.Exit(-1) + + if not binpath: + print >> sys.stderr, "* error: can't find program `%s'" % (progname) + env.Exit(-1) + + return binpath + +def checkStructMember(context): + struct_member = """ +#include <time.h> +int main() { + struct tm a; + a.tm_gmtoff = 0; + return 0; +} +""" + context.Message('Checking for tm_gmtoff in struct tm...') + result = context.TryLink(struct_member, '.c') + context.Result(result) + + return result + + +BuildDir('build', 'src', duplicate = 0) + +opts = Options('config.py') +opts.AddOptions( + ('prefix', 'prefix', '/usr/local'), + ('bindir', 'binary directory', '${prefix}/bin'), + ('sbindir', 'binary directory', '${prefix}/sbin'), + ('libdir', 'library directory', '${prefix}/lib'), + PackageOption('with_mysql', 'enable mysql support', 'no'), + PackageOption('with_xml', 'enable xml support', 'no'), + PackageOption('with_pcre', 'enable pcre support', 'yes'), + PathOption('CC', 'path to the c-compiler', None), + BoolOption('build_dynamic', 'enable dynamic build', 'yes'), + BoolOption('build_static', 'enable static build', 'no'), + BoolOption('build_fullstatic', 'enable fullstatic build', 'no'), + BoolOption('with_sqlite3', 'enable sqlite3 support', 'no'), + BoolOption('with_memcache', 'enable memcache support', 'no'), + BoolOption('with_fam', 'enable FAM/gamin support', 'no'), + BoolOption('with_openssl', 'enable memcache support', 'no'), + BoolOption('with_gzip', 'enable gzip compression', 'no'), + BoolOption('with_bzip2', 'enable bzip2 compression', 'no'), + BoolOption('with_lua', 'enable lua support for mod_cml', 'no'), + BoolOption('with_ldap', 'enable ldap auth support', 'no')) + +env = Environment( + env = os.environ, + options = opts, + CPPPATH = Split('#build') +) + +env.Help(opts.GenerateHelpText(env)) + +if env.subst('${CC}') is not '': + env['CC'] = env.subst('${CC}') + +env['package'] = package +env['version'] = version +if env['CC'] == 'gcc': + ## we need x-open 6 and bsd 4.3 features + env.Append(CCFLAGS = Split('-Wall -O2 -g -W -pedantic -Wunused -Wshadow -std=gnu99')) + +# cache configure checks +if 1: + autoconf = Configure(env, custom_tests = {'CheckStructMember': checkStructMember }) + autoconf.headerfile = "foo.h" + checkCHeaders(autoconf, string.split(""" + arpa/inet.h + fcntl.h + netinet/in.h + sys/types.h netinet/in.h + stdlib.h + string.h + sys/socket.h + sys/types.h sys/socket.h + sys/time.h + unistd.h + sys/sendfile.h + sys/uio.h + sys/types.h sys/uio.h + getopt.h + sys/epoll.h + sys/select.h + sys/types.h sys/select.h + poll.h + sys/poll.h + sys/devpoll.h + sys/filio.h + sys/mman.h + sys/types.h sys/mman.h + sys/event.h + sys/types.h sys/event.h + sys/port.h + winsock2.h + pwd.h + sys/syslimits.h + sys/resource.h + sys/time.h sys/types.h sys/resource.h + sys/un.h + sys/types.h sys/un.h + syslog.h + stdint.h + inttypes.h + sys/prctl.h + sys/wait.h""", "\n")) + + checkFuncs(autoconf, Split('fork stat lstat strftime dup2 getcwd inet_ntoa inet_ntop memset mmap munmap strchr \ + strdup strerror strstr strtol sendfile getopt socket \ + gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot \ + getuid select signal pathconf madvise prctl\ + writev sigaction sendfile64 send_file kqueue port_create localtime_r posix_fadvise')) + + checkTypes(autoconf, Split('pid_t size_t off_t')) + + autoconf.env.Append( LIBSQLITE3 = '', LIBXML2 = '', LIBMYSQL = '', LIBZ = '', + LIBBZ2 = '', LIBCRYPT = '', LIBMEMCACHE = '', LIBFCGI = '', LIBPCRE = '', + LIBLDAP = '', LIBLBER = '', LIBLUA = '', LIBLUALIB = '', LIBDL = '') + + if env['with_fam']: + if autoconf.CheckLibWithHeader('fam', 'fam.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_FAM_H', '-DHAVE_LIBFAM' ], LIBS = 'fam') + checkFuncs(autoconf, ['FAMNoExists']); + + + if autoconf.CheckLibWithHeader('crypt', 'crypt.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_CRYPT_H', '-DHAVE_LIBCRYPT' ], LIBCRYPT = 'crypt') + + if autoconf.CheckLibWithHeader('uuid', 'uuid/uuid.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_UUID_UUID_H', '-DHAVE_LIBUUID' ], LIBUUID = 'uuid') + + if env['with_openssl']: + if autoconf.CheckLibWithHeader('ssl', 'openssl/ssl.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_OPENSSL_SSL_H', '-DHAVE_LIBSSL'] , LIBS = [ 'ssl', 'crypto' ]) + + if env['with_gzip']: + if autoconf.CheckLibWithHeader('z', 'zlib.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_ZLIB_H', '-DHAVE_LIBZ' ], LIBZ = 'z') + + if env['with_ldap']: + if autoconf.CheckLibWithHeader('ldap', 'ldap.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_LDAP_H', '-DHAVE_LIBLDAP' ], LIBLDAP = 'ldap') + if autoconf.CheckLibWithHeader('lber', 'lber.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_LBER_H', '-DHAVE_LIBLBER' ], LIBLBER = 'lber') + + if env['with_bzip2']: + if autoconf.CheckLibWithHeader('bz2', 'bzlib.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_BZLIB_H', '-DHAVE_LIBBZ2' ], LIBBZ2 = 'bz2') + + if env['with_memcache']: + if autoconf.CheckLibWithHeader('memcache', 'memcache.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_MEMCACHE_H', '-DHAVE_LIBMEMCACHE' ], LIBMEMCACHE = 'memcache') + + if env['with_sqlite3']: + if autoconf.CheckLibWithHeader('sqlite3', 'sqlite3.h', 'C'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_SQLITE3_H', '-DHAVE_LIBSQLITE3' ], LIBSQLITE3 = 'sqlite3') + + ol = env['LIBS'] + if autoconf.CheckLibWithHeader('fcgi', 'fastcgi.h', 'C'): + autoconf.env.Append(LIBFCGI = 'fcgi') + env['LIBS'] = ol + + ol = env['LIBS'] + if autoconf.CheckLibWithHeader('dl', 'dlfcn.h', 'C'): + autoconf.env.Append(LIBDL = 'dl') + env['LIBS'] = ol + + if autoconf.CheckType('socklen_t', '#include <unistd.h>\n#include <sys/socket.h>\n#include <sys/types.h>'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_SOCKLEN_T' ]) + + if autoconf.CheckType('struct sockaddr_storage', '#include <sys/socket.h>\n'): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_STRUCT_SOCKADDR_STORAGE' ]) + + if autoconf.CheckStructMember(): + autoconf.env.Append(CPPFLAGS = [ '-DHAVE_STRUCT_TM_GMTOFF' ]) + + env = autoconf.Finish() + + if env['with_lua']: + oldlibs = env['LIBS'] + env.ParseConfig("pkg-config 'lua >= 5.0' --cflags --libs") + lualibs = env['LIBS'][len(oldlibs):] + env.Append(LIBLUA = lualibs) + env.Append(CPPFLAGS = [ '-DHAVE_LUA_H' ]) + env['LIBS'] = oldlibs + + +if env['with_pcre']: + pcre_config = checkProgram(env, 'pcre', 'pcre-config') + env.ParseConfig(pcre_config + ' --cflags --libs') + env.Append(CPPFLAGS = [ '-DHAVE_PCRE_H', '-DHAVE_LIBPCRE' ], LIBPCRE = 'pcre') + +if env['with_xml']: + xml2_config = checkProgram(env, 'xml', 'xml2-config') + oldlib = env['LIBS'] + env['LIBS'] = [] + env.ParseConfig(xml2_config + ' --cflags --libs') + env.Append(CPPFLAGS = [ '-DHAVE_LIBXML_H', '-DHAVE_LIBXML2' ], LIBXML2 = env['LIBS']) + env['LIBS'] = oldlib + +if env['with_mysql']: + mysql_config = checkProgram(env, 'mysql', 'mysql_config') + oldlib = env['LIBS'] + env['LIBS'] = [] + env.ParseConfig(mysql_config + ' --cflags --libs') + env.Append(CPPFLAGS = [ '-DHAVE_MYSQL_H', '-DHAVE_LIBMYSQL' ], LIBMYSQL = 'mysqlclient') + env['LIBS'] = oldlib + +if re.compile("cygwin|mingw").search(env['PLATFORM']): + env.Append(COMMON_LIB = 'bin') +elif re.compile("darwin|aix").search(env['PLATFORM']): + env.Append(COMMON_LIB = 'lib') +else: + env.Append(COMMON_LIB = False) + +versions = string.split(version, '.') +version_id = int(versions[0]) << 16 | int(versions[1]) << 8 | int(versions[2]) +env.Append(CPPFLAGS = [ + '-DLIGHTTPD_VERSION_ID=' + str(version_id), + '-DPACKAGE_NAME=\\"' + package + '\\"', + '-DPACKAGE_VERSION=\\"' + version + '\\"', + '-DLIBRARY_DIR="\\"${libdir}\\""', + '-D_FILE_OFFSET_BITS=64', '-D_LARGEFILE_SOURCE', '-D_LARGE_FILES' + ] ) + +SConscript( 'src/SConscript', 'env', build_dir = 'build', duplicate = 0) +SConscript( 'tests/SConscript', 'env' ) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..ae2d948 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +LIBTOOLIZE=${LIBTOOLIZE:-libtoolize} +LIBTOOLIZE_FLAGS="--copy --force" +ACLOCAL=${ACLOCAL:-aclocal} +AUTOHEADER=${AUTOHEADER:-autoheader} +AUTOMAKE=${AUTOMAKE:-automake} +AUTOMAKE_FLAGS="--add-missing --copy" +AUTOCONF=${AUTOCONF:-autoconf} + +ARGV0=$0 + +set -e + + +run() { + echo "$ARGV0: running \`$@'" + $@ +} + +run $LIBTOOLIZE $LIBTOOLIZE_FLAGS +run $ACLOCAL $ACLOCAL_FLAGS +run $AUTOHEADER +run $AUTOMAKE $AUTOMAKE_FLAGS +run $AUTOCONF +echo "Now type './configure ...' and 'make' to compile." @@ -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.18. +# Generated by GNU Autoconf 2.61 for lighttpd 1.4.19. # # 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.18' -PACKAGE_STRING='lighttpd 1.4.18' +PACKAGE_VERSION='1.4.19' +PACKAGE_STRING='lighttpd 1.4.19' 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.18 to adapt to many kinds of systems. +\`configure' configures lighttpd 1.4.19 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.18:";; + short | recursive ) echo "Configuration of lighttpd 1.4.19:";; esac cat <<\_ACEOF @@ -1548,6 +1548,7 @@ Optional Packages: --with-openssl-libs=DIR OpenSSL libraries --with-kerberos5 use Kerberos5 support with OpenSSL --with-pcre Enable pcre support (default yes) + --with-zlib Enable zlib support for mod_compress --with-bzip2 Enable bzip2 support for mod_compress --with-fam fam/gamin for reducing number of stat() calls --with-webdav-props properties in mod_webdav @@ -1645,7 +1646,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -lighttpd configure 1.4.18 +lighttpd configure 1.4.19 generated by GNU Autoconf 2.61 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, @@ -1659,7 +1660,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.18, which was +It was created by lighttpd $as_me 1.4.19, which was generated by GNU Autoconf 2.61. Invocation command line was $ $0 $@ @@ -2478,7 +2479,7 @@ fi # Define the identity of the package. PACKAGE='lighttpd' - VERSION='1.4.18' + VERSION='1.4.19' cat >>confdefs.h <<_ACEOF @@ -5668,7 +5669,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 5671 "configure"' > conftest.$ac_ext + echo '#line 5672 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -7925,11 +7926,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:7928: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7929: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7932: \$? = $ac_status" >&5 + echo "$as_me:7933: \$? = $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. @@ -8193,11 +8194,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:8196: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8197: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:8200: \$? = $ac_status" >&5 + echo "$as_me:8201: \$? = $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. @@ -8297,11 +8298,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:8300: $lt_compile\"" >&5) + (eval echo "\"\$as_me:8301: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:8304: \$? = $ac_status" >&5 + echo "$as_me:8305: \$? = $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 @@ -10605,7 +10606,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 10608 "configure" +#line 10609 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -10705,7 +10706,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 10708 "configure" +#line 10709 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -13041,11 +13042,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:13044: $lt_compile\"" >&5) + (eval echo "\"\$as_me:13045: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:13048: \$? = $ac_status" >&5 + echo "$as_me:13049: \$? = $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. @@ -13145,11 +13146,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:13148: $lt_compile\"" >&5) + (eval echo "\"\$as_me:13149: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:13152: \$? = $ac_status" >&5 + echo "$as_me:13153: \$? = $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 @@ -14715,11 +14716,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:14718: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14719: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14722: \$? = $ac_status" >&5 + echo "$as_me:14723: \$? = $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. @@ -14819,11 +14820,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:14822: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14823: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14826: \$? = $ac_status" >&5 + echo "$as_me:14827: \$? = $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 @@ -17017,11 +17018,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:17020: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17021: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:17024: \$? = $ac_status" >&5 + echo "$as_me:17025: \$? = $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. @@ -17285,11 +17286,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:17288: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17289: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:17292: \$? = $ac_status" >&5 + echo "$as_me:17293: \$? = $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. @@ -17389,11 +17390,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:17392: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17393: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:17396: \$? = $ac_status" >&5 + echo "$as_me:17397: \$? = $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 @@ -24239,12 +24240,30 @@ done fi LIBS="$OLDLIBS" + else + { { echo "$as_me:$LINENO: error: pcre-config not found, install the pcre-devel package and build with --without-pcre" >&5 +echo "$as_me: error: pcre-config not found, install the pcre-devel package and build with --without-pcre" >&2;} + { (exit 1); exit 1; }; } fi fi -{ echo "$as_me:$LINENO: checking for deflate in -lz" >&5 +{ echo "$as_me:$LINENO: checking for zlib support" >&5 +echo $ECHO_N "checking for zlib support... $ECHO_C" >&6; } + +# Check whether --with-zlib was given. +if test "${with_zlib+set}" = set; then + withval=$with_zlib; WITH_ZLIB=$withval +else + WITH_ZLIB=yes +fi + +{ echo "$as_me:$LINENO: result: $WITH_ZLIB" >&5 +echo "${ECHO_T}$WITH_ZLIB" >&6; } + +if test "$WITH_ZLIB" != "no"; then + { echo "$as_me:$LINENO: checking for deflate in -lz" >&5 echo $ECHO_N "checking for deflate in -lz... $ECHO_C" >&6; } if test "${ac_cv_lib_z_deflate+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 @@ -24448,13 +24467,13 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF - Z_LIB=-lz + Z_LIB=-lz cat >>confdefs.h <<\_ACEOF #define HAVE_LIBZ 1 _ACEOF - cat >>confdefs.h <<\_ACEOF + cat >>confdefs.h <<\_ACEOF #define HAVE_ZLIB_H 1 _ACEOF @@ -24466,6 +24485,12 @@ done fi + if test x$Z_LIB = x; then + { { echo "$as_me:$LINENO: error: zlib-headers and/or libs where not found, install them or build with --without-zlib" >&5 +echo "$as_me: error: zlib-headers and/or libs where not found, install them or build with --without-zlib" >&2;} + { (exit 1); exit 1; }; } + fi +fi { echo "$as_me:$LINENO: checking for bzip2 support" >&5 @@ -24704,6 +24729,11 @@ done fi + if test x$BZ_LIB = x; then + { { echo "$as_me:$LINENO: error: bzip2-headers and/or libs where not found, install them or build with --without-bzip2" >&5 +echo "$as_me: error: bzip2-headers and/or libs where not found, install them or build with --without-bzip2" >&2;} + { (exit 1); exit 1; }; } + fi fi @@ -25329,6 +25359,12 @@ fi done LIBS=$OLD_LIBS + + if test x$FAM_LIBS = x; then + { { echo "$as_me:$LINENO: error: fam/gamin-headers and/or libs where not found, install them or build with --without-fam" >&5 +echo "$as_me: error: fam/gamin-headers and/or libs where not found, install them or build with --without-fam" >&2;} + { (exit 1); exit 1; }; } + fi fi { echo "$as_me:$LINENO: checking for properties in mod_webdav" >&5 @@ -28619,7 +28655,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.18, which was +This file was extended by lighttpd $as_me 1.4.19, which was generated by GNU Autoconf 2.61. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -28672,7 +28708,7 @@ Report bugs to <bug-autoconf@gnu.org>." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -lighttpd config.status 1.4.18 +lighttpd config.status 1.4.19 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 f9189ac..2dcebac 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.18, jan@kneschke.de) +AC_INIT(lighttpd, 1.4.19, jan@kneschke.de) AC_CONFIG_SRCDIR([src/server.c]) AC_CANONICAL_TARGET @@ -266,18 +266,30 @@ if test "x$cross_compiling" = xno -a "$WITH_PCRE" != "no"; then ]) ]) LIBS="$OLDLIBS" + else + AC_MSG_ERROR([pcre-config not found, install the pcre-devel package and build with --without-pcre]) fi fi AC_SUBST(PCRE_LIB) -AC_CHECK_LIB(z, deflate, [ - AC_CHECK_HEADERS([zlib.h],[ - Z_LIB=-lz - AC_DEFINE([HAVE_LIBZ], [1], [libz]) - AC_DEFINE([HAVE_ZLIB_H], [1]) +AC_MSG_CHECKING(for zlib support) +AC_ARG_WITH(zlib, AC_HELP_STRING([--with-zlib],[Enable zlib support for mod_compress]), + [WITH_ZLIB=$withval],[WITH_ZLIB=yes]) +AC_MSG_RESULT([$WITH_ZLIB]) + +if test "$WITH_ZLIB" != "no"; then + AC_CHECK_LIB(z, deflate, [ + AC_CHECK_HEADERS([zlib.h],[ + Z_LIB=-lz + AC_DEFINE([HAVE_LIBZ], [1], [libz]) + AC_DEFINE([HAVE_ZLIB_H], [1]) + ]) ]) -]) + if test x$Z_LIB = x; then + AC_MSG_ERROR([zlib-headers and/or libs where not found, install them or build with --without-zlib]) + fi +fi AC_SUBST(Z_LIB) AC_MSG_CHECKING(for bzip2 support) @@ -293,6 +305,9 @@ if test "$WITH_BZIP2" != "no"; then AC_DEFINE([HAVE_BZLIB_H], [1]) ]) ]) + if test x$BZ_LIB = x; then + AC_MSG_ERROR([bzip2-headers and/or libs where not found, install them or build with --without-bzip2]) + fi fi AC_SUBST(BZ_LIB) @@ -324,6 +339,10 @@ if test "$WITH_FAM" != "no"; then LIBS=$FAM_LIBS AC_CHECK_FUNCS([FAMNoExists]) LIBS=$OLD_LIBS + + if test x$FAM_LIBS = x; then + AC_MSG_ERROR([fam/gamin-headers and/or libs where not found, install them or build with --without-fam]) + fi fi AC_MSG_CHECKING(for properties in mod_webdav) diff --git a/cygwin/lighttpd.README b/cygwin/lighttpd.README index 8fc9339..812c5c2 100644 --- a/cygwin/lighttpd.README +++ b/cygwin/lighttpd.README @@ -31,17 +31,17 @@ Canonical download: ------------------------------------ Build instructions: - unpack lighttpd-1.4.18-<REL>-src.tar.bz2 + unpack lighttpd-1.4.19-<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.18-<REL>.sh all + ./lighttpd-1.4.19-<REL>.sh all This will create: - /usr/src/lighttpd-1.4.18-<REL>.tar.bz2 - /usr/src/lighttpd-1.4.18-<REL>-src.tar.bz2 + /usr/src/lighttpd-1.4.19-<REL>.tar.bz2 + /usr/src/lighttpd-1.4.19-<REL>-src.tar.bz2 -Or use './lighttpd-1.4.18-<REL>.sh prep' to get a patched source directory +Or use './lighttpd-1.4.19-<REL>.sh prep' to get a patched source directory ------------------------------------------- diff --git a/debian/changelog b/debian/changelog index 247c804..0120e98 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +lighttpd (1.4.19-1) UNRELEASED; urgency=low + + * New upstream release. + + -- Pierre Habouzit <madcoder@debian.org> Sun, 16 Mar 2008 10:11:45 +0100 + lighttpd (1.4.18-4) unstable; urgency=high * The “I HATE DPATCH”-release. diff --git a/doc/configuration.txt b/doc/configuration.txt index 416329b..8aac874 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7,8 +7,8 @@ Module: core ------------ :Author: Jan Kneschke -:Date: $Date: 2006-10-04 15:26:23 +0200 (Wed, 04 Oct 2006) $ -:Revision: $Revision: 1371 $ +:Date: $Date: 2007-11-04 17:53:17 +0100 (Sun, 04 Nov 2007) $ +:Revision: $Revision: 2012 $ :abstract: the layout of the configuration file @@ -85,6 +85,8 @@ where <field> is one of one of the following: $HTTP["cookie"] match on cookie +$HTTP["scheme"] + match on scheme $HTTP["host"] match on host $HTTP["useragent"] diff --git a/doc/lighttpd.conf b/doc/lighttpd.conf index 767e100..7fa7471 100644 --- a/doc/lighttpd.conf +++ b/doc/lighttpd.conf @@ -72,6 +72,7 @@ mimetype.assign = ( ".ogg" => "application/ogg", ".wav" => "audio/x-wav", ".gif" => "image/gif", + ".jar" => "application/x-java-archive", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".png" => "image/png", diff --git a/lighttpd.spec b/lighttpd.spec index 1a32b5d..3b58c3d 100644 --- a/lighttpd.spec +++ b/lighttpd.spec @@ -1,26 +1,24 @@ Summary: A fast webserver with minimal memory-footprint (lighttpd) Name: lighttpd -Version: 1.4.18 +Version: 1.4.19 Release: 1 Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz Packager: Jan Kneschke <jan@kneschke.de> License: BSD Group: Networking/Daemons -URL: http://jan.kneschke.de/projects/lighttpd/ +URL: http://www.lighttpd.net/ Requires: pcre >= 3.1 zlib -BuildPrereq: libtool zlib-devel +BuildRequires: libtool zlib-devel BuildRoot: %{_tmppath}/%{name}-root - %description lighttpd is intented to be a frontend for ad-servers which have to deliver small files concurrently to many connections. -Available rpmbuild rebuild options : ---with : ssl mysql lua memcache +Available rpmbuild rebuild options: +--with: ssl mysql lua memcache %prep - %setup -q %build @@ -33,14 +31,13 @@ rm -rf %{buildroot} make %install - %makeinstall mkdir -p %{buildroot}%{_sysconfdir}/{init.d,sysconfig} -if test -f /etc/redhat-release -o -f /etc/fedora-release; then - install -m 755 doc/rc.lighttpd.redhat %{buildroot}%{_sysconfdir}/init.d/lighttpd +if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then + install -m 755 doc/rc.lighttpd.redhat %{buildroot}%{_sysconfdir}/init.d/lighttpd else - install -m 755 doc/rc.lighttpd %{buildroot}%{_sysconfdir}/init.d/lighttpd + install -m 755 doc/rc.lighttpd %{buildroot}%{_sysconfdir}/init.d/lighttpd fi install -m 644 doc/sysconfig.lighttpd %{buildroot}%{_sysconfdir}/sysconfig/lighttpd @@ -49,16 +46,16 @@ rm -rf %{buildroot} %post ## read http://www.fedora.us/docs/spec.html next time :) -if test "$1" = "1"; then - # real install, not upgrade - /sbin/chkconfig --add lighttpd +if [ "$1" = "1" ]; then + # real install, not upgrade + /sbin/chkconfig --add lighttpd fi %preun -if test "$1" = "0"; then - # real uninstall, not upgrade - %{_sysconfdir}/init.d/lighttpd stop - /sbin/chkconfig --del lighttpd +if [ "$1" = "0"]; then + # real uninstall, not upgrade + %{_sysconfdir}/init.d/lighttpd stop + /sbin/chkconfig --del lighttpd fi %files diff --git a/lighttpd.spec.in b/lighttpd.spec.in index 9436a83..2e41846 100644 --- a/lighttpd.spec.in +++ b/lighttpd.spec.in @@ -6,21 +6,19 @@ Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar. Packager: Jan Kneschke <jan@kneschke.de> License: BSD Group: Networking/Daemons -URL: http://jan.kneschke.de/projects/lighttpd/ +URL: http://www.lighttpd.net/ Requires: pcre >= 3.1 zlib -BuildPrereq: libtool zlib-devel +BuildRequires: libtool zlib-devel BuildRoot: %{_tmppath}/%{name}-root - %description lighttpd is intented to be a frontend for ad-servers which have to deliver small files concurrently to many connections. -Available rpmbuild rebuild options : ---with : ssl mysql lua memcache +Available rpmbuild rebuild options: +--with: ssl mysql lua memcache %prep - %setup -q %build @@ -33,14 +31,13 @@ rm -rf %{buildroot} make %install - %makeinstall mkdir -p %{buildroot}%{_sysconfdir}/{init.d,sysconfig} -if test -f /etc/redhat-release -o -f /etc/fedora-release; then - install -m 755 doc/rc.lighttpd.redhat %{buildroot}%{_sysconfdir}/init.d/lighttpd +if [ -f /etc/redhat-release -o -f /etc/fedora-release ]; then + install -m 755 doc/rc.lighttpd.redhat %{buildroot}%{_sysconfdir}/init.d/lighttpd else - install -m 755 doc/rc.lighttpd %{buildroot}%{_sysconfdir}/init.d/lighttpd + install -m 755 doc/rc.lighttpd %{buildroot}%{_sysconfdir}/init.d/lighttpd fi install -m 644 doc/sysconfig.lighttpd %{buildroot}%{_sysconfdir}/sysconfig/lighttpd @@ -49,16 +46,16 @@ rm -rf %{buildroot} %post ## read http://www.fedora.us/docs/spec.html next time :) -if test "$1" = "1"; then - # real install, not upgrade - /sbin/chkconfig --add lighttpd +if [ "$1" = "1" ]; then + # real install, not upgrade + /sbin/chkconfig --add lighttpd fi %preun -if test "$1" = "0"; then - # real uninstall, not upgrade - %{_sysconfdir}/init.d/lighttpd stop - /sbin/chkconfig --del lighttpd +if [ "$1" = "0"]; then + # real uninstall, not upgrade + %{_sysconfdir}/init.d/lighttpd stop + /sbin/chkconfig --del lighttpd fi %files diff --git a/openwrt/control b/openwrt/control index 7dee2c3..7aa3529 100644 --- a/openwrt/control +++ b/openwrt/control @@ -1,8 +1,8 @@ Package: lighttpd -Version: 1.4.18 +Version: 1.4.19 Architecture: mipsel Maintainer: Jan Kneschke <jan@kneschke.de> -Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.18.tar.gz +Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.19.tar.gz Section: net Priority: optional Depends: diff --git a/openwrt/lighttpd.mk b/openwrt/lighttpd.mk index 71cf0c7..1474f75 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.18 +LIGHTTPD=lighttpd-1.4.19 LIGHTTPD_TARGET=.built LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD) LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk diff --git a/src/Makefile.am b/src/Makefile.am index 24967c8..a112789 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,20 +16,20 @@ if CROSS_COMPILING configparser.c configparser.h: mod_ssi_exprparser.c mod_ssi_exprparser.h: else -configparser.y: lemon -mod_ssi_exprparser.y: lemon +$(srcdir)/configparser.y: lemon +$(srcdir)/mod_ssi_exprparser.y: lemon -configparser.c configparser.h: configparser.y +configparser.c configparser.h: $(srcdir)/configparser.y rm -f configparser.h $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c -mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y +mod_ssi_exprparser.c mod_ssi_exprparser.h: $(srcdir)/mod_ssi_exprparser.y rm -f mod_ssi_exprparser.h $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c endif -configfile.c: configparser.h -mod_ssi_expr.c: mod_ssi_exprparser.h +$(srcdir)/configfile.c: configparser.h +$(srcdir)/mod_ssi_expr.c: mod_ssi_exprparser.h common_src=buffer.c log.c \ keyvalue.c chunk.c \ @@ -281,4 +281,4 @@ proc_open_CPPFLAGS= -DDEBUG_PROC_OPEN #ajp_SOURCES = ajp.c noinst_HEADERS = $(hdr) -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c SConscript diff --git a/src/Makefile.in b/src/Makefile.in index 2952518..826af20 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -755,7 +755,7 @@ proc_open_CPPFLAGS = -DDEBUG_PROC_OPEN #bench_SOURCES = buffer.c bench.c #ajp_SOURCES = ajp.c noinst_HEADERS = $(hdr) -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c SConscript all: all-am .SUFFIXES: @@ -1669,19 +1669,19 @@ uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \ @CROSS_COMPILING_TRUE@configparser.c configparser.h: @CROSS_COMPILING_TRUE@mod_ssi_exprparser.c mod_ssi_exprparser.h: -@CROSS_COMPILING_FALSE@configparser.y: lemon -@CROSS_COMPILING_FALSE@mod_ssi_exprparser.y: lemon +@CROSS_COMPILING_FALSE@$(srcdir)/configparser.y: lemon +@CROSS_COMPILING_FALSE@$(srcdir)/mod_ssi_exprparser.y: lemon -@CROSS_COMPILING_FALSE@configparser.c configparser.h: configparser.y +@CROSS_COMPILING_FALSE@configparser.c configparser.h: $(srcdir)/configparser.y @CROSS_COMPILING_FALSE@ rm -f configparser.h @CROSS_COMPILING_FALSE@ $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c -@CROSS_COMPILING_FALSE@mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y +@CROSS_COMPILING_FALSE@mod_ssi_exprparser.c mod_ssi_exprparser.h: $(srcdir)/mod_ssi_exprparser.y @CROSS_COMPILING_FALSE@ rm -f mod_ssi_exprparser.h @CROSS_COMPILING_FALSE@ $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c -configfile.c: configparser.h -mod_ssi_expr.c: mod_ssi_exprparser.h +$(srcdir)/configfile.c: configparser.h +$(srcdir)/mod_ssi_expr.c: mod_ssi_exprparser.h # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/SConscript b/src/SConscript new file mode 100644 index 0000000..0ad2a4e --- /dev/null +++ b/src/SConscript @@ -0,0 +1,195 @@ +import os +import re +import types + +Import('env') + +common_src = Split("buffer.c log.c \ + keyvalue.c chunk.c \ + http_chunk.c stream.c fdevent.c \ + stat_cache.c plugin.c joblist.c etag.c array.c \ + data_string.c data_count.c data_array.c \ + data_integer.c md5.c data_fastcgi.c \ + fdevent_select.c fdevent_linux_rtsig.c \ + fdevent_poll.c fdevent_linux_sysepoll.c \ + fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \ + data_config.c bitset.c \ + inet_ntop_cache.c crc32.c \ + connections-glue.c \ + configfile-glue.c \ + http-header-glue.c \ + splaytree.c network_writev.c \ + network_write.c network_linux_sendfile.c \ + network_freebsd_sendfile.c \ + network_solaris_sendfilev.c network_openssl.c \ + status_counter.c \ +") + +src = Split("server.c response.c connections.c network.c \ + configfile.c configparser.c request.c proc_open.c") + +lemon = env.Program('lemon', 'lemon.c') + +configparser = env.Command(['configparser.c', 'configparser.h'], 'configparser.y', '(cd build; ../' + lemon[0].path + ' -q ../$SOURCE ../src/lempar.c; cd ..)') +env.Depends(configparser, lemon) + +mod_ssi_exprparser = env.Command(['mod_ssi_exprparser.c', 'mod_ssi_exprparser.h'], 'mod_ssi_exprparser.y', '(cd build; ../' + lemon[0].path + ' -q ../$SOURCE ../src/lempar.c; cd ..)') +env.Depends(mod_ssi_exprparser, lemon) + +## the modules and how they are built +modules = { + 'mod_access' : { 'src' : [ 'mod_access.c' ] }, + 'mod_alias' : { 'src' : [ 'mod_alias.c' ] }, + 'mod_cgi' : { 'src' : [ 'mod_cgi.c' ] }, + 'mod_fastcgi' : { 'src' : [ 'mod_fastcgi.c' ] }, + 'mod_scgi' : { 'src' : [ 'mod_scgi.c' ] }, + 'mod_staticfile' : { 'src' : [ 'mod_staticfile.c' ] }, + 'mod_dirlisting' : { 'src' : [ 'mod_dirlisting.c' ], 'lib' : [ env['LIBPCRE'] ] }, + 'mod_indexfile' : { 'src' : [ 'mod_indexfile.c' ] }, + 'mod_setenv' : { 'src' : [ 'mod_setenv.c' ] }, + 'mod_rrdtool' : { 'src' : [ 'mod_rrdtool.c' ] }, + 'mod_usertrack' : { 'src' : [ 'mod_usertrack.c' ] }, + 'mod_proxy' : { 'src' : [ 'mod_proxy.c' ] }, + 'mod_userdir' : { 'src' : [ 'mod_userdir.c' ] }, + 'mod_secdownload' : { 'src' : [ 'mod_secure_download.c' ] }, + 'mod_accesslog' : { 'src' : [ 'mod_accesslog.c' ] }, + 'mod_simple_vhost' : { 'src' : [ 'mod_simple_vhost.c' ] }, + 'mod_evhost' : { 'src' : [ 'mod_evhost.c' ] }, + 'mod_expire' : { 'src' : [ 'mod_expire.c' ] }, + 'mod_status' : { 'src' : [ 'mod_status.c' ] }, + 'mod_compress' : { 'src' : [ 'mod_compress.c' ], 'lib' : [ env['LIBZ'], env['LIBBZ2'] ] }, + 'mod_redirect' : { 'src' : [ 'mod_redirect.c' ], 'lib' : [ env['LIBPCRE'] ] }, + 'mod_rewrite' : { 'src' : [ 'mod_rewrite.c' ], 'lib' : [ env['LIBPCRE'] ] }, + 'mod_auth' : { + 'src' : [ 'mod_auth.c', 'http_auth_digest.c', 'http_auth.c' ], + 'lib' : [ env['LIBCRYPT'], env['LIBLDAP'], env['LIBLBER'] ] }, + 'mod_webdav' : { 'src' : [ 'mod_webdav.c' ], 'lib' : [ env['LIBXML2'], env['LIBSQLITE3'], env['LIBUUID'] ] }, + 'mod_mysql_vhost' : { 'src' : [ 'mod_mysql_vhost.c' ], 'lib' : [ env['LIBMYSQL'] ] }, + 'mod_trigger_b4_dl' : { 'src' : [ 'mod_trigger_b4_dl.c' ], 'lib' : [ env['LIBPCRE'] ] }, + 'mod_cml' : { + 'src' : [ 'mod_cml_lua.c', 'mod_cml.c', 'mod_cml_funcs.c' ], + 'lib' : [ env['LIBPCRE'], env['LIBMEMCACHE'], env['LIBLUA'], env['LIBLUALIB'] ] }, + 'mod_uploadprogress' : { 'src' : [ 'mod_uploadprogress.c' ] }, + 'mod_evasive' : { 'src' : [ 'mod_evasive.c' ] }, + 'mod_ssi' : { 'src' : [ 'mod_ssi_exprparser.c', 'mod_ssi_expr.c', 'mod_ssi.c' ], 'lib' : [ env['LIBPCRE'] ] }, + 'mod_flv_streaming' : { 'src' : [ 'mod_flv_streaming.c' ] }, + 'mod_magnet' : { 'src' : [ 'mod_magnet.c', 'mod_magnet_cache.c' ], 'lib' : [ env['LIBLUA'] ] }, +} + +staticenv = env.Copy(CPPFLAGS=[ env['CPPFLAGS'], '-DLIGHTTPD_STATIC', '-DOPENSSL_NO_KRB5']) + +## all the core-sources + the modules +staticsrc = src + common_src + +staticlib = env['LIBS'] +staticinit = '' +for module in modules.keys(): + staticsrc += modules[module]['src'] + staticinit += "PLUGIN_INIT(%s)\n"%module + if modules[module].has_key('lib'): + staticlib += modules[module]['lib'] + +open('plugin-static.h', 'w+').write(staticinit) + +## turn all src-files into objects +staticobj = [] +for cfile in staticsrc: + staticobj += [ staticenv.Object('static-' + cfile.replace('.c', ''), cfile) ] + +staticbin = staticenv.Program('lighttpd-semi-static', + staticobj, + LIBS = staticlib + ) + +## you might have to adjust the list of libs and the order for your setup +## this is tricky, be warned +fullstaticlib = [] + +## try to calculate the libs for fullstatic with ldd +## 1. find the lib +## 2. check the deps +## 3. add them to the libs +searchlibs = os.pathsep.join([ '/lib/', '/usr/lib/', '/usr/local/lib/' ]) +lddre = re.compile(r'^\s+lib([^=-]+)(?:-[\.0-9]+)?\.so\.[0-9]+ =>', re.MULTILINE) +for libs in staticlib: + if type(libs) is types.StringType: libs = [ libs ] + for lib in libs: + fullstaticlib += [ lib ] + solibpath = env.WhereIs('lib' + lib + '.so', searchlibs) + fullstaticlib += [ lib ] + if solibpath is None: + continue + + f = os.popen('ldd ' + solibpath, 'r') + for aword in lddre.findall(f.read()): + fullstaticlib += [ aword ] + f.close + + +fullstaticbin = staticenv.Program('lighttpd-static', + staticobj, + LIBS = fullstaticlib, + LINKFLAGS= ['-static'] + ) + +Alias('static', staticbin) +Alias('fullstatic', fullstaticbin) + +implib = 'lighttpd.exe.a' +bin_targets = ['lighttpd'] +bin_linkflags = [ env['LINKFLAGS'] ] +if env['COMMON_LIB'] == 'lib': + common_lib = env.SharedLibrary('liblighttpd', common_src, LINKFLAGS = [ env['LINKFLAGS'], '-Wl,--export-dynamic' ]) +else: + src += common_src + common_lib = [] + if env['COMMON_LIB'] == 'bin': + bin_linkflags += [ '-Wl,--export-all-symbols', '-Wl,--out-implib=build/' + implib ] + bin_targets += [ implib ] + else: + bin_linkflags += [ '-Wl,--export-dynamic' ] + +instbin = env.Program(bin_targets, src, LINKFLAGS = bin_linkflags, LIBS= [ env['LIBS'], common_lib, env['LIBDL'] ]) +env.Depends(instbin, configparser) + +spawn_fcgi = env.Program("spawn-fcgi", "spawn-fcgi.c") + +if env['COMMON_LIB'] == 'bin': + common_lib = instbin[1] + +env['SHLIBPREFIX'] = '' +instlib = [] +for module in modules.keys(): + libs = [ common_lib ] + if modules[module].has_key('lib'): + libs += modules[module]['lib'] + instlib += env.SharedLibrary(module, modules[module]['src'], LIBS= [ libs ]) + +inst = [] + +Default(spawn_fcgi) +inst += env.Install('${bindir}', spawn_fcgi) + +if env['build_dynamic']: + Default(instbin[0], instlib) + inst += env.Install('${sbindir}', instbin[0]) + inst += env.Install('${libdir}', instlib) + if env['COMMON_LIB'] == 'lib': + Default(common_lib) + inst += env.Install('${bindir}', common_lib) + +if env['build_static']: + Default(staticbin) + inst += env.Install('${sbindir}', staticbin) + +if env['build_fullstatic']: + Default(fullstaticbin) + inst += env.Install('${sbindir}', fullstaticbin) + +env.Alias('dynamic', instbin) +# default all to be installed +env.Alias('install', inst) + +pkgdir = '.' +tarname = env['package'] + '-' + env['version'] + diff --git a/src/array.h b/src/array.h index b8a8345..9dacf10 100644 --- a/src/array.h +++ b/src/array.h @@ -86,10 +86,12 @@ typedef enum { COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, - COMP_HTTP_USERAGENT, + COMP_HTTP_USER_AGENT, COMP_HTTP_COOKIE, - COMP_HTTP_REMOTEIP, - COMP_HTTP_QUERYSTRING, + COMP_HTTP_REMOTE_IP, + COMP_HTTP_QUERY_STRING, + COMP_HTTP_SCHEME, + COMP_HTTP_REQUEST_METHOD, COMP_LAST_ELEMENT } comp_key_t; @@ -515,6 +515,7 @@ typedef struct { #ifdef USE_OPENSSL SSL_CTX *ssl_ctx; #endif + unsigned short is_proxy_ssl; } server_socket; typedef struct { diff --git a/src/configfile-glue.c b/src/configfile-glue.c index f6ead92..66a596e 100644 --- a/src/configfile-glue.c +++ b/src/configfile-glue.c @@ -277,7 +277,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat } break; } - case COMP_HTTP_REMOTEIP: { + case COMP_HTTP_REMOTE_IP: { char *nm_slash; /* handle remoteip limitations * @@ -341,11 +341,15 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat } break; } + case COMP_HTTP_SCHEME: + l = con->uri.scheme; + break; + case COMP_HTTP_URL: l = con->uri.path; break; - case COMP_HTTP_QUERYSTRING: + case COMP_HTTP_QUERY_STRING: l = con->uri.query; break; @@ -372,7 +376,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat } break; } - case COMP_HTTP_USERAGENT: { + case COMP_HTTP_USER_AGENT: { data_string *ds; if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) { l = ds->value; @@ -381,7 +385,17 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat } break; } + case COMP_HTTP_REQUEST_METHOD: { + const char *method = get_http_method_name(con->request.http_method); + + /* we only have the request method as const char but we need a buffer for comparing */ + + buffer_copy_string(srv->tmp_buf, method); + l = srv->tmp_buf; + + break; + } default: return COND_RESULT_FALSE; } diff --git a/src/configparser.c b/src/configparser.c index 363b395..58a03fe 100644 --- a/src/configparser.c +++ b/src/configparser.c @@ -54,7 +54,7 @@ static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) { return NULL; } -/* op1 is to be eat/return by this function, op1->key is not cared +/* op1 is to be eat/return by this function if success, op1->key is not cared op2 is left untouch, unreferenced */ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { @@ -72,7 +72,6 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { return (data_unset *)ds; } else { fprintf(stderr, "data type mismatch, cannot be merge\n"); - op1->free(op1); return NULL; } } @@ -106,7 +105,7 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { } -#line 110 "configparser.c" +#line 109 "configparser.c" /* Next is all token values, in a form suitable for use by makeheaders. ** This section will be null unless lemon is run with the -m switch. */ @@ -515,42 +514,42 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ case 25: #line 142 "./configparser.y" { buffer_free((yypminor->yy0)); } -#line 518 "configparser.c" +#line 517 "configparser.c" break; case 35: #line 133 "./configparser.y" { (yypminor->yy41)->free((yypminor->yy41)); } -#line 523 "configparser.c" +#line 522 "configparser.c" break; case 36: #line 134 "./configparser.y" { (yypminor->yy41)->free((yypminor->yy41)); } -#line 528 "configparser.c" +#line 527 "configparser.c" break; case 37: #line 135 "./configparser.y" { (yypminor->yy41)->free((yypminor->yy41)); } -#line 533 "configparser.c" +#line 532 "configparser.c" break; case 39: #line 136 "./configparser.y" { array_free((yypminor->yy40)); } -#line 538 "configparser.c" +#line 537 "configparser.c" break; case 40: #line 137 "./configparser.y" { array_free((yypminor->yy40)); } -#line 543 "configparser.c" +#line 542 "configparser.c" break; case 41: #line 138 "./configparser.y" { buffer_free((yypminor->yy43)); } -#line 548 "configparser.c" +#line 547 "configparser.c" break; case 42: #line 139 "./configparser.y" { buffer_free((yypminor->yy43)); } -#line 553 "configparser.c" +#line 552 "configparser.c" break; default: break; /* If no destructor action specified: do nothing */ } @@ -818,9 +817,9 @@ static void yy_reduce( /* No destructor defined for global */ break; case 5: -#line 116 "./configparser.y" +#line 115 "./configparser.y" { yymsp[-1].minor.yy78 = NULL; } -#line 823 "configparser.c" +#line 822 "configparser.c" yy_destructor(1,&yymsp[0].minor); break; case 6: @@ -835,31 +834,33 @@ static void yy_reduce( case 9: #line 144 "./configparser.y" { - buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43); - if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) { - fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", - ctx->current->context_ndx, - ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr); - ctx->ok = 0; - } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) { - array_insert_unique(ctx->current->value, yymsp[0].minor.yy41); - yymsp[0].minor.yy41 = NULL; - } else { - fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", - ctx->current->context_ndx, - ctx->current->key->ptr, yymsp[0].minor.yy41->key->ptr); - ctx->ok = 0; - yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); - yymsp[0].minor.yy41 = NULL; + if (ctx->ok) { + buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43); + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) { + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", + ctx->current->context_ndx, + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr); + ctx->ok = 0; + } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) { + array_insert_unique(ctx->current->value, yymsp[0].minor.yy41); + yymsp[0].minor.yy41 = NULL; + } else { + fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", + ctx->current->context_ndx, + ctx->current->key->ptr, yymsp[0].minor.yy41->key->ptr); + ctx->ok = 0; + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); + yymsp[0].minor.yy41 = NULL; + } } buffer_free(yymsp[-2].minor.yy43); yymsp[-2].minor.yy43 = NULL; } -#line 858 "configparser.c" +#line 859 "configparser.c" yy_destructor(2,&yymsp[-1].minor); break; case 10: -#line 166 "./configparser.y" +#line 168 "./configparser.y" { array *vars = ctx->current->value; data_unset *du; @@ -884,6 +885,7 @@ static void yy_reduce( du = configparser_merge_data(du, yymsp[0].minor.yy41); if (NULL == du) { ctx->ok = 0; + du->free(du); } else { buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43); @@ -898,11 +900,11 @@ static void yy_reduce( yymsp[-2].minor.yy43 = NULL; yymsp[0].minor.yy41 = NULL; } -#line 901 "configparser.c" +#line 903 "configparser.c" yy_destructor(3,&yymsp[-1].minor); break; case 11: -#line 205 "./configparser.y" +#line 208 "./configparser.y" { if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) { yygotominor.yy43 = buffer_init_string("var."); @@ -914,10 +916,10 @@ static void yy_reduce( yymsp[0].minor.yy0 = NULL; } } -#line 917 "configparser.c" +#line 919 "configparser.c" break; case 12: -#line 217 "./configparser.y" +#line 220 "./configparser.y" { yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41); if (NULL == yygotominor.yy41) { @@ -927,19 +929,19 @@ static void yy_reduce( yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } -#line 930 "configparser.c" +#line 932 "configparser.c" yy_destructor(5,&yymsp[-1].minor); break; case 13: -#line 227 "./configparser.y" +#line 230 "./configparser.y" { yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } -#line 939 "configparser.c" +#line 941 "configparser.c" break; case 14: -#line 232 "./configparser.y" +#line 235 "./configparser.y" { yygotominor.yy41 = NULL; if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) { @@ -966,59 +968,59 @@ static void yy_reduce( buffer_free(yymsp[0].minor.yy43); yymsp[0].minor.yy43 = NULL; } -#line 969 "configparser.c" +#line 971 "configparser.c" break; case 15: -#line 259 "./configparser.y" +#line 262 "./configparser.y" { yygotominor.yy41 = (data_unset *)data_string_init(); buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0); buffer_free(yymsp[0].minor.yy0); yymsp[0].minor.yy0 = NULL; } -#line 979 "configparser.c" +#line 981 "configparser.c" break; case 16: -#line 266 "./configparser.y" +#line 269 "./configparser.y" { yygotominor.yy41 = (data_unset *)data_integer_init(); ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10); buffer_free(yymsp[0].minor.yy0); yymsp[0].minor.yy0 = NULL; } -#line 989 "configparser.c" +#line 991 "configparser.c" break; case 17: -#line 272 "./configparser.y" +#line 275 "./configparser.y" { yygotominor.yy41 = (data_unset *)data_array_init(); array_free(((data_array *)(yygotominor.yy41))->value); ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40; yymsp[0].minor.yy40 = NULL; } -#line 999 "configparser.c" +#line 1001 "configparser.c" break; case 18: -#line 278 "./configparser.y" +#line 281 "./configparser.y" { yygotominor.yy40 = array_init(); } -#line 1006 "configparser.c" +#line 1008 "configparser.c" yy_destructor(8,&yymsp[-1].minor); yy_destructor(9,&yymsp[0].minor); break; case 19: -#line 281 "./configparser.y" +#line 284 "./configparser.y" { yygotominor.yy40 = yymsp[-1].minor.yy40; yymsp[-1].minor.yy40 = NULL; } -#line 1016 "configparser.c" +#line 1018 "configparser.c" yy_destructor(8,&yymsp[-2].minor); yy_destructor(9,&yymsp[0].minor); break; case 20: -#line 286 "./configparser.y" +#line 289 "./configparser.y" { if (buffer_is_empty(yymsp[0].minor.yy41->key) || NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) { @@ -1035,37 +1037,37 @@ static void yy_reduce( yygotominor.yy40 = yymsp[-2].minor.yy40; yymsp[-2].minor.yy40 = NULL; } -#line 1038 "configparser.c" +#line 1040 "configparser.c" yy_destructor(10,&yymsp[-1].minor); break; case 21: -#line 303 "./configparser.y" +#line 306 "./configparser.y" { yygotominor.yy40 = yymsp[-1].minor.yy40; yymsp[-1].minor.yy40 = NULL; } -#line 1047 "configparser.c" +#line 1049 "configparser.c" yy_destructor(10,&yymsp[0].minor); break; case 22: -#line 308 "./configparser.y" +#line 311 "./configparser.y" { yygotominor.yy40 = array_init(); array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } -#line 1057 "configparser.c" +#line 1059 "configparser.c" break; case 23: -#line 314 "./configparser.y" +#line 317 "./configparser.y" { yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } -#line 1065 "configparser.c" +#line 1067 "configparser.c" break; case 24: -#line 318 "./configparser.y" +#line 321 "./configparser.y" { buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43); buffer_free(yymsp[-2].minor.yy43); @@ -1074,7 +1076,7 @@ static void yy_reduce( yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } -#line 1077 "configparser.c" +#line 1079 "configparser.c" yy_destructor(11,&yymsp[-1].minor); break; case 25: @@ -1083,18 +1085,18 @@ static void yy_reduce( case 26: break; case 27: -#line 330 "./configparser.y" +#line 333 "./configparser.y" { data_config *dc; dc = (data_config *)array_get_element(ctx->srv->config_context, "global"); assert(dc); configparser_push(ctx, dc, 0); } -#line 1093 "configparser.c" +#line 1095 "configparser.c" yy_destructor(12,&yymsp[0].minor); break; case 28: -#line 337 "./configparser.y" +#line 340 "./configparser.y" { data_config *cur; @@ -1103,16 +1105,16 @@ static void yy_reduce( assert(cur && ctx->current); - yygotominor.yy0 = cur; + yygotominor.yy78 = cur; } -#line 1108 "configparser.c" +#line 1110 "configparser.c" /* No destructor defined for globalstart */ yy_destructor(13,&yymsp[-2].minor); /* No destructor defined for metalines */ yy_destructor(14,&yymsp[0].minor); break; case 29: -#line 348 "./configparser.y" +#line 351 "./configparser.y" { assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx); yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78; @@ -1121,20 +1123,20 @@ static void yy_reduce( yymsp[-3].minor.yy78 = NULL; yymsp[0].minor.yy78 = NULL; } -#line 1124 "configparser.c" +#line 1126 "configparser.c" /* No destructor defined for eols */ yy_destructor(15,&yymsp[-1].minor); break; case 30: -#line 357 "./configparser.y" +#line 360 "./configparser.y" { yygotominor.yy78 = yymsp[0].minor.yy78; yymsp[0].minor.yy78 = NULL; } -#line 1134 "configparser.c" +#line 1136 "configparser.c" break; case 31: -#line 362 "./configparser.y" +#line 365 "./configparser.y" { data_config *cur; @@ -1145,14 +1147,14 @@ static void yy_reduce( yygotominor.yy78 = cur; } -#line 1148 "configparser.c" +#line 1150 "configparser.c" /* No destructor defined for context */ yy_destructor(13,&yymsp[-2].minor); /* No destructor defined for metalines */ yy_destructor(14,&yymsp[0].minor); break; case 32: -#line 373 "./configparser.y" +#line 376 "./configparser.y" { data_config *dc; buffer *b, *rvalue, *op; @@ -1201,10 +1203,15 @@ static void yy_reduce( { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) }, { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) }, { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) }, - { COMP_HTTP_USERAGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, + { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, + { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) }, { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) }, - { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, - { COMP_HTTP_QUERYSTRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, + { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, + { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) }, + { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, + { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") }, + { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") }, + { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) }, { COMP_UNSET, NULL, 0 }, }; size_t i; @@ -1288,45 +1295,45 @@ static void yy_reduce( yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } -#line 1291 "configparser.c" +#line 1298 "configparser.c" yy_destructor(16,&yymsp[-6].minor); yy_destructor(18,&yymsp[-4].minor); yy_destructor(19,&yymsp[-2].minor); break; case 33: -#line 508 "./configparser.y" +#line 516 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_EQ; } -#line 1301 "configparser.c" +#line 1308 "configparser.c" yy_destructor(20,&yymsp[0].minor); break; case 34: -#line 511 "./configparser.y" +#line 519 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_MATCH; } -#line 1309 "configparser.c" +#line 1316 "configparser.c" yy_destructor(21,&yymsp[0].minor); break; case 35: -#line 514 "./configparser.y" +#line 522 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_NE; } -#line 1317 "configparser.c" +#line 1324 "configparser.c" yy_destructor(22,&yymsp[0].minor); break; case 36: -#line 517 "./configparser.y" +#line 525 "./configparser.y" { yygotominor.yy27 = CONFIG_COND_NOMATCH; } -#line 1325 "configparser.c" +#line 1332 "configparser.c" yy_destructor(23,&yymsp[0].minor); break; case 37: -#line 521 "./configparser.y" +#line 529 "./configparser.y" { yygotominor.yy43 = NULL; if (ctx->ok) { @@ -1343,10 +1350,10 @@ static void yy_reduce( yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } -#line 1346 "configparser.c" +#line 1353 "configparser.c" break; case 38: -#line 538 "./configparser.y" +#line 546 "./configparser.y" { if (ctx->ok) { if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) { @@ -1356,11 +1363,11 @@ static void yy_reduce( yymsp[0].minor.yy43 = NULL; } } -#line 1359 "configparser.c" +#line 1366 "configparser.c" yy_destructor(24,&yymsp[-1].minor); break; case 39: -#line 548 "./configparser.y" +#line 556 "./configparser.y" { if (ctx->ok) { if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) { @@ -1370,7 +1377,7 @@ static void yy_reduce( yymsp[0].minor.yy43 = NULL; } } -#line 1373 "configparser.c" +#line 1380 "configparser.c" yy_destructor(25,&yymsp[-1].minor); break; }; @@ -1400,11 +1407,11 @@ static void yy_parse_failed( while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ -#line 107 "./configparser.y" +#line 106 "./configparser.y" ctx->ok = 0; -#line 1407 "configparser.c" +#line 1414 "configparser.c" configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */ } diff --git a/src/configparser.y b/src/configparser.y index 30f5fd9..57e2dc5 100644 --- a/src/configparser.y +++ b/src/configparser.y @@ -51,7 +51,7 @@ static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) { return NULL; } -/* op1 is to be eat/return by this function, op1->key is not cared +/* op1 is to be eat/return by this function if success, op1->key is not cared op2 is left untouch, unreferenced */ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { @@ -69,7 +69,6 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { return (data_unset *)ds; } else { fprintf(stderr, "data type mismatch, cannot be merge\n"); - op1->free(op1); return NULL; } } @@ -123,6 +122,7 @@ metaline ::= EOL. %type aelement {data_unset *} %type condline {data_config *} %type condlines {data_config *} +%type global {data_config *} %type aelements {array *} %type array {array *} %type key {buffer *} @@ -142,22 +142,24 @@ metaline ::= EOL. %token_destructor { buffer_free($$); } varline ::= key(A) ASSIGN expression(B). { - buffer_copy_string_buffer(B->key, A); - if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { - fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", - ctx->current->context_ndx, - ctx->current->key->ptr, A->ptr); - ctx->ok = 0; - } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) { - array_insert_unique(ctx->current->value, B); - B = NULL; - } else { - fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", - ctx->current->context_ndx, - ctx->current->key->ptr, B->key->ptr); - ctx->ok = 0; - B->free(B); - B = NULL; + if (ctx->ok) { + buffer_copy_string_buffer(B->key, A); + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) { + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n", + ctx->current->context_ndx, + ctx->current->key->ptr, A->ptr); + ctx->ok = 0; + } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) { + array_insert_unique(ctx->current->value, B); + B = NULL; + } else { + fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", + ctx->current->context_ndx, + ctx->current->key->ptr, B->key->ptr); + ctx->ok = 0; + B->free(B); + B = NULL; + } } buffer_free(A); A = NULL; @@ -187,6 +189,7 @@ varline ::= key(A) APPEND expression(B). { du = configparser_merge_data(du, B); if (NULL == du) { ctx->ok = 0; + du->free(du); } else { buffer_copy_string_buffer(du->key, A); @@ -418,10 +421,15 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio { COMP_HTTP_URL, CONST_STR_LEN("HTTP[\"url\"]" ) }, { COMP_HTTP_HOST, CONST_STR_LEN("HTTP[\"host\"]" ) }, { COMP_HTTP_REFERER, CONST_STR_LEN("HTTP[\"referer\"]" ) }, - { COMP_HTTP_USERAGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, + { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"useragent\"]" ) }, + { COMP_HTTP_USER_AGENT, CONST_STR_LEN("HTTP[\"user-agent\"]" ) }, { COMP_HTTP_COOKIE, CONST_STR_LEN("HTTP[\"cookie\"]" ) }, - { COMP_HTTP_REMOTEIP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, - { COMP_HTTP_QUERYSTRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, + { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remoteip\"]" ) }, + { COMP_HTTP_REMOTE_IP, CONST_STR_LEN("HTTP[\"remote-ip\"]" ) }, + { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"querystring\"]") }, + { COMP_HTTP_QUERY_STRING, CONST_STR_LEN("HTTP[\"query-string\"]") }, + { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") }, + { COMP_HTTP_SCHEME, CONST_STR_LEN("HTTP[\"scheme\"]" ) }, { COMP_UNSET, NULL, 0 }, }; size_t i; diff --git a/src/connections.c b/src/connections.c index 94d36b4..184ecb9 100644 --- a/src/connections.c +++ b/src/connections.c @@ -394,10 +394,13 @@ static int connection_handle_write_prepare(server *srv, connection *con) { * 403 is from the response handler when noone else catched it * * */ - if (con->uri.path->used && + if ((!con->http_status || con->http_status == 200) && con->uri.path->used && con->uri.path->ptr[0] != '*') { response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + con->parsed_response &= ~HTTP_CONTENT_LENGTH; + con->http_status = 200; con->file_finished = 1; @@ -498,9 +501,11 @@ static int connection_handle_write_prepare(server *srv, connection *con) { case 207: case 200: /* class: header + body */ case 201: + case 300: case 301: case 302: case 303: + case 307: break; case 206: /* write_queue is already prepared */ @@ -511,13 +516,13 @@ static int connection_handle_write_prepare(server *srv, connection *con) { default: /* disable chunked encoding again as we have no body */ con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; + con->parsed_response &= ~HTTP_CONTENT_LENGTH; chunkqueue_reset(con->write_queue); con->file_finished = 1; break; } - if (con->file_finished) { /* we have all the content and chunked encoding is not used, set a content-length */ @@ -536,12 +541,16 @@ static int connection_handle_write_prepare(server *srv, connection *con) { if ((con->http_status >= 100 && con->http_status < 200) || con->http_status == 204 || con->http_status == 304) { + data_string *ds; /* no Content-Body, no Content-Length */ - } else if (qlen >= 0) { + if (NULL != (ds = (data_string*) array_get_element(con->response.headers, "Content-Length"))) { + buffer_reset(ds->value); // Headers with empty values are ignored for output + } + } else if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) { /* qlen = 0 is important for Redirects (301, ...) as they MAY have * a content. Browsers are waiting for a Content otherwise */ - buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue)); + buffer_copy_off_t(srv->tmp_buf, qlen); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf)); } @@ -582,6 +591,8 @@ static int connection_handle_write_prepare(server *srv, connection *con) { * a HEAD request has the same as a GET * without the content */ + con->file_finished = 1; + chunkqueue_reset(con->write_queue); con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; } @@ -834,14 +845,8 @@ int connection_reset(server *srv, connection *con) { con->plugin_ctx[pd->id] = NULL; } -#if COND_RESULT_UNSET - for (i = srv->config_context->used - 1; i >= 0; i --) { - con->cond_cache[i].result = COND_RESULT_UNSET; - con->cond_cache[i].patterncount = 0; - } -#else - memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used); -#endif + /* The cond_cache gets reset in response.c */ +// config_cond_cache_reset(srv, con); #ifdef USE_OPENSSL if (con->ssl_error_want_reuse_buffer) { @@ -1,5 +1,14 @@ #include <string.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#if defined HAVE_STDINT_H #include <stdint.h> +#elif defined HAVE_INTTYPES_H +#include <inttypes.h> +#endif #include "buffer.h" #include "etag.h" diff --git a/src/fdevent_solaris_devpoll.c b/src/fdevent_solaris_devpoll.c index f77daef..76414a4 100644 --- a/src/fdevent_solaris_devpoll.c +++ b/src/fdevent_solaris_devpoll.c @@ -67,7 +67,7 @@ static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) { int ret; dopoll.dp_timeout = timeout_ms; - dopoll.dp_nfds = ev->maxfds; + dopoll.dp_nfds = ev->maxfds - 1; dopoll.dp_fds = ev->devpollfds; ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll); diff --git a/src/http_auth.c b/src/http_auth.c index 1bfb460..89abde6 100644 --- a/src/http_auth.c +++ b/src/http_auth.c @@ -29,6 +29,7 @@ #include "log.h" #include "http_auth.h" #include "http_auth_digest.h" +#include "inet_ntop_cache.h" #include "stream.h" #ifdef USE_OPENSSL @@ -862,7 +863,7 @@ int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, /* password doesn't match */ if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) { - log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username); + log_error_write(srv, __FILE__, __LINE__, "sbbss", "password doesn't match for ", con->uri.path, username, ", IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr))); buffer_free(username); buffer_free(password); @@ -1130,7 +1131,7 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p } log_error_write(srv, __FILE__, __LINE__, "sss", - "digest: auth failed for", username, "wrong password"); + "digest: auth failed for ", username, ": wrong password, IP:", inet_ntop_cache_get_ip(srv, &(con->dst_addr))); buffer_free(b); return 0; diff --git a/src/mod_auth.c b/src/mod_auth.c index 19ed387..7bd306d 100644 --- a/src/mod_auth.c +++ b/src/mod_auth.c @@ -238,13 +238,13 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) { int auth_type_len = auth_realm - http_authorization; if ((auth_type_len == 5) && - (0 == strncmp(http_authorization, "Basic", auth_type_len))) { + (0 == strncasecmp(http_authorization, "Basic", auth_type_len))) { if (0 == strcmp(method->value->ptr, "basic")) { auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1); } } else if ((auth_type_len == 6) && - (0 == strncmp(http_authorization, "Digest", auth_type_len))) { + (0 == strncasecmp(http_authorization, "Digest", auth_type_len))) { if (0 == strcmp(method->value->ptr, "digest")) { if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) { con->http_status = 400; diff --git a/src/mod_cgi.c b/src/mod_cgi.c index f5e5b3a..82ae78b 100644 --- a/src/mod_cgi.c +++ b/src/mod_cgi.c @@ -1004,6 +1004,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * case -1: /* error */ log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno)); + return -1; break; default: { handler_ctx *hctx; @@ -1227,8 +1228,14 @@ TRIGGER_FUNC(cgi_trigger) { #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", p->cgi_pid.ptr[ndx]); #endif + } else if (WIFSIGNALED(status)) { + /* FIXME: what if we killed the CGI script with a kill(..., SIGTERM) ? + */ + if (WTERMSIG(status) != SIGTERM) { + log_error_write(srv, __FILE__, __LINE__, "sd", "cleaning up CGI: process died with signal", WTERMSIG(status)); + } } else { - log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?"); + log_error_write(srv, __FILE__, __LINE__, "s", "cleaning up CGI: ended unexpectedly"); } cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]); diff --git a/src/mod_compress.c b/src/mod_compress.c index 464945e..79f6e74 100644 --- a/src/mod_compress.c +++ b/src/mod_compress.c @@ -102,6 +102,50 @@ FREE_FUNC(mod_compress_free) { return HANDLER_GO_ON; } +// 0 on success, -1 for error +int mkdir_recursive(char *dir) { + char *p = dir; + + if (!dir || !dir[0]) + return 0; + + while ((p = strchr(p + 1, '/')) != NULL) { + + *p = '\0'; + if ((mkdir(dir, 0700) != 0) && (errno != EEXIST)) { + *p = '/'; + return -1; + } + + *p++ = '/'; + if (!*p) return 0; // Ignore trailing slash + } + + return (mkdir(dir, 0700) != 0) && (errno != EEXIST) ? -1 : 0; +} + +// 0 on success, -1 for error +int mkdir_for_file(char *filename) { + char *p = filename; + + if (!filename || !filename[0]) + return -1; + + while ((p = strchr(p + 1, '/')) != NULL) { + + *p = '\0'; + if ((mkdir(filename, 0700) != 0) && (errno != EEXIST)) { + *p = '/'; + return -1; + } + + *p++ = '/'; + if (!*p) return -1; // Unexpected trailing slash in filename + } + + return 0; +} + SETDEFAULTS_FUNC(mod_compress_setdefaults) { plugin_data *p = p_d; size_t i = 0; @@ -134,6 +178,8 @@ SETDEFAULTS_FUNC(mod_compress_setdefaults) { } if (!buffer_is_empty(s->compress_cache_dir)) { + mkdir_recursive(s->compress_cache_dir->ptr); + struct stat st; if (0 != stat(s->compress_cache_dir->ptr, &st)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", @@ -342,27 +388,8 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu BUFFER_APPEND_SLASH(p->ofn); if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) { - size_t offset = p->ofn->used - 1; - char *dir, *nextdir; - buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1); - buffer_copy_string_buffer(p->b, p->ofn); - - /* mkdir -p ... */ - for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) { - *nextdir = '\0'; - - if (-1 == mkdir(p->b->ptr, 0700)) { - if (errno != EEXIST) { - log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno)); - - return -1; - } - } - - *nextdir = '/'; - } } else { buffer_append_string_buffer(p->ofn, con->uri.path); } @@ -384,6 +411,11 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu buffer_append_string_buffer(p->ofn, sce->etag); + if (-1 == mkdir_for_file(p->ofn->ptr)) { + log_error_write(srv, __FILE__, __LINE__, "sb", "couldn't create directory for file", p->ofn); + return -1; + } + if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) { if (errno == EEXIST) { /* cache-entry exists */ @@ -407,6 +439,11 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu close(ofd); + /* Remove the incomplete cache file, so that later hits aren't served from it */ + if (-1 == unlink(p->ofn->ptr)) { + log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno)); + } + return -1; } @@ -416,6 +453,12 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu close(ofd); close(ifd); + + /* Remove the incomplete cache file, so that later hits aren't served from it */ + if (-1 == unlink(p->ofn->ptr)) { + log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno)); + } + return -1; } @@ -438,22 +481,29 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu break; } - if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) { - munmap(start, sce->st.st_size); - close(ofd); - close(ifd); - return -1; - } - - if ((size_t)r != p->b->used) { - + if (ret == 0) { + r = write(ofd, p->b->ptr, p->b->used); + if (-1 == r) { + log_error_write(srv, __FILE__, __LINE__, "sbss", "writing cachefile", p->ofn, "failed:", strerror(errno)); + ret = -1; + } else if ((size_t)r != p->b->used) { + log_error_write(srv, __FILE__, __LINE__, "sbs", "writing cachefile", p->ofn, "failed: not enough bytes written"); + ret = -1; + } } munmap(start, sce->st.st_size); close(ofd); close(ifd); - if (ret != 0) return -1; + if (ret != 0) { + /* Remove the incomplete cache file, so that later hits aren't served from it */ + if (-1 == unlink(p->ofn->ptr)) { + log_error_write(srv, __FILE__, __LINE__, "sbss", "unlinking incomplete cachefile", p->ofn, "failed:", strerror(errno)); + } + + return -1; + } buffer_copy_string_buffer(con->physical.path, p->ofn); @@ -570,6 +620,8 @@ PHYSICALPATH_FUNC(mod_compress_physical) { off_t max_fsize; stat_cache_entry *sce = NULL; + if (con->mode != DIRECT || con->http_status) return HANDLER_GO_ON; + /* only GET and POST can get compressed */ if (con->request.http_method != HTTP_METHOD_GET && con->request.http_method != HTTP_METHOD_POST) { @@ -678,8 +730,16 @@ PHYSICALPATH_FUNC(mod_compress_physical) { } } else if (0 == deflate_file_to_buffer(srv, con, p, con->physical.path, sce, compression_type)) { + buffer *mtime; response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name)); + + mtime = strftime_cache_get(srv, sce->st.st_mtime); + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); + + etag_mutate(con->physical.etag, sce->etag); + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag)); + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type)); return HANDLER_FINISHED; diff --git a/src/mod_extforward.c b/src/mod_extforward.c index 8ed336d..be7dd0f 100644 --- a/src/mod_extforward.c +++ b/src/mod_extforward.c @@ -20,6 +20,7 @@ /** * mod_extforward.c for lighttpd, by comman.kang <at> gmail <dot> com * extended, modified by Lionel Elie Mamane (LEM), lionel <at> mamane <dot> lu + * support chained proxies by glen@delfi.ee, #1528 * * Config example: * @@ -33,6 +34,10 @@ * Note that "all" has precedence over specific entries, * so "all except" setups will not work. * + * In case you have chained proxies, you can add all their IP's to the + * config. However "all" has effect only on connecting IP, as the + * X-Forwarded-For header can not be trusted. + * * Note: The effect of this module is variable on $HTTP["remotip"] directives and * other module's remote ip dependent actions. * Things done by modules before we change the remoteip or after we reset it will match on the proxy's IP. @@ -225,18 +230,16 @@ static array *extract_forward_array(buffer *pbuffer) char *base, *curr; /* state variable, 0 means not in string, 1 means in string */ int in_str = 0; - for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) - { + for (base = pbuffer->ptr, curr = pbuffer->ptr; *curr; curr++) { if (in_str) { - if ( (*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':' ) { + if ((*curr > '9' || *curr < '0') && *curr != '.' && *curr != ':') { /* found an separator , insert value into result array */ - put_string_into_array_len(result, base, curr-base); + put_string_into_array_len(result, base, curr - base); /* change state to not in string */ in_str = 0; } } else { - if (*curr >= '0' && *curr <= '9') - { + if (*curr >= '0' && *curr <= '9') { /* found leading char of an IP address, move base pointer and change state */ base = curr; in_str = 1; @@ -244,9 +247,8 @@ static array *extract_forward_array(buffer *pbuffer) } } /* if breaking out while in str, we got to the end of string, so add it */ - if (in_str) - { - put_string_into_array_len(result, base, curr-base); + if (in_str) { + put_string_into_array_len(result, base, curr - base); } } return result; @@ -255,18 +257,40 @@ static array *extract_forward_array(buffer *pbuffer) #define IP_TRUSTED 1 #define IP_UNTRUSTED 0 /* - check whether ip is trusted, return 1 for trusted , 0 for untrusted -*/ + * check whether ip is trusted, return 1 for trusted , 0 for untrusted + */ static int is_proxy_trusted(const char *ipstr, plugin_data *p) { - data_string* allds = (data_string *) array_get_element(p->conf.forwarder,"all"); + data_string* allds = (data_string *)array_get_element(p->conf.forwarder, "all"); + if (allds) { - if (strcasecmp(allds->value->ptr,"trust") == 0) + if (strcasecmp(allds->value->ptr, "trust") == 0) { return IP_TRUSTED; - else + } else { return IP_UNTRUSTED; + } } - return (data_string *)array_get_element(p->conf.forwarder,ipstr) ? IP_TRUSTED : IP_UNTRUSTED ; + + return (data_string *)array_get_element(p->conf.forwarder, ipstr) ? IP_TRUSTED : IP_UNTRUSTED; +} + +/* + * Return char *ip of last address of proxy that is not trusted. + * Do not accept "all" keyword here. + */ +static const char *last_not_in_array(array *a, plugin_data *p) +{ + array *forwarder = p->conf.forwarder; + + for (int i = a->used - 1; i >= 0; i--) { + data_string *ds = (data_string *)a->data[i]; + const char *ip = ds->value->ptr; + + if (!array_get_element(forwarder, ip)) { + return ip; + } + } + return NULL; } struct addrinfo *ipstr_to_sockaddr(const char *host) @@ -305,7 +329,7 @@ struct addrinfo *ipstr_to_sockaddr(const char *host) static void clean_cond_cache(server *srv, connection *con) { - config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTEIP); + config_cond_cache_reset_item(srv, con, COMP_HTTP_REMOTE_IP); } URIHANDLER_FUNC(mod_extforward_uri_handler) { @@ -316,9 +340,8 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) { struct addrinfo *addrlist = NULL; #endif const char *dst_addr_str = NULL; - int i; array *forward_array = NULL; - char *real_remote_addr = NULL; + const char *real_remote_addr = NULL; #ifdef HAVE_IPV6 #endif @@ -342,7 +365,6 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) { return HANDLER_GO_ON; } - /* if the remote ip itself is not trusted , then do nothing */ #ifdef HAVE_IPV6 dst_addr_str = inet_ntop(con->dst_addr.plain.sa_family, con->dst_addr.plain.sa_family == AF_INET6 ? @@ -353,7 +375,9 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) { #else dst_addr_str = inet_ntoa(con->dst_addr.ipv4.sin_addr); #endif - if (IP_UNTRUSTED == is_proxy_trusted (dst_addr_str, p) ) { + + /* if the remote ip itself is not trusted, then do nothing */ + if (IP_UNTRUSTED == is_proxy_trusted(dst_addr_str, p)) { if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "remote address is NOT a trusted proxy, skipping"); @@ -362,40 +386,34 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) { return HANDLER_GO_ON; } + /* build forward_array from forwarded data_string */ forward_array = extract_forward_array(forwarded->value); - - /* Testing shows that multiple headers and multiple values in one header - come in _reverse_ order. So the first one we get is the last one in the request. */ - for (i = forward_array->used - 1; i >= 0; i--) { - data_string *ds = (data_string *) forward_array->data[i]; - if (ds) { - real_remote_addr = ds->value->ptr; - break; - } else { - /* bug ? bailing out here */ - break; - } - } + real_remote_addr = last_not_in_array(forward_array, p); if (real_remote_addr != NULL) { /* parsed */ sock_addr sock; - struct addrinfo *addrs_left; + server_socket *srv_sock = con->srv_socket; + data_string *forwarded_proto = (data_string *)array_get_element(con->request.headers, "X-Forwarded-Proto"); + + if (forwarded_proto && !strcmp(forwarded_proto->value->ptr, "https")) { + srv_sock->is_proxy_ssl = 1; + } else { + srv_sock->is_proxy_ssl = 0; + } if (con->conf.log_request_handling) { - log_error_write(srv, __FILE__, __LINE__, "ss", - "using address:", real_remote_addr); + log_error_write(srv, __FILE__, __LINE__, "ss", "using address:", real_remote_addr); } #ifdef HAVE_IPV6 addrlist = ipstr_to_sockaddr(real_remote_addr); sock.plain.sa_family = AF_UNSPEC; - for (addrs_left = addrlist; addrs_left != NULL; - addrs_left = addrs_left -> ai_next) { + for (addrs_left = addrlist; addrs_left != NULL; addrs_left = addrs_left -> ai_next) { sock.plain.sa_family = addrs_left->ai_family; - if ( sock.plain.sa_family == AF_INET ) { + if (sock.plain.sa_family == AF_INET) { sock.ipv4.sin_addr = ((struct sockaddr_in*)addrs_left->ai_addr)->sin_addr; break; - } else if ( sock.plain.sa_family == AF_INET6 ) { + } else if (sock.plain.sa_family == AF_INET6) { sock.ipv6.sin6_addr = ((struct sockaddr_in6*)addrs_left->ai_addr)->sin6_addr; break; } @@ -430,7 +448,7 @@ URIHANDLER_FUNC(mod_extforward_uri_handler) { if (addrlist != NULL ) freeaddrinfo(addrlist); #endif } - array_free(forward_array); + array_free(forward_array); /* not found */ return HANDLER_GO_ON; diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c index 75b52ad..9ce9556 100644 --- a/src/mod_fastcgi.c +++ b/src/mod_fastcgi.c @@ -162,8 +162,8 @@ typedef struct { * if host is one of the local IP adresses the * whole connection is local * - * if tcp/ip should be used host AND port have - * to be specified + * if port is not 0, and host is not specified, + * "localhost" (INADDR_LOOPBACK) is assumed. * */ buffer *host; @@ -823,12 +823,12 @@ static int fcgi_spawn_connection(server *srv, fcgi_addr_in.sin_family = AF_INET; if (buffer_is_empty(host->host)) { - fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); + fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } else { struct hostent *he; /* set a useful default */ - fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); + fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); if (NULL == (he = gethostbyname(host->host->ptr))) { @@ -858,7 +858,11 @@ static int fcgi_spawn_connection(server *srv, fcgi_addr = (struct sockaddr *) &fcgi_addr_in; buffer_copy_string(proc->connection_name, "tcp:"); - buffer_append_string_buffer(proc->connection_name, host->host); + if (!buffer_is_empty(host->host)) { + buffer_append_string_buffer(proc->connection_name, host->host); + } else { + buffer_append_string(proc->connection_name, "localhost"); + } buffer_append_string(proc->connection_name, ":"); buffer_append_long(proc->connection_name, proc->port); } @@ -1687,12 +1691,16 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h #endif } else { fcgi_addr_in.sin_family = AF_INET; - if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "converting IP address failed for", host->host, - "\nBe sure to specify an IP address here"); - - return -1; + if (!buffer_is_empty(host->host)) { + if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) { + log_error_write(srv, __FILE__, __LINE__, "sbs", + "converting IP address failed for", host->host, + "\nBe sure to specify an IP address here"); + + return -1; + } + } else { + fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); } fcgi_addr_in.sin_port = htons(proc->port); servlen = sizeof(fcgi_addr_in); @@ -1702,7 +1710,11 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h if (buffer_is_empty(proc->connection_name)) { /* on remote spawing we have to set the connection-name now */ buffer_copy_string(proc->connection_name, "tcp:"); - buffer_append_string_buffer(proc->connection_name, host->host); + if (!buffer_is_empty(host->host)) { + buffer_append_string_buffer(proc->connection_name, host->host); + } else { + buffer_append_string(proc->connection_name, "localhost"); + } buffer_append_string(proc->connection_name, ":"); buffer_append_long(proc->connection_name, proc->port); } @@ -2045,12 +2057,9 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { s = get_http_version_name(con->request.http_version); FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)),con) -#ifdef USE_OPENSSL - if (srv_sock->is_ssl) { + if (srv_sock->is_ssl || srv_sock->is_proxy_ssl) { FCGI_ENV_ADD_CHECK(fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")),con) } -#endif - FCGI_ENV_ADD_CHECK(fcgi_env_add_request_headers(srv, con, p), con); @@ -2343,7 +2352,7 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p /* no header */ buffer_free(packet->b); - log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header too small"); + log_error_write(srv, __FILE__, __LINE__, "sdsds", "FastCGI: header too small:", packet->b->used, "bytes <", sizeof(FCGI_Header), "bytes"); return -1; } @@ -2530,15 +2539,28 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { } if (host->allow_xsendfile && - NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) { + (NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file")) + || NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-Sendfile")))) { stat_cache_entry *sce; if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) { + data_string *dcls = data_string_init(); /* found */ - http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size); hctx->send_content_body = 0; /* ignore the content */ joblist_append(srv, con); + + buffer_copy_string_len(dcls->key, "Content-Length", sizeof("Content-Length")-1); + buffer_copy_long(dcls->value, sce->st.st_size); + dcls = (data_string*) array_replace(con->response.headers, (data_unset *)dcls); + if (dcls) dcls->free((data_unset*)dcls); + + con->parsed_response |= HTTP_CONTENT_LENGTH; + con->response.content_length = sce->st.st_size; + } else { + log_error_write(srv, __FILE__, __LINE__, "sb", + "send-file error: couldn't get stat_cache entry for:", + ds->value); } } @@ -2719,9 +2741,14 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { int ret; - /* sanity check */ + /* sanity check: + * - host != NULL + * - either: + * - tcp socket (do not check host->host->uses, as it may be not set which means INADDR_LOOPBACK) + * - unix socket + */ if (!host || - ((!host->host->used || !host->port) && !host->unixsocket->used)) { + (!host->port && !host->unixsocket->used)) { log_error_write(srv, __FILE__, __LINE__, "sxddd", "write-req: error", host, @@ -3456,8 +3483,9 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i if (s_len < ct_len) continue; /* check extension in the form "/fcgi_pattern" */ - if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { - break; + if (*(extension->key->ptr) == '/') { + if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) + break; } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) { /* check extension in the form ".fcg" */ break; @@ -3473,7 +3501,7 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i for (k = 0; k < extension->used; k++) { host = extension->hosts[k]; - /* we should have at least one proc that can do somthing */ + /* we should have at least one proc that can do something */ if (host->active_procs == 0) { host = NULL; diff --git a/src/mod_proxy.c b/src/mod_proxy.c index c4ac15f..4d8ecdd 100644 --- a/src/mod_proxy.c +++ b/src/mod_proxy.c @@ -1093,15 +1093,17 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p if (s_len < ct_len) continue; /* check extension in the form "/proxy_pattern" */ - if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { - if (s_len > ct_len + 1) { - char *pi_offset; + if (*(extension->key->ptr) == '/') { + if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { + if (s_len > ct_len + 1) { + char *pi_offset; - if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) { - path_info_offset = pi_offset - fn->ptr; + if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) { + path_info_offset = pi_offset - fn->ptr; + } } + break; } - break; } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) { /* check extension in the form ".fcg" */ break; @@ -1203,7 +1205,7 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p } /* didn't found a higher id, wrap to the start */ - if (ndx != -1 && max_usage != INT_MAX) { + if (ndx == -1 && max_usage != INT_MAX) { ndx = max_usage; } diff --git a/src/mod_scgi.c b/src/mod_scgi.c index bc487c5..b7287ba 100644 --- a/src/mod_scgi.c +++ b/src/mod_scgi.c @@ -1057,6 +1057,9 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { /* a local socket + self spawning */ size_t pno; + /* HACK: just to make sure the adaptive spawing is disabled */ + df->min_procs = df->max_procs; + if (df->min_procs > df->max_procs) df->max_procs = df->min_procs; if (df->max_load_per_proc < 1) df->max_load_per_proc = 0; @@ -2694,8 +2697,9 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i if (s_len < ct_len) continue; /* check extension in the form "/scgi_pattern" */ - if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { - break; + if (*(extension->key->ptr) == '/') { + if (strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) + break; } else if (0 == strncmp(fn->ptr + s_len - ct_len, extension->key->ptr, ct_len)) { /* check extension in the form ".fcg" */ break; diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c index 08a0554..57e407f 100644 --- a/src/mod_secure_download.c +++ b/src/mod_secure_download.c @@ -245,7 +245,8 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) { /* timed-out */ if (srv->cur_ts - ts > p->conf.timeout || srv->cur_ts - ts < -p->conf.timeout) { - con->http_status = 408; + /* "Gone" as the url will never be valid again instead of "408 - Timeout" where the request may be repeated */ + con->http_status = 410; return HANDLER_FINISHED; } diff --git a/src/mod_ssi.c b/src/mod_ssi.c index e706e8f..d02d998 100644 --- a/src/mod_ssi.c +++ b/src/mod_ssi.c @@ -36,6 +36,11 @@ #include <sys/filio.h> #endif +#include "etag.h" + +/* The newest modified time of included files for include statement */ +static volatile time_t include_file_last_mtime = 0; + /* init the plugin data */ INIT_FUNC(mod_ssi_init) { plugin_data *p; @@ -575,6 +580,11 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, break; case SSI_INCLUDE: chunkqueue_append_file(con->write_queue, p->stat_fn, 0, st.st_size); + + /* Keep the newest mtime of included files */ + if (st.st_mtime > include_file_last_mtime) + include_file_last_mtime = st.st_mtime; + break; } } else { @@ -718,50 +728,57 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, /* father */ int status; ssize_t r; + int was_interrupted = 0; close(from_exec_fds[1]); /* wait for the client to end */ /* - * FIXME: if we get interrupted by a SIGCHILD we count this as error - * - * for now it only happened on OpenBSD. - * - * that leads to zombies and missing output + * OpenBSD and Solaris send a EINTR on SIGCHILD even if we ignore it */ - if (-1 == waitpid(pid, &status, 0)) { - log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno)); - } else if (WIFEXITED(status)) { - int toread; - /* read everything from client and paste it into the output */ - - while(1) { - if (ioctl(from_exec_fds[0], FIONREAD, &toread)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "unexpected end-of-file (perhaps the ssi-exec process died)"); - return -1; + do { + if (-1 == waitpid(pid, &status, 0)) { + if (errno == EINTR) { + was_interrupted++; + } else { + was_interrupted = 0; + log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno)); } - - if (toread > 0) { - b = chunkqueue_get_append_buffer(con->write_queue); - - buffer_prepare_copy(b, toread + 1); - - if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) { - /* read failed */ - break; + } else if (WIFEXITED(status)) { + int toread; + /* read everything from client and paste it into the output */ + was_interrupted = 0; + + while(1) { + if (ioctl(from_exec_fds[0], FIONREAD, &toread)) { + log_error_write(srv, __FILE__, __LINE__, "s", + "unexpected end-of-file (perhaps the ssi-exec process died)"); + return -1; + } + + if (toread > 0) { + b = chunkqueue_get_append_buffer(con->write_queue); + + buffer_prepare_copy(b, toread + 1); + + if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) { + /* read failed */ + break; + } else { + b->used = r; + b->ptr[b->used++] = '\0'; + } } else { - b->used = r; - b->ptr[b->used++] = '\0'; + break; } - } else { - break; } + } else { + was_interrupted = 0; + log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally"); } - } else { - log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally"); - } + } while (was_interrupted > 0 && was_interrupted < 4); /* if waitpid() gets interrupted, retry, but max 4 times */ + close(from_exec_fds[0]); break; @@ -912,6 +929,9 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) build_ssi_cgi_vars(srv, con, p); p->if_is_false = 0; + /* Reset the modified time of included files */ + include_file_last_mtime = 0; + if (-1 == stream_open(&s, con->physical.path)) { log_error_write(srv, __FILE__, __LINE__, "sb", "stream-open: ", con->physical.path); @@ -1010,6 +1030,30 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); + { + /* Generate "ETag" & "Last-Modified" headers */ + + stat_cache_entry *sce = NULL; + time_t lm_time = 0; + buffer *mtime = NULL; + + stat_cache_get_entry(srv, con, con->physical.path, &sce); + + etag_mutate(con->physical.etag, sce->etag); + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag)); + + if (sce->st.st_mtime > include_file_last_mtime) + lm_time = sce->st.st_mtime; + else + lm_time = include_file_last_mtime; + + mtime = strftime_cache_get(srv, lm_time); + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); + } + + /* Reset the modified time of included files */ + include_file_last_mtime = 0; + /* reset physical.path */ buffer_reset(con->physical.path); diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c index 59fafee..0ffa901 100644 --- a/src/mod_staticfile.c +++ b/src/mod_staticfile.c @@ -352,7 +352,7 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { size_t k; int s_len; stat_cache_entry *sce = NULL; - buffer *mtime; + buffer *mtime = NULL; data_string *ds; int allow_caching = 1; @@ -450,7 +450,9 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { } } - response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes")); + if (con->conf.range_requests) { + response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes")); + } if (allow_caching) { if (p->conf.etags_used && con->etag_flags != 0 && !buffer_is_empty(sce->etag)) { @@ -483,7 +485,23 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { /* if the value is the same as our ETag, we do a Range-request, * otherwise a full 200 */ - if (!buffer_is_equal(ds->value, con->physical.etag)) { + if (ds->value->ptr[0] == '"') { + /** + * client wants a ETag + */ + if (!con->physical.etag) { + do_range_request = 0; + } else if (!buffer_is_equal(ds->value, con->physical.etag)) { + do_range_request = 0; + } + } else if (!mtime) { + /** + * we don't have a Last-Modified and can match the If-Range: + * + * sending all + */ + do_range_request = 0; + } else if (!buffer_is_equal(ds->value, mtime)) { do_range_request = 0; } } diff --git a/src/mod_status.c b/src/mod_status.c index 80c0040..028cbc7 100644 --- a/src/mod_status.c +++ b/src/mod_status.c @@ -560,6 +560,8 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c double avg; time_t ts; char buf[32]; + unsigned int k; + unsigned int l; b = chunkqueue_get_append_buffer(con->write_queue); @@ -588,6 +590,22 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c buffer_append_long(b, srv->conns->used); BUFFER_APPEND_STRING_CONST(b, "\n"); + BUFFER_APPEND_STRING_CONST(b, "IdleServers: "); + buffer_append_long(b, srv->conns->size - srv->conns->used); + BUFFER_APPEND_STRING_CONST(b, "\n"); + + /* output scoreboard */ + BUFFER_APPEND_STRING_CONST(b, "Scoreboard: "); + for (k = 0; k < srv->conns->used; k++) { + connection *c = srv->conns->ptr[k]; + const char *state = connection_get_short_state(c->state); + buffer_append_string_len(b, state, 1); + } + for (l = 0; l < srv->conns->size - srv->conns->used; l++) { + BUFFER_APPEND_STRING_CONST(b, "_"); + } + BUFFER_APPEND_STRING_CONST(b, "\n"); + /* set text/plain output */ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain")); diff --git a/src/mod_userdir.c b/src/mod_userdir.c index 2fef0f2..e664bf2 100644 --- a/src/mod_userdir.c +++ b/src/mod_userdir.c @@ -21,6 +21,7 @@ typedef struct { array *include_user; buffer *path; buffer *basepath; + unsigned short letterhomes; } plugin_config; typedef struct { @@ -87,6 +88,7 @@ SETDEFAULTS_FUNC(mod_userdir_set_defaults) { { "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ + { "userdir.letterhomes", NULL, T_CONFIG_BOOLEAN,T_CONFIG_SCOPE_CONNECTION }, /* 4 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; @@ -102,11 +104,13 @@ SETDEFAULTS_FUNC(mod_userdir_set_defaults) { s->include_user = array_init(); s->path = buffer_init(); s->basepath = buffer_init(); + s->letterhomes = 0; cv[0].destination = s->path; cv[1].destination = s->exclude_user; cv[2].destination = s->include_user; cv[3].destination = s->basepath; + cv[4].destination = &(s->letterhomes); p->config_storage[i] = s; @@ -128,6 +132,7 @@ static int mod_userdir_patch_connection(server *srv, connection *con, plugin_dat PATCH(exclude_user); PATCH(include_user); PATCH(basepath); + PATCH(letterhomes); /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { @@ -149,6 +154,8 @@ static int mod_userdir_patch_connection(server *srv, connection *con, plugin_dat PATCH(include_user); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) { PATCH(basepath); + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.letterhomes"))) { + PATCH(letterhomes); } } } @@ -170,6 +177,11 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) { mod_userdir_patch_connection(srv, con, p); + /* enforce the userdir.path to be set in the config, ugly fix for #1587; + * should be replaced with a clean .enabled option in 1.5 + */ + if (p->conf.path->used == 0) return HANDLER_GO_ON; + uri_len = con->uri.path->used - 1; /* /~user/foo.html -> /home/user/public_html/foo.html */ @@ -253,6 +265,10 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) { buffer_copy_string_buffer(p->temp_path, p->conf.basepath); BUFFER_APPEND_SLASH(p->temp_path); + if (p->conf.letterhomes) { + buffer_append_string_len(p->temp_path, p->username->ptr, 1); + BUFFER_APPEND_SLASH(p->temp_path); + } buffer_append_string_buffer(p->temp_path, p->username); } BUFFER_APPEND_SLASH(p->temp_path); diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c index 6586efb..5f01812 100644 --- a/src/network_linux_sendfile.c +++ b/src/network_linux_sendfile.c @@ -162,6 +162,7 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, switch (errno) { case EAGAIN: case EINTR: + /* ok, we can't send more, let's try later again */ r = 0; break; case EPIPE: @@ -172,9 +173,7 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, "sendfile failed:", strerror(errno), fd); return -1; } - } - - if (r == 0) { + } else if (r == 0) { int oerrno = errno; /* We got an event to write but we wrote nothing * diff --git a/src/network_openssl.c b/src/network_openssl.c index e6df35e..ff9fb97 100644 --- a/src/network_openssl.c +++ b/src/network_openssl.c @@ -58,31 +58,6 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN); } - /* evil hack for opera 9.01 and 8.54 and earlier - * - * opera hangs if the trainling 0\r\n\r\n is in a seperate SSL-packet - * - * we try to move the packet into the previous mem-chunk if possible - */ - if ((cq == con->write_queue) && - (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) && - (con->file_finished)) { - /* merge the last chunk into the previous chunk */ - - for(c = cq->first; c && c->next && c->next->next; c = c->next); - - if (c && - c->type == MEM_CHUNK && - c->next && - c->next->type == MEM_CHUNK && - c->next->mem->used == sizeof("0\r\n\r\n") && - 0 == strcmp(c->next->mem->ptr, "0\r\n\r\n")) { - buffer_append_string_buffer(c->mem, c->next->mem); - - c->next->mem->used = 0; - } - } - for(c = cq->first; c; c = c->next) { int chunk_finished = 0; @@ -128,6 +103,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu /* no, but we have errno */ switch(errno) { case EPIPE: + case ECONNRESET: return -2; default: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", @@ -230,6 +206,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu /* no, but we have errno */ switch(errno) { case EPIPE: + case ECONNRESET: return -2; default: log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", diff --git a/src/response.c b/src/response.c index b8775f0..bc2bdd1 100644 --- a/src/response.c +++ b/src/response.c @@ -19,6 +19,7 @@ #include "stat_cache.h" #include "chunk.h" +#include "configfile.h" #include "connections.h" #include "plugin.h" @@ -59,7 +60,8 @@ int http_response_write_header(server *srv, connection *con) { ds = (data_string *)con->response.headers->data[i]; if (ds->value->used && ds->key->used && - 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) { + 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) && + 0 != strncmp(ds->key->ptr, "X-Sendfile", sizeof("X-Sendfile") - 1)) { if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1; if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1; @@ -149,6 +151,9 @@ handler_t http_response_prepare(server *srv, connection *con) { * * */ + config_cond_cache_reset(srv, con); + config_setup_connection(srv, con); // Perhaps this could be removed at other places. + if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "run condition"); } @@ -180,11 +185,13 @@ handler_t http_response_prepare(server *srv, connection *con) { buffer_copy_string_buffer(con->uri.authority, con->request.http_host); buffer_to_lower(con->uri.authority); + config_patch_connection(srv, con, COMP_HTTP_SCHEME); /* Scheme: */ config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */ - config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */ + config_patch_connection(srv, con, COMP_HTTP_REMOTE_IP); /* Client-IP */ config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */ - config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */ + config_patch_connection(srv, con, COMP_HTTP_USER_AGENT);/* User-Agent: */ config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */ + config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */ /** their might be a fragment which has to be cut away */ if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) { @@ -270,7 +277,7 @@ handler_t http_response_prepare(server *srv, connection *con) { */ config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */ - config_patch_connection(srv, con, COMP_HTTP_QUERYSTRING); /* HTTPqs */ + config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */ /* do we have to downgrade to 1.0 ? */ if (!con->conf.allow_http11) { @@ -547,17 +554,14 @@ handler_t http_response_prepare(server *srv, connection *con) { buffer_copy_string_buffer(srv->tmp_buf, con->physical.path); do { - struct stat st; - if (slash) { buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr); } else { buffer_copy_string_buffer(con->physical.path, srv->tmp_buf); } - if (0 == stat(con->physical.path->ptr, &(st)) && - S_ISREG(st.st_mode)) { - found = 1; + if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { + found = S_ISREG(sce->st.st_mode); break; } @@ -589,6 +593,20 @@ handler_t http_response_prepare(server *srv, connection *con) { return HANDLER_FINISHED; } +#ifdef HAVE_LSTAT + if ((sce->is_symlink != 0) && !con->conf.follow_symlink) { + con->http_status = 403; + + if (con->conf.log_request_handling) { + log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); + log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); + } + + buffer_reset(con->physical.path); + return HANDLER_FINISHED; + }; +#endif + /* we have a PATHINFO */ if (pathinfo) { buffer_copy_string(con->request.pathinfo, pathinfo); @@ -631,8 +649,14 @@ handler_t http_response_prepare(server *srv, connection *con) { /* if we are still here, no one wanted the file, status 403 is ok I think */ - if (con->mode == DIRECT) { - con->http_status = 403; + if (con->mode == DIRECT && con->http_status == 0) { + switch (con->request.http_method) { + case HTTP_METHOD_OPTIONS: + con->http_status = 200; + break; + default: + con->http_status = 403; + } return HANDLER_FINISHED; } diff --git a/src/server.c b/src/server.c index 132eb32..585a973 100644 --- a/src/server.c +++ b/src/server.c @@ -697,9 +697,6 @@ int main (int argc, char **argv) { } } - /* #372: solaris need some fds extra for devpoll */ - if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10; - if (srv->event_handler == FDEVENT_HANDLER_SELECT) { srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200; } else { @@ -759,6 +756,19 @@ int main (int argc, char **argv) { return -1; } +#ifdef HAVE_PWD_H + /* + * Change group before chroot, when we have access + * to /etc/group + * */ + if (srv->srvconf.groupname->used) { + setgid(grp->gr_gid); + setgroups(0, NULL); + if (srv->srvconf.username->used) { + initgroups(srv->srvconf.username->ptr, grp->gr_gid); + } + } +#endif #ifdef HAVE_CHROOT if (srv->srvconf.changeroot->used) { tzset(); @@ -775,15 +785,7 @@ int main (int argc, char **argv) { #endif #ifdef HAVE_PWD_H /* drop root privs */ - if (srv->srvconf.groupname->used) { - setgid(grp->gr_gid); - setgroups(0, NULL); - } - if (srv->srvconf.username->used) { - if (srv->srvconf.groupname->used) { - initgroups(srv->srvconf.username->ptr, grp->gr_gid); - } setuid(pwd->pw_uid); } #endif @@ -891,6 +893,17 @@ int main (int argc, char **argv) { pid_fd = -1; } + // Close stderr ASAP in the child process to make sure that nothing + // is being written to that fd which may not be valid anymore. + if (-1 == log_error_open(srv)) { + log_error_write(srv, __FILE__, __LINE__, "s", "Opening errorlog failed. Going down."); + + plugins_free(srv); + network_close(srv); + server_free(srv); + return -1; + } + if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); @@ -941,15 +954,7 @@ int main (int argc, char **argv) { return -1; } - if (-1 == log_error_open(srv)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "opening errorlog failed, dying"); - plugins_free(srv); - network_close(srv); - server_free(srv); - return -1; - } #ifdef HAVE_SIGACTION diff --git a/src/spawn-fcgi.c b/src/spawn-fcgi.c index 8237e79..60e02bd 100644 --- a/src/spawn-fcgi.c +++ b/src/spawn-fcgi.c @@ -37,7 +37,7 @@ typedef int socklen_t; #endif #ifdef HAVE_SYS_UN_H -int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const char *unixsocket, int child_count, int pid_fd, int nofork) { +int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned short port, const char *unixsocket, int child_count, int pid_fd, int nofork) { int fcgi_fd; int socket_type, status; struct timeval tv = { 0, 100 * 1000 }; @@ -48,6 +48,9 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const socklen_t servlen; + pid_t child; + int val; + if (child_count < 2) { child_count = 5; } @@ -71,6 +74,25 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const #endif socket_type = AF_UNIX; fcgi_addr = (struct sockaddr *) &fcgi_addr_un; + + /* check if some backend is listening on the socket + * as if we delete the socket-file and rebind there will be no "socket already in use" error + */ + if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { + fprintf(stderr, "%s.%d\n", + __FILE__, __LINE__); + return -1; + } + + if (-1 != connect(fcgi_fd, fcgi_addr, servlen)) { + fprintf(stderr, "%s.%d: socket is already used, can't spawn\n", + __FILE__, __LINE__); + return -1; + } + + /* cleanup previous socket if it exists */ + unlink(unixsocket); + close(fcgi_fd); } else { fcgi_addr_in.sin_family = AF_INET; if (addr != NULL) { @@ -85,144 +107,128 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const fcgi_addr = (struct sockaddr *) &fcgi_addr_in; } + /* open socket */ if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { fprintf(stderr, "%s.%d\n", __FILE__, __LINE__); return -1; } - if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { - /* server is not up, spawn in */ - pid_t child; - int val; + val = 1; + if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { + fprintf(stderr, "%s.%d\n", + __FILE__, __LINE__); + return -1; + } - if (unixsocket) unlink(unixsocket); + /* create socket */ + if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { + fprintf(stderr, "%s.%d: bind failed: %s\n", + __FILE__, __LINE__, + strerror(errno)); + return -1; + } - close(fcgi_fd); + if (-1 == listen(fcgi_fd, 1024)) { + fprintf(stderr, "%s.%d: fd = -1\n", + __FILE__, __LINE__); + return -1; + } - /* reopen socket */ - if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - fprintf(stderr, "%s.%d\n", - __FILE__, __LINE__); - return -1; - } + if (!nofork) { + child = fork(); + } else { + child = 0; + } - val = 1; - if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { - fprintf(stderr, "%s.%d\n", - __FILE__, __LINE__); - return -1; - } + switch (child) { + case 0: { + char cgi_childs[64]; - /* create socket */ - if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { - fprintf(stderr, "%s.%d: bind failed: %s\n", - __FILE__, __LINE__, - strerror(errno)); - return -1; - } + int i = 0; - if (-1 == listen(fcgi_fd, 1024)) { - fprintf(stderr, "%s.%d: fd = -1\n", - __FILE__, __LINE__); - return -1; - } + /* is safe as we limit to 256 childs */ + sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); - if (!nofork) { - child = fork(); - } else { - child = 0; + if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { + close(FCGI_LISTENSOCK_FILENO); + dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); + close(fcgi_fd); } - switch (child) { - case 0: { - char cgi_childs[64]; - char *b; - - int i = 0; - - /* is save as we limit to 256 childs */ - sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); + /* we don't need the client socket */ + for (i = 3; i < 256; i++) { + close(i); + } - if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { - close(FCGI_LISTENSOCK_FILENO); - dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); - close(fcgi_fd); - } + /* create environment */ - /* we don't need the client socket */ - for (i = 3; i < 256; i++) { - close(i); - } + putenv(cgi_childs); - /* create environment */ + /* fork and replace shell */ + if (appArgv) { + execv(appArgv[0], appArgv); - putenv(cgi_childs); - - /* fork and replace shell */ - b = malloc(strlen("exec ") + strlen(appPath) + 1); + } else { + char *b = malloc(strlen("exec ") + strlen(appPath) + 1); strcpy(b, "exec "); strcat(b, appPath); /* exec the cgi */ execl("/bin/sh", "sh", "-c", b, (char *)NULL); + } - exit(errno); + exit(errno); + + break; + } + case -1: + /* error */ + break; + default: + /* father */ + + /* wait */ + select(0, NULL, NULL, NULL, &tv); + + switch (waitpid(child, &status, WNOHANG)) { + case 0: + fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", + __FILE__, __LINE__, + child); + + /* write pid file */ + if (pid_fd != -1) { + /* assume a 32bit pid_t */ + char pidbuf[12]; + + snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); + + write(pid_fd, pidbuf, strlen(pidbuf)); + close(pid_fd); + pid_fd = -1; + } break; - } case -1: - /* error */ break; default: - /* father */ - - /* wait */ - select(0, NULL, NULL, NULL, &tv); - - switch (waitpid(child, &status, WNOHANG)) { - case 0: - fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", + if (WIFEXITED(status)) { + fprintf(stderr, "%s.%d: child exited with: %d, %s\n", + __FILE__, __LINE__, + WEXITSTATUS(status), strerror(WEXITSTATUS(status))); + } else if (WIFSIGNALED(status)) { + fprintf(stderr, "%s.%d: child signaled: %d\n", + __FILE__, __LINE__, + WTERMSIG(status)); + } else { + fprintf(stderr, "%s.%d: child died somehow: %d\n", __FILE__, __LINE__, - child); - - /* write pid file */ - if (pid_fd != -1) { - /* assume a 32bit pid_t */ - char pidbuf[12]; - - snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); - - write(pid_fd, pidbuf, strlen(pidbuf)); - close(pid_fd); - pid_fd = -1; - } - - break; - case -1: - break; - default: - if (WIFEXITED(status)) { - fprintf(stderr, "%s.%d: child exited with: %d, %s\n", - __FILE__, __LINE__, - WEXITSTATUS(status), strerror(WEXITSTATUS(status))); - } else if (WIFSIGNALED(status)) { - fprintf(stderr, "%s.%d: child signaled: %d\n", - __FILE__, __LINE__, - WTERMSIG(status)); - } else { - fprintf(stderr, "%s.%d: child died somehow: %d\n", - __FILE__, __LINE__, - status); - } + status); } - - break; } - } else { - fprintf(stderr, "%s.%d: socket is already used, can't spawn\n", - __FILE__, __LINE__); - return -1; + + break; } close(fcgi_fd); @@ -239,9 +245,12 @@ void show_version () { } void show_help () { - char *b = "spawn-fcgi" "-" PACKAGE_VERSION \ -" - spawns fastcgi processes\n" \ -"usage:\n" \ + char *b = \ +"Usage: spawn-fcgi [options] -- <fcgiapp> [fcgi app arguments]\n" \ +"\n" \ +"spawn-fcgi v" PACKAGE_VERSION " - spawns fastcgi processes\n" \ +"\n" \ +"Options:\n" \ " -f <fcgiapp> filename of the fcgi-application\n" \ " -a <addr> bind to ip address\n" \ " -p <port> bind to tcp-port\n" \ @@ -264,6 +273,7 @@ int main(int argc, char **argv) { char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, *groupname = NULL, *unixsocket = NULL, *pid_file = NULL, *addr = NULL; + char **fcgi_app_argv = { NULL }; unsigned short port = 0; int child_count = 5; int i_am_root, o; @@ -274,10 +284,10 @@ int main(int argc, char **argv) { i_am_root = (getuid() == 0); - while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) { + while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) { switch(o) { case 'f': fcgi_app = optarg; break; - case 'a': addr = optarg;/* ip addr */ break; + case 'a': addr = optarg;/* ip addr */ break; case 'p': port = strtol(optarg, NULL, 10);/* port */ break; case 'C': child_count = strtol(optarg, NULL, 10);/* */ break; case 's': unixsocket = optarg; /* unix-domain socket */ break; @@ -294,7 +304,11 @@ int main(int argc, char **argv) { } } - if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) { + if (optind < argc) { + fcgi_app_argv = &argv[optind]; + } + + if ((fcgi_app == NULL && fcgi_app_argv == NULL) || (port == 0 && unixsocket == NULL)) { show_help(); return -1; } @@ -404,6 +418,18 @@ int main(int argc, char **argv) { } } + /* + * Change group before chroot, when we have access + * to /etc/group + */ + if (groupname) { + setgid(grp->gr_gid); + setgroups(0, NULL); + if (username) { + initgroups(username, grp->gr_gid); + } + } + if (changeroot) { if (-1 == chroot(changeroot)) { fprintf(stderr, "%s.%d: %s %s\n", @@ -420,18 +446,12 @@ int main(int argc, char **argv) { } /* drop root privs */ - if (groupname) { - setgid(grp->gr_gid); - } if (username) { - if (groupname) { - initgroups(username, grp->gr_gid); - } setuid(pwd->pw_uid); } } - return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork); + return fcgi_spawn_connection(fcgi_app, fcgi_app_argv, addr, port, unixsocket, child_count, pid_fd, nofork); } #else int main() { diff --git a/src/stream.c b/src/stream.c index aac6cf7..d249647 100644 --- a/src/stream.c +++ b/src/stream.c @@ -64,6 +64,7 @@ int stream_open(stream *f, buffer *fn) { NULL); if (!mh) { +/* LPVOID lpMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | @@ -73,7 +74,7 @@ int stream_open(stream *f, buffer *fn) { MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); - +*/ return -1; } diff --git a/tests/LightyTest.pm b/tests/LightyTest.pm index 33eca61..6e3f5c2 100755 --- a/tests/LightyTest.pm +++ b/tests/LightyTest.pm @@ -72,7 +72,7 @@ sub stop_proc { if (defined $pid) { kill('TERM',$pid) or return -1; - select(undef, undef, undef, 0.01); + select(undef, undef, undef, 0.1); } return 0; @@ -92,6 +92,8 @@ sub start_proc { unlink($self->{LIGHTTPD_PIDFILE}); if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') { system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &"); + } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'truss') { + system("/usr/dtrctkit/bin/dtruss -d -e ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." 2> strace &"); } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') { system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --log-file=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &"); } else { diff --git a/tests/Makefile.am b/tests/Makefile.am index dfdf06b..c353730 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -31,14 +31,20 @@ CONFS=fastcgi-10.conf \ core-response.t \ core-keepalive.t \ core.t \ + mod-proxy.t \ + proxy.conf \ + mod-secdownload.t \ mod-access.t \ mod-auth.t \ mod-cgi.t \ mod-compress.t \ mod-fastcgi.t \ mod-redirect.t \ - mod-userdir.t \ mod-rewrite.t \ + mod-userdir.t \ + env-variables.t \ + env-variables.conf \ + symlink.t \ request.t \ mod-ssi.t \ LightyTest.pm \ @@ -49,12 +55,12 @@ CONFS=fastcgi-10.conf \ core-404-handler.t \ 404-handler.conf - TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) EXTRA_DIST=wrapper.sh lighttpd.conf \ lighttpd.user \ lighttpd.htpasswd \ + SConscript \ $(CONFS) \ $(TESTS) diff --git a/tests/Makefile.in b/tests/Makefile.in index 429efd1..4a792b1 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -244,14 +244,20 @@ CONFS = fastcgi-10.conf \ core-response.t \ core-keepalive.t \ core.t \ + mod-proxy.t \ + proxy.conf \ + mod-secdownload.t \ mod-access.t \ mod-auth.t \ mod-cgi.t \ mod-compress.t \ mod-fastcgi.t \ mod-redirect.t \ - mod-userdir.t \ mod-rewrite.t \ + mod-userdir.t \ + env-variables.t \ + env-variables.conf \ + symlink.t \ request.t \ mod-ssi.t \ LightyTest.pm \ @@ -266,6 +272,7 @@ TESTS_ENVIRONMENT = $(srcdir)/wrapper.sh $(srcdir) $(top_builddir) EXTRA_DIST = wrapper.sh lighttpd.conf \ lighttpd.user \ lighttpd.htpasswd \ + SConscript \ $(CONFS) \ $(TESTS) diff --git a/tests/SConscript b/tests/SConscript new file mode 100644 index 0000000..07c76c9 --- /dev/null +++ b/tests/SConscript @@ -0,0 +1,45 @@ +Import('env') + +tests = Split('prepare.sh \ + run-tests.pl \ + cleanup.sh') + +extra_dist = Split('fastcgi-10.conf \ + fastcgi-auth.conf \ + fastcgi-responder.conf \ + fastcgi-13.conf \ + bug-06.conf \ + bug-12.conf \ + core-var-include.t \ + var-include.conf \ + var-include-sub.conf \ + condition.conf \ + core-condition.t \ + core-request.t \ + core-response.t \ + core-keepalive.t \ + core.t \ + mod-access.t \ + mod-auth.t \ + mod-cgi.t \ + mod-compress.t \ + mod-fastcgi.t \ + mod-redirect.t \ + mod-userdir.t \ + mod-rewrite.t \ + request.t \ + mod-ssi.t \ + LightyTest.pm \ + mod-setenv.t') + +t = env.Command('foo1', 'prepare.sh', '(cd ./tests/; ./prepare.sh; cd ..)') +t += env.Command('foo2', 'run-tests.pl', '( cd ./tests/; SHELL=/bin/sh ./run-tests.pl; cd ..)') +t += env.Command('foo3', 'cleanup.sh', '(cd ./tests/; ./cleanup.sh; cd ..)') + +if env['LIBFCGI']: + fcgis = [] + fcgis += env.Program("fcgi-auth", "fcgi-auth.c", LIBS=env['LIBFCGI']) + fcgis += env.Program("fcgi-responder", "fcgi-responder.c", LIBS=env['LIBFCGI']) + env.Depends(t, fcgis) + +env.Alias('check', t ) diff --git a/tests/cachable.t b/tests/cachable.t index 0d1e1b4..605a68f 100755 --- a/tests/cachable.t +++ b/tests/cachable.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/core-404-handler.t b/tests/core-404-handler.t index b9c5df1..599ade2 100644 --- a/tests/core-404-handler.t +++ b/tests/core-404-handler.t @@ -10,10 +10,10 @@ # 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; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/core-condition.t b/tests/core-condition.t index 96b05d8..53919a1 100755 --- a/tests/core-condition.t +++ b/tests/core-condition.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/core-keepalive.t b/tests/core-keepalive.t index 8d91b4c..b4f51f9 100755 --- a/tests/core-keepalive.t +++ b/tests/core-keepalive.t @@ -1,10 +1,9 @@ #!/usr/bin/env perl - BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/core-request.t b/tests/core-request.t index fc6e25f..a24777f 100755 --- a/tests/core-request.t +++ b/tests/core-request.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/core-response.t b/tests/core-response.t index c7a158c..ff2cf1d 100755 --- a/tests/core-response.t +++ b/tests/core-response.t @@ -1,10 +1,9 @@ #!/usr/bin/env perl - BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/core-var-include.t b/tests/core-var-include.t index b26790f..8161751 100755 --- a/tests/core-var-include.t +++ b/tests/core-var-include.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/core.t b/tests/core.t index 6de933c..b196666 100755 --- a/tests/core.t +++ b/tests/core.t @@ -1,10 +1,9 @@ #!/usr/bin/env perl - BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/env-variables.conf b/tests/env-variables.conf new file mode 100644 index 0000000..043e788 --- /dev/null +++ b/tests/env-variables.conf @@ -0,0 +1 @@ +server.document-root = env.CWD diff --git a/tests/env-variables.t b/tests/env-variables.t new file mode 100644 index 0000000..ee48ee9 --- /dev/null +++ b/tests/env-variables.t @@ -0,0 +1,21 @@ +#!/usr/bin/perl +BEGIN { + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; +} + +use strict; +use IO::Socket; +use Test::More tests => 2; +use LightyTest; + +my $tf = LightyTest->new(); +$tf->{CONFIGFILE} = 'env-variables.conf'; + +TODO: { + local $TODO = 'we still crash on undefined environment variables'; + ok($tf->start_proc == 0, "Starting lighttpd"); + ok($tf->stop_proc == 0, "Stopping lighttpd"); +}; diff --git a/tests/fcgi-auth.c b/tests/fcgi-auth.c index bb7ae69..26bbd0f 100644 --- a/tests/fcgi-auth.c +++ b/tests/fcgi-auth.c @@ -1,4 +1,6 @@ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif #ifdef HAVE_FASTCGI_FASTCGI_H #include <fastcgi/fcgi_stdio.h> #else diff --git a/tests/fcgi-responder.c b/tests/fcgi-responder.c index 9270295..721c2ce 100644 --- a/tests/fcgi-responder.c +++ b/tests/fcgi-responder.c @@ -1,4 +1,6 @@ +#ifdef HAVE_CONFIG_H #include "config.h" +#endif #ifdef HAVE_FASTCGI_FASTCGI_H #include <fastcgi/fcgi_stdio.h> #else diff --git a/tests/lowercase.t b/tests/lowercase.t index b9ee8e8..f6f6f2c 100755 --- a/tests/lowercase.t +++ b/tests/lowercase.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/mod-access.t b/tests/mod-access.t index 82275df..58c01ac 100755 --- a/tests/mod-access.t +++ b/tests/mod-access.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/mod-auth.t b/tests/mod-auth.t index cfeb042..475a5f6 100755 --- a/tests/mod-auth.t +++ b/tests/mod-auth.t @@ -1,14 +1,14 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # 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 => 13; +use Test::More tests => 14; use LightyTest; my $tf = LightyTest->new(); @@ -48,6 +48,16 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (des)'); +$t->{REQUEST} = ( <<EOF +GET /server-config HTTP/1.0 +Host: auth-htpasswd.example.org +Authorization: basic ZGVzOmRlcw== +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf->handle_http($t) == 0, 'Basic-Auth: Valid Auth-token - htpasswd (des) (lowercase)'); + + SKIP: { skip "no md5 for crypt under cygwin", 1 if $^O eq 'cygwin'; $t->{REQUEST} = ( <<EOF diff --git a/tests/mod-cgi.t b/tests/mod-cgi.t index b89a1af..24777ca 100755 --- a/tests/mod-cgi.t +++ b/tests/mod-cgi.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/mod-compress.t b/tests/mod-compress.t index f243832..4fa66db 100755 --- a/tests/mod-compress.t +++ b/tests/mod-compress.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/mod-fastcgi.t b/tests/mod-fastcgi.t index 2c1dedb..44b4b03 100755 --- a/tests/mod-fastcgi.t +++ b/tests/mod-fastcgi.t @@ -1,13 +1,13 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; -use Test::More tests => 46; +use Test::More tests => 47; use LightyTest; my $tf = LightyTest->new(); @@ -223,7 +223,7 @@ EOF } SKIP: { - skip "no php found", 4 unless -x "/usr/bin/php-cgi"; + skip "no php found", 5 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 @@ -234,6 +234,15 @@ EOF $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; ok($tf->handle_http($t) == 0, 'FastCGI + local spawning'); + $t->{REQUEST} = ( <<EOF +HEAD /indexfile/index.php HTTP/1.0 +Host: www.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-Content-Length' => '0' } ]; + # Of course a valid content-length != 0 would be ok, but we assume for now that such one is not generated. + ok($tf->handle_http($t) == 0, 'Check for buggy content length with HEAD'); + $t->{REQUEST} = ( <<EOF GET /get-env.php?env=MAIL HTTP/1.0 Host: www.example.org diff --git a/tests/mod-proxy.t b/tests/mod-proxy.t new file mode 100755 index 0000000..b43c465 --- /dev/null +++ b/tests/mod-proxy.t @@ -0,0 +1,53 @@ +#!/usr/bin/env perl +BEGIN { + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; +} + +use strict; +use IO::Socket; +use Test::More tests => 6; +use LightyTest; + +my $tf_real = LightyTest->new(); +my $tf_proxy = LightyTest->new(); + +my $t; + +## we need two procs +## 1. the real webserver +## 2. the proxy server + +$tf_real->{PORT} = 2048; +$tf_real->{CONFIGFILE} = 'lighttpd.conf'; +$tf_real->{LIGHTTPD_PIDFILE} = $tf_real->{TESTDIR}.'/tmp/lighttpd/lighttpd.pid'; + +$tf_proxy->{PORT} = 2050; +$tf_proxy->{CONFIGFILE} = 'proxy.conf'; +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{TESTDIR}.'/tmp/lighttpd/lighttpd-proxy.pid'; + +ok($tf_real->start_proc == 0, "Starting lighttpd") or die(); + +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die(); + +$t->{REQUEST} = ( <<EOF +GET /index.html HTTP/1.0 +Host: www.example.org +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; +ok($tf_proxy->handle_http($t) == 0, 'valid request'); + +$t->{REQUEST} = ( <<EOF +GET /index.html HTTP/1.0 +Host: www.example.org +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'Apache 1.3.29' } ]; +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server'); + +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy"); + +ok($tf_real->stop_proc == 0, "Stopping lighttpd"); diff --git a/tests/mod-redirect.t b/tests/mod-redirect.t index 076a4b3..14669d9 100755 --- a/tests/mod-redirect.t +++ b/tests/mod-redirect.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/mod-rewrite.t b/tests/mod-rewrite.t index a1e2193..4de8c10 100755 --- a/tests/mod-rewrite.t +++ b/tests/mod-rewrite.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/mod-secdownload.t b/tests/mod-secdownload.t new file mode 100755 index 0000000..c8cad38 --- /dev/null +++ b/tests/mod-secdownload.t @@ -0,0 +1,79 @@ +#!/usr/bin/env perl +BEGIN { + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; +} + +use strict; +use IO::Socket; +use Test::More tests => 7; +use LightyTest; +use Digest::MD5 qw(md5_hex); + +my $tf = LightyTest->new(); +my $t; + +ok($tf->start_proc == 0, "Starting lighttpd") or die(); + +my $secret = "verysecret"; +my $f = "/index.html"; +my $thex = sprintf("%08x", time); +my $m = md5_hex($secret.$f.$thex); + +$t->{REQUEST} = ( <<EOF +GET /sec/$m/$thex$f HTTP/1.0 +Host: vvv.example.org +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; + +ok($tf->handle_http($t) == 0, 'secdownload'); + +$thex = sprintf("%08x", time - 1800); +$m = md5_hex($secret.$f.$thex); + +$t->{REQUEST} = ( <<EOF +GET /sec/$m/$thex$f HTTP/1.0 +Host: vvv.example.org +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 410 } ]; + +ok($tf->handle_http($t) == 0, 'secdownload - gone (timeout)'); + +$t->{REQUEST} = ( <<EOF +GET /sec$f HTTP/1.0 +Host: vvv.example.org +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; + +ok($tf->handle_http($t) == 0, 'secdownload - direct access'); + +$t->{REQUEST} = ( <<EOF +GET $f HTTP/1.0 +Host: www.example.org +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; + +ok($tf->handle_http($t) == 0, 'secdownload - conditional access'); + + +$f = "/noexists"; +$thex = sprintf("%08x", time); +$m = md5_hex($secret.$f.$thex); + +$t->{REQUEST} = ( <<EOF +GET /sec/$m/$thex$f HTTP/1.0 +Host: vvv.example.org +EOF + ); +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404 } ]; + +ok($tf->handle_http($t) == 0, 'secdownload - timeout'); + +ok($tf->stop_proc == 0, "Stopping lighttpd"); + diff --git a/tests/mod-setenv.t b/tests/mod-setenv.t index a5c2b7e..1e56301 100755 --- a/tests/mod-setenv.t +++ b/tests/mod-setenv.t @@ -1,10 +1,9 @@ #!/usr/bin/env perl - BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/mod-ssi.t b/tests/mod-ssi.t index a6b021b..d5d69db 100755 --- a/tests/mod-ssi.t +++ b/tests/mod-ssi.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/mod-userdir.t b/tests/mod-userdir.t index 13a8e1b..40f55ef 100755 --- a/tests/mod-userdir.t +++ b/tests/mod-userdir.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/proxy.conf b/tests/proxy.conf new file mode 100644 index 0000000..2d1ab0d --- /dev/null +++ b/tests/proxy.conf @@ -0,0 +1,156 @@ +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/" +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid" + +## bind to port (default: 80) +server.port = 2050 + +## 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 = "Proxy" + +server.dir-listing = "enable" + +#server.event-handler = "linux-sysepoll" +#server.event-handler = "linux-rtsig" + +#server.modules.path = "" +server.modules = ( + "mod_rewrite", + "mod_setenv", + "mod_access", + "mod_auth", +# "mod_httptls", + "mod_status", + "mod_expire", + "mod_simple_vhost", + "mod_redirect", +# "mod_evhost", +# "mod_localizer", + "mod_fastcgi", + "mod_proxy", + "mod_cgi", + "mod_compress", + "mod_userdir", + "mod_accesslog" ) + +server.indexfiles = ( "index.php", "index.html", + "index.htm", "default.htm" ) + + +######################## MODULE CONFIG ############################ + + +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log" + +mimetype.assign = ( ".png" => "image/png", + ".jpg" => "image/jpeg", + ".jpeg" => "image/jpeg", + ".gif" => "image/gif", + ".html" => "text/html", + ".htm" => "text/html", + ".pdf" => "application/pdf", + ".swf" => "application/x-shockwave-flash", + ".spl" => "application/futuresplash", + ".txt" => "text/plain", + ".tar.gz" => "application/x-tgz", + ".tgz" => "application/x-tgz", + ".gz" => "application/x-gzip", + ".c" => "text/plain", + ".conf" => "text/plain" ) + +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/" +compress.filetype = ("text/plain", "text/html") + +setenv.add-environment = ( "TRAC_ENV" => "foo") +setenv.add-request-header = ( "FOO" => "foo") +setenv.add-response-header = ( "BAR" => "foo") + +proxy.debug = 1 +proxy.server = ( "" => ( + "grisu" => ( + "host" => "127.0.0.1", + "port" => 2048, + ) + ) + ) + + +cgi.assign = ( ".pl" => "/usr/bin/perl", + ".cgi" => "/usr/bin/perl", + ".py" => "/usr/bin/python" ) + +userdir.include-user = ( "jan" ) +userdir.path = "/" + +ssl.engine = "disable" +ssl.pemfile = "server.pem" + +auth.backend = "plain" +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user" +auth.backend.plain.groupfile = "lighttpd.group" + +auth.backend.ldap.hostname = "localhost" +auth.backend.ldap.base-dn = "dc=my-domain,dc=com" +auth.backend.ldap.filter = "(uid=$)" + +auth.require = ( "/server-status" => + ( + "method" => "digest", + "realm" => "download archiv", +# "require" => ("group=www", "user=jan", "host=192.168.2.10") + "require" => "group=www|user=jan|host=192.168.2.10" + ), + "/auth.php" => + ( + "method" => "basic", + "realm" => "download archiv", +# "require" => ("group=www", "user=jan", "host=192.168.2.10") + "require" => "user=jan" + ), + "/server-config" => + ( + "method" => "basic", + "realm" => "download archiv", +# "require" => ("group=www", "user=jan", "user=weigon", "host=192.168.2.10") + "require" => "group=www|user=jan|host=192.168.2.10" + ) + ) + +url.access-deny = ( "~", ".inc") + +url.redirect = ( "^/redirect/$" => "http://localhost:2048/" ) + +url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1", + "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" ) + +expire.url = ( "/expire/access" => "access 2 hours", + "/expire/modification" => "access plus 1 seconds 2 minutes") + +#cache.cache-dir = "/home/weigon/wwwroot/cache/" + +#### status module +status.status-url = "/server-status" +status.config-url = "/server-config" + +$HTTP["host"] == "vvv.example.org" { + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/" +} + +$HTTP["host"] == "zzz.example.org" { + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/" + server.name = "zzz.example.org" +} + +$HTTP["host"] == "no-simple.example.org" { + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/" + server.name = "zzz.example.org" +} + +$HTTP["host"] !~ "(no-simple\.example\.org)" { + simple-vhost.document-root = "pages" + simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/" + simple-vhost.default-host = "www.example.org" +} + diff --git a/tests/request.t b/tests/request.t index c153b21..d2c8819 100755 --- a/tests/request.t +++ b/tests/request.t @@ -1,9 +1,9 @@ #!/usr/bin/env perl BEGIN { - # add current source dir to the include-path - # we need this for make distcheck - (my $srcdir = $0) =~ s#/[^/]+$#/#; - unshift @INC, $srcdir; + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; } use strict; diff --git a/tests/run-tests.pl b/tests/run-tests.pl index 6dae9a8..818f1c2 100755 --- a/tests/run-tests.pl +++ b/tests/run-tests.pl @@ -3,7 +3,7 @@ use strict; use Test::Harness qw(&runtests $verbose); -$verbose=0; +$verbose = (defined $ENV{'VERBOSE'} ? $ENV{'VERBOSE'} : 0);; my $srcdir = (defined $ENV{'srcdir'} ? $ENV{'srcdir'} : '.'); diff --git a/tests/symlink.t b/tests/symlink.t new file mode 100644 index 0000000..9b275bd --- /dev/null +++ b/tests/symlink.t @@ -0,0 +1,115 @@ +#!/usr/bin/env perl +BEGIN { + # add current source dir to the include-path + # we need this for make distcheck + (my $srcdir = $0) =~ s,/[^/]+$,/,; + unshift @INC, $srcdir; +} + +use strict; +use IO::Socket; +use Test::More tests => 10; +use LightyTest; + +my $tf = LightyTest->new(); +my $t; +my $docroot = $tf->{'TESTDIR'}."/tmp/lighttpd/servers/www.example.org/pages"; + +sub init_testbed { + return 0 unless eval { symlink("",""); 1 }; + my $f = "$docroot/index.html"; + my $l = "$docroot/index.xhtml"; + my $rc = undef; + unless (-l $l) { + return 0 unless symlink($f,$l); + }; + $f = "$docroot/expire"; + $l = "$docroot/symlinked"; + $rc = undef; + unless (-l $l) { + return 0 unless symlink($f,$l); + } + return 1; +}; + +SKIP: { + skip "perl does not support symlinking or setting up the symlinks failed.", 10 unless init_testbed; + ok($tf->start_proc == 0, "Starting lighttpd") or die(); + +# allow case +# simple file + $t->{REQUEST} = ( <<EOF +GET /index.html HTTP/1.0 +Host: symlink.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; + ok($tf->handle_http($t) == 0, 'allow: simple file'); + +# symlinked file + $t->{REQUEST} = ( <<EOF +GET /index.xhtml HTTP/1.0 +Host: symlink.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; + ok($tf->handle_http($t) == 0, 'allow: symlinked file'); + +# directly symlinked dir + $t->{REQUEST} = ( <<EOF +GET /symlinked/ HTTP/1.0 +Host: symlink.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; + ok($tf->handle_http($t) == 0, 'allow: directly symlinked dir'); + +# symlinked dir in path + $t->{REQUEST} = ( <<EOF +GET /symlinked/access.txt HTTP/1.0 +Host: symlink.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; + ok($tf->handle_http($t) == 0, 'allow: symlinked dir in path'); + +# deny case +# simple file + $t->{REQUEST} = ( <<EOF +GET /index.html HTTP/1.0 +Host: nosymlink.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ]; + ok($tf->handle_http($t) == 0, 'deny: simple file'); + +# symlinked file + $t->{REQUEST} = ( <<EOF +GET /index.xhtml HTTP/1.0 +Host: nosymlink.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; + ok($tf->handle_http($t) == 0, 'deny: symlinked file'); + +# directly symlinked dir + $t->{REQUEST} = ( <<EOF +GET /symlinked/ HTTP/1.0 +Host: nosymlink.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; + ok($tf->handle_http($t) == 0, 'deny: directly symlinked dir'); + +# symlinked dir in path + $t->{REQUEST} = ( <<EOF +GET /symlinked/access.txt HTTP/1.0 +Host: nosymlink.example.org +EOF + ); + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ]; + ok($tf->handle_http($t) == 0, 'deny: symlinked dir in path'); + +# cleanup + ok($tf->stop_proc == 0, "Stopping lighttpd"); +}; |