summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS23
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure23
-rw-r--r--configure.in4
-rw-r--r--cygwin/lighttpd.README10
-rw-r--r--doc/authentication.txt24
-rw-r--r--doc/cml.txt51
-rw-r--r--doc/configuration.txt37
-rw-r--r--doc/fastcgi.txt185
-rw-r--r--doc/lighttpd.conf4
-rw-r--r--doc/mysqlvhost.txt19
-rw-r--r--doc/performance.txt142
-rw-r--r--doc/plugins.txt30
-rw-r--r--doc/rrdtool.txt16
-rw-r--r--doc/scgi.txt2
-rw-r--r--doc/secdownload.txt86
-rw-r--r--doc/security.txt4
-rw-r--r--doc/setenv.txt4
-rw-r--r--doc/simple-vhost.txt38
-rwxr-xr-xdoc/spawn-php.sh14
-rw-r--r--doc/ssi.txt6
-rw-r--r--doc/ssl.txt27
-rw-r--r--doc/status.txt70
-rw-r--r--doc/traffic-shaping.txt32
-rw-r--r--doc/trigger_b4_dl.txt18
-rw-r--r--doc/userdir.txt16
-rw-r--r--doc/webdav.txt14
-rw-r--r--lighttpd.spec6
-rw-r--r--lighttpd.spec.in4
-rw-r--r--openwrt/control4
-rw-r--r--openwrt/lighttpd.mk2
-rw-r--r--src/Makefile.am6
-rw-r--r--src/Makefile.in68
-rw-r--r--src/base.h34
-rw-r--r--src/buffer.c27
-rw-r--r--src/buffer.h1
-rw-r--r--src/configfile.c19
-rw-r--r--src/configparser.c4
-rw-r--r--src/configparser.y4
-rw-r--r--src/connections.c15
-rw-r--r--src/http_auth.c12
-rw-r--r--src/http_auth_digest.c82
-rw-r--r--src/http_auth_digest.h24
-rw-r--r--src/keyvalue.c1
-rw-r--r--src/keyvalue.h3
-rw-r--r--src/mod_access.c18
-rw-r--r--src/mod_auth.c22
-rw-r--r--src/mod_cgi.c4
-rw-r--r--src/mod_cml.c122
-rw-r--r--src/mod_cml.h1
-rw-r--r--src/mod_cml_lua.c24
-rw-r--r--src/mod_dirlisting.c92
-rw-r--r--src/mod_evasive.c178
-rw-r--r--src/mod_fastcgi.c927
-rw-r--r--src/mod_mysql_vhost.c2
-rw-r--r--src/mod_proxy.c7
-rw-r--r--src/mod_scgi.c2
-rw-r--r--src/mod_secure_download.c2
-rw-r--r--src/mod_setenv.c51
-rw-r--r--src/mod_staticfile.c34
-rw-r--r--src/mod_status.c52
-rw-r--r--src/mod_webdav.c22
-rw-r--r--src/network.c41
-rw-r--r--src/network_linux_sendfile.c5
-rw-r--r--src/plugin.c19
-rw-r--r--src/request.c53
-rw-r--r--src/response.c14
-rw-r--r--src/server.c38
-rwxr-xr-xtests/LightyTest.pm15
-rw-r--r--tests/docroot/www/dummydir/.svn/README.txt2
-rw-r--r--tests/docroot/www/dummydir/.svn/empty-file0
-rw-r--r--tests/docroot/www/dummydir/.svn/entries13
-rw-r--r--tests/docroot/www/dummydir/.svn/format1
-rw-r--r--tests/fastcgi-13.conf4
-rwxr-xr-xtests/mod-fastcgi.t2
-rwxr-xr-xtests/request.t40
76 files changed, 1970 insertions, 1055 deletions
diff --git a/NEWS b/NEWS
index bc1caa4..1755ee6 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,29 @@
NEWS
====
+- 1.4.9 - 2006-01-14
+
+ * added server.core-files option (sandy <sandy@meebo.com>)
+ * added docs for mod_status
+ * added mod_evasive to limit the number of connections by IP (<w1zzard@techpowerup.com>)
+ * added the power-magnet to mod_cml
+ * added internal statistics to mod_fastcgi
+ * added server.statistics-url to get internal statistics from mod_status
+ * added support for conditional range-requests through If-Range
+ * added static building via scons
+ * fixed 100% cpu loops in mod_cgi ("sandy" <sjen@cs.stanford.edu>)
+ * fixed handling for secure-download.timeout (jamis@37signals.com)
+ * fixed IE bug in content-charset in the output of mod_dirlisting (sniper@php.net)
+ * fixed typos and language in the docs (ryan-2005@ryandesign.com)
+ * fixed assertion in mod_cgi on HEAD request is Content-Length (<sandy@meebo.com>)
+ * fixed handling if equal but duplicate If-Modified-Since request headers
+ * fixed endless loops in mod_fastcgi if backend is dead
+ * fixed Depth: 1 handling in PROPFIND requests on empty dirs
+ * fixed encoding of UTF8 encoded dirlistings (Jani Taskinen <sniper@iki.fi>)
+ * fixed initial bind to a unix-domain socket through server.bind
+ * fixed handling of lowercase filesystems
+ * fixed duplicate request headers cause by mod_setenv
+
- 1.4.8 - 2005-11-23
* added auto-reconnect to ldap-server in mod_auth
diff --git a/config.h.in b/config.h.in
index 4c4f7d8..956639c 100644
--- a/config.h.in
+++ b/config.h.in
@@ -283,6 +283,9 @@
/* Define to 1 if you have the <sys/port.h> header file. */
#undef HAVE_SYS_PORT_H
+/* Define to 1 if you have the <sys/prctl.h> header file. */
+#undef HAVE_SYS_PRCTL_H
+
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
diff --git a/configure b/configure
index b80e6f5..f83097e 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.59 for lighttpd 1.4.8.
+# Generated by GNU Autoconf 2.59 for lighttpd 1.4.9.
#
# Report bugs to <jan@kneschke.de>.
#
@@ -423,8 +423,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='lighttpd'
PACKAGE_TARNAME='lighttpd'
-PACKAGE_VERSION='1.4.8'
-PACKAGE_STRING='lighttpd 1.4.8'
+PACKAGE_VERSION='1.4.9'
+PACKAGE_STRING='lighttpd 1.4.9'
PACKAGE_BUGREPORT='jan@kneschke.de'
ac_unique_file="src/server.c"
@@ -954,7 +954,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.8 to adapt to many kinds of systems.
+\`configure' configures lighttpd 1.4.9 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1021,7 +1021,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of lighttpd 1.4.8:";;
+ short | recursive ) echo "Configuration of lighttpd 1.4.9:";;
esac
cat <<\_ACEOF
@@ -1183,7 +1183,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-lighttpd configure 1.4.8
+lighttpd configure 1.4.9
generated by GNU Autoconf 2.59
Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1197,7 +1197,7 @@ cat >&5 <<_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.8, which was
+It was created by lighttpd $as_me 1.4.9, which was
generated by GNU Autoconf 2.59. Invocation command line was
$ $0 $@
@@ -1925,7 +1925,7 @@ fi
# Define the identity of the package.
PACKAGE='lighttpd'
- VERSION='1.4.8'
+ VERSION='1.4.9'
cat >>confdefs.h <<_ACEOF
@@ -20636,11 +20636,12 @@ fi
+
for ac_header in arpa/inet.h fcntl.h netinet/in.h stdlib.h string.h \
sys/socket.h sys/time.h unistd.h sys/sendfile.h sys/uio.h \
getopt.h sys/epoll.h sys/select.h poll.h sys/poll.h sys/devpoll.h sys/filio.h \
sys/mman.h sys/event.h sys/port.h pwd.h sys/syslimits.h \
-sys/resource.h sys/un.h syslog.h
+sys/resource.h sys/un.h syslog.h sys/prctl.h
do
as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
if eval "test \"\${$as_ac_Header+set}\" = set"; then
@@ -29197,7 +29198,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
-This file was extended by lighttpd $as_me 1.4.8, which was
+This file was extended by lighttpd $as_me 1.4.9, which was
generated by GNU Autoconf 2.59. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -29260,7 +29261,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-lighttpd config.status 1.4.8
+lighttpd config.status 1.4.9
configured by $0, generated by GNU Autoconf 2.59,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/configure.in b/configure.in
index 0f94f5c..93cbb0f 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.8, jan@kneschke.de)
+AC_INIT(lighttpd, 1.4.9, jan@kneschke.de)
AC_CONFIG_SRCDIR([src/server.c])
AC_CANONICAL_TARGET
@@ -56,7 +56,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h netinet/in.h stdlib.h string.h \
sys/socket.h sys/time.h unistd.h sys/sendfile.h sys/uio.h \
getopt.h sys/epoll.h sys/select.h poll.h sys/poll.h sys/devpoll.h sys/filio.h \
sys/mman.h sys/event.h sys/port.h pwd.h sys/syslimits.h \
-sys/resource.h sys/un.h syslog.h])
+sys/resource.h sys/un.h syslog.h sys/prctl.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
diff --git a/cygwin/lighttpd.README b/cygwin/lighttpd.README
index 18bf85f..8acecba 100644
--- a/cygwin/lighttpd.README
+++ b/cygwin/lighttpd.README
@@ -31,17 +31,17 @@ Canonical download:
------------------------------------
Build instructions:
- unpack lighttpd-1.4.8-<REL>-src.tar.bz2
+ unpack lighttpd-1.4.9-<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.8-<REL>.sh all
+ ./lighttpd-1.4.9-<REL>.sh all
This will create:
- /usr/src/lighttpd-1.4.8-<REL>.tar.bz2
- /usr/src/lighttpd-1.4.8-<REL>-src.tar.bz2
+ /usr/src/lighttpd-1.4.9-<REL>.tar.bz2
+ /usr/src/lighttpd-1.4.9-<REL>-src.tar.bz2
-Or use './lighttpd-1.4.8-<REL>.sh prep' to get a patched source directory
+Or use './lighttpd-1.4.9-<REL>.sh prep' to get a patched source directory
-------------------------------------------
diff --git a/doc/authentication.txt b/doc/authentication.txt
index 20c06bd..2a11f64 100644
--- a/doc/authentication.txt
+++ b/doc/authentication.txt
@@ -7,8 +7,8 @@ Module: mod_auth
----------------
:Author: Jan Kneschke
-:Date: $Date: 2005-09-16 14:45:15 +0200 (Fri, 16 Sep 2005) $
-:Revision: $Revision: 712 $
+:Date: $Date: 2006-01-12 19:34:26 +0100 (Thu, 12 Jan 2006) $
+:Revision: $Revision: 940 $
:abstract:
The auth module provides ...
@@ -85,7 +85,7 @@ newline. ::
You can use htpasswd from the apache distribution to manage
those files. ::
- $ htpasswd lighttpd.user.digest agent007
+ $ htpasswd lighttpd.user.htpasswd agent007
htdigest
@@ -101,12 +101,24 @@ by a single newline. ::
You can use htdigest from the apache distribution to manage
those files. ::
- $ htdigest src/lighttpd.user.digest 'download area' agent007
+ $ htdigest lighttpd.user.htdigest 'download area' agent007
Using md5sum can also generate the password-hash: ::
+
+ #!/bin/sh
+ user=$1
+ realm=$2
+ pass=$3
+
+ hash=`echo -n "$user:$realm:$pass" | md5sum | cut -b -32`
+
+ echo "$user:$realm:$hash"
+
+To use it:
+
+ $ htdigest.sh 'agent007' 'download area' 'secret'
+ agent007:download area:8364d0044ef57b3defcfa141e8f77b65
- $ echo -n "agent007:download area:secret" | md5sum -
- 8364d0044ef57b3defcfa141e8f77b65 -
ldap
diff --git a/doc/cml.txt b/doc/cml.txt
index f7752d4..ddae340 100644
--- a/doc/cml.txt
+++ b/doc/cml.txt
@@ -156,6 +156,53 @@ The index.cml for this looks like: ::
Now we get about 10000 req/s instead of 600 req/s.
+Power Magnet
+------------
+
+Next to all the features about Cache Decisions CML can do more. Starting
+with lighttpd 1.4.9 a power-magnet was added which attracts each request
+and allows you to manipulate the request for your needs.
+
+We want to display a maintainance page by putting a file in a specified
+place:
+
+We enable the power magnet: ::
+
+ cml.power-magnet = "/home/www/power-magnet.cml"
+
+and create /home/www/power-magnet.cml with: ::
+
+ dr = request["DOCUMENT_ROOT"]
+
+ if file_isreg(dr .. 'maintainance.html') then
+ output_include = { 'maintainance.html' }
+ return CACHE_HIT
+ end
+
+ return CACHE_MISS
+
+For each requested file the /home/www/power-magnet.cml is executed which
+checks if maintainance.html exists in the docroot and displays it
+instead of handling the usual request.
+
+Another example, create thumbnail for requested image and serve it instead
+of sending the big image: ::
+
+ ## image-url is /album/baltic_winter_2005.jpg
+ ## no params -> 640x480 is served
+ ## /album/baltic_winter_2005.jpg/orig for full size
+ ## /album/baltic_winter_2005.jpg/thumb for thumbnail
+
+ dr = request["DOCUMENT_ROOT"]
+ sn = request["SCRIPT_NAME"]
+
+ ## to be continued :) ...
+
+ trigger_handler = '/gen_image.php'
+
+ return CACHE_MISS
+
+
Installation
============
@@ -176,6 +223,8 @@ Options
hosts for the memcache.* functions
:cml.memcache-namespace:
(not used yet)
+:cml.power-magnet:
+ a cml file that is executed for each request
Language
========
@@ -206,7 +255,7 @@ Additionally to the functions provided by lua mod_cml provides: ::
boolean memcache_exists(string)
-What ever your script does, it has to return either 0 or 1 for ``cache-hit`` or ``cache-miss``.
+What ever your script does, it has to return either CACHE_HIT or CACHE_MISS.
It case a error occures check the error-log, the user will get a error 500. If you don't like
the standard error-page use ``server.errorfile-prefix``.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 106b008..29db662 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -7,8 +7,8 @@ Module: core
------------
:Author: Jan Kneschke
-:Date: $Date: 2005-11-11 13:43:16 +0100 (Fri, 11 Nov 2005) $
-:Revision: $Revision: 835 $
+:Date: $Date: 2006-01-14 18:07:25 +0100 (Sat, 14 Jan 2006) $
+:Revision: $Revision: 947 $
:abstract:
the layout of the configuration file
@@ -96,9 +96,10 @@ $HTTP["url"]
$HTTP["remoteip"]
match on the remote IP or a remote Network
$SERVER["socket"]
- match on socket. Value must be on the format "$ip:$port" where $ip is an IP
- address and $port a port number. Only equal match (==) is supported.
- It also binds to this socket.
+ match on socket. Value must be on the format "ip:port" where ip is an IP
+ address and port a port number. Only equal match (==) is supported.
+ It also binds the daemon to this socket. Use this if you want to do IP/port-
+ based virtual hosts.
<operator> is one of:
@@ -126,8 +127,8 @@ Example
}
# handish virtual hosting
- # map all subdomains to a single document-root
- $HTTP["host"] =~ "\.example\.org$" {
+ # map all domains of a top-level-domain to a single document-root
+ $HTTP["host"] =~ "(^|\.)example\.org$" {
server.document-root = "/var/www/htdocs/example.org/pages/"
}
@@ -180,9 +181,16 @@ server.document-root
Default: no default, required
server.bind
- hostname of the server
+ IP address, hostname or absolute path to the unix-domain socket the server
+ listen on.
Default: bind to all interfaces
+
+ Example: ::
+
+ server.bind = "127.0.0.1"
+ server.bind = "www.example.org"
+ server.bind = "/tmp/lighttpd.socket"
server.port
tcp-port to bind the server to
@@ -221,6 +229,8 @@ dir-listing.activate
enables virtual directory listings if a directory is requested no
index-file was found
+ Default: disabled
+
dir-listing.hide-dotfiles
if enabled, does not list hidden files in directory listings generated
by the dir-listing option.
@@ -291,17 +301,20 @@ server.event-handler
server.pid-file
set the name of the .pid-file where the PID of the server should be placed.
- This option is used in combination with a start-script and the deamon mode
+ This option is used in combination with a start-script and the daemon mode
Default: not set
server.max-request-size
- maximum size in kbytes of the request (header + body)
+ maximum size in kbytes of the request (header + body). Only applies to POST
+ requests.
- Default: 2Gb
+ Default: 2097152 (2GB)
server.max-worker
- number of worker processes to spawn (works but has no benefit)
+ number of worker processes to spawn. This is usually only needed on servers
+ which are fairly loaded and the network handler calls delay often (e.g. new
+ requests are not handled instantaneously).
Default: 0
diff --git a/doc/fastcgi.txt b/doc/fastcgi.txt
index a9ab948..2407273 100644
--- a/doc/fastcgi.txt
+++ b/doc/fastcgi.txt
@@ -162,41 +162,32 @@ Examples
Multiple extensions for the same host ::
fastcgi.server = ( ".php" =>
- ( "grisu" =>
- (
- "host" => "127.0.0.1",
- "port" => 1026,
- "bin-path" => "/usr/local/bin/php"
- )
- ),
- ".php4" =>
- ( "grisu" =>
- (
- "host" => "127.0.0.1",
- "port" => 1026
- )
- )
- )
+ (( "host" => "127.0.0.1",
+ "port" => 1026,
+ "bin-path" => "/usr/local/bin/php"
+ )),
+ ".php4" =>
+ (( "host" => "127.0.0.1",
+ "port" => 1026
+ ))
+ )
Example with prefix: ::
fastcgi.server = ( "/remote_scripts/" =>
- ( "fcg" =>
- (
- "host" => "192.168.0.3",
- "port" => 9000,
- "check-local" => "disable",
- "docroot" => "/" # remote server may use
- # it's own docroot
- )
- )
- )
+ (( "host" => "192.168.0.3",
+ "port" => 9000,
+ "check-local" => "disable",
+ "docroot" => "/" # remote server may use
+ # it's own docroot
+ ))
+ )
The request `http://my.host.com/remote_scripts/test.cgi` will
be forwarded to fastcgi server at 192.168.0.3 and the value
"/remote_scripts/test.cgi" will be used for the SCRIPT_NAME
variable. Remote server may prepend it with its own
- document root. The handling of index files si also the
+ document root. The handling of index files is also the
resposibility of remote server for this case.
In the case that the prefix is not terminated with a slash
@@ -207,15 +198,12 @@ Examples
Example for "authorizer" mode: ::
fastcgi.server = ( "/remote_scripts/" =>
- ( "auth" =>
- (
- "host" => "10.0.0.2",
- "port" => 9000,
- "docroot" => "/path_to_private_docs",
- "mode" => "authorizer"
- )
- )
- )
+ (( "host" => "10.0.0.2",
+ "port" => 9000,
+ "docroot" => "/path_to_private_docs",
+ "mode" => "authorizer"
+ ))
+ )
Note that if "docroot" is specified then its value will be
used in DOCUMENT_ROOT and SCRIPT_FILENAME variables passed
@@ -228,16 +216,9 @@ The FastCGI plugin provides automaticly a load-balancing between
multiple FastCGI servers. ::
fastcgi.server = ( ".php" =>
- ( "server1" =>
- ( "host" => "10.0.0.3",
- "port" => 1030 ),
- "server2" =>
- ( "host" => "10.0.0.3",
- "port" => 1030 )
- )
- )
-
-
+ (( "host" => "10.0.0.2", "port" => 1030 ),
+ ( "host" => "10.0.0.3", "port" => 1030 ))
+ )
To understand how the load-balancing works you can enable the
@@ -268,11 +249,11 @@ The output shows:
As you can see the list is always sorted by the load field.
-When ever a new connection is requested, the first entry (the one
-with the lowest load) is selected, the load is increase (got proc: ...)
+Whenever a new connection is requested, the first entry (the one
+with the lowest load) is selected, the load is increased (got proc: ...)
and the list is sorted again.
-If a FastCGI request is done or the connection is drop, the load on the
+If a FastCGI request is done or the connection is dropped, the load on the
FastCGI proc decreases and the list is sorted again (release proc: ...)
This behaviour is very light-weight in code and still very efficient
@@ -303,14 +284,15 @@ Example
-------
::
- fastcgi.server = ( ".php" => ( "localhost" =>
- ( "socket" => "/tmp/php.socket",
- "bin-path" => "/usr/local/bin/php",
- "min-procs" => 1,
- "max-procs" => 32,
- "max-load-per-proc" => 4,
- "idle-timeout" => 20 )
- ) )
+ fastcgi.server = ( ".php" =>
+ (( "socket" => "/tmp/php.socket",
+ "bin-path" => "/usr/local/bin/php",
+ "min-procs" => 1,
+ "max-procs" => 32,
+ "max-load-per-proc" => 4,
+ "idle-timeout" => 20
+ ))
+ )
Disabling Adaptive Spawning
---------------------------
@@ -328,14 +310,15 @@ is done:
$ PHP_FCGI_CHILDREN=384 ./lighttpd -f ./lighttpd.conf
- fastcgi.server = ( ".php" => ( "localhost" =>
- ( "socket" => "/tmp/php.socket",
- "bin-path" => "/usr/local/bin/php",
- "min-procs" => 1,
- "max-procs" => 1,
- "max-load-per-proc" => 4,
- "idle-timeout" => 20 )
- ) )
+ fastcgi.server = ( ".php" =>
+ (( "socket" => "/tmp/php.socket",
+ "bin-path" => "/usr/local/bin/php",
+ "min-procs" => 1,
+ "max-procs" => 1,
+ "max-load-per-proc" => 4,
+ "idle-timeout" => 20
+ ))
+ )
It will create one socket and let's PHP create the 384 processes itself.
@@ -388,12 +371,10 @@ Starting with version 1.3.6 lighttpd can spawn the FastCGI
processes locally itself if necessary: ::
fastcgi.server = ( ".php" =>
- ( "localhost" =>
- ( "socket" => "/tmp/php-fastcgi.socket",
- "bin-path" => "/usr/local/bin/php"
- )
- )
- )
+ (( "socket" => "/tmp/php-fastcgi.socket",
+ "bin-path" => "/usr/local/bin/php"
+ ))
+ )
PHP provides 2 special environment variables which control the number of
spawned workes under the control of a single watching process
@@ -401,34 +382,28 @@ spawned workes under the control of a single watching process
handles before it kills itself. ::
fastcgi.server = ( ".php" =>
- ( "localhost" =>
- ( "socket" => "/tmp/php-fastcgi.socket",
- "bin-path" => "/usr/local/bin/php",
- "bin-environment" => (
- "PHP_FCGI_CHILDREN" => "16",
- "PHP_FCGI_MAX_REQUESTS" => "10000"
- )
- )
- )
- )
+ (( "socket" => "/tmp/php-fastcgi.socket",
+ "bin-path" => "/usr/local/bin/php",
+ "bin-environment" => (
+ "PHP_FCGI_CHILDREN" => "16",
+ "PHP_FCGI_MAX_REQUESTS" => "10000"
+ )
+ ))
+ )
To increase the security of the started process you should only pass
the necessary environment variables to the FastCGI process. ::
fastcgi.server = ( ".php" =>
- ( "localhost" =>
- ( "socket" => "/tmp/php-fastcgi.socket",
- "bin-path" => "/usr/local/bin/php",
- "bin-environment" => (
- "PHP_FCGI_CHILDREN" => "16",
- "PHP_FCGI_MAX_REQUESTS" => "10000"
- ),
- "bin-copy-environment" => (
- "PATH", "SHELL", "USER"
- )
- )
- )
- )
+ (( "socket" => "/tmp/php-fastcgi.socket",
+ "bin-path" => "/usr/local/bin/php",
+ "bin-environment" => (
+ "PHP_FCGI_CHILDREN" => "16",
+ "PHP_FCGI_MAX_REQUESTS" => "10000" ),
+ "bin-copy-environment" => (
+ "PATH", "SHELL", "USER" )
+ ))
+ )
Configuring PHP
---------------
@@ -441,20 +416,16 @@ configure php and lighttpd. The php.ini needs the option: ::
and the option ``broken-scriptfilename`` in your fastcgi.server config: ::
fastcgi.server = ( ".php" =>
- ( "localhost" =>
- ( "socket" => "/tmp/php-fastcgi.socket",
- "bin-path" => "/usr/local/bin/php",
- "bin-environment" => (
- "PHP_FCGI_CHILDREN" => "16",
- "PHP_FCGI_MAX_REQUESTS" => "10000"
- ),
- "bin-copy-environment" => (
- "PATH", "SHELL", "USER"
- ),
- "broken-scriptfilename" => "enable"
- )
- )
- )
+ (( "socket" => "/tmp/php-fastcgi.socket",
+ "bin-path" => "/usr/local/bin/php",
+ "bin-environment" => (
+ "PHP_FCGI_CHILDREN" => "16",
+ "PHP_FCGI_MAX_REQUESTS" => "10000" ),
+ "bin-copy-environment" => (
+ "PATH", "SHELL", "USER" ),
+ "broken-scriptfilename" => "enable"
+ ))
+ )
Why this ? the ``cgi.fix_pathinfo = 0`` would give you a working ``PATH_INFO``
but no ``PHP_SELF``. If you enable it, it turns around. To fix the
diff --git a/doc/lighttpd.conf b/doc/lighttpd.conf
index 0601841..28402ea 100644
--- a/doc/lighttpd.conf
+++ b/doc/lighttpd.conf
@@ -1,6 +1,6 @@
# lighttpd configuration file
#
-# use a it as base for lighttpd 1.0.0 and above
+# use it as a base for lighttpd 1.0.0 and above
#
# $Id: lighttpd.conf,v 1.7 2004/11/03 22:26:05 weigon Exp $
@@ -243,7 +243,7 @@ static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
# "realm" => "download archiv",
# "require" => "user=jan"
# ),
-# "/server-info" =>
+# "/server-config" =>
# (
# "method" => "digest",
# "realm" => "download archiv",
diff --git a/doc/mysqlvhost.txt b/doc/mysqlvhost.txt
index 93a08dc..9a869a1 100644
--- a/doc/mysqlvhost.txt
+++ b/doc/mysqlvhost.txt
@@ -1,6 +1,5 @@
-
====================
-MySQL based vhosting
+MySQL-based vhosting
====================
-----------------------
@@ -12,20 +11,20 @@ Module: mod_mysql_vhost
:Revision: $Revision: 1.1 $
:abstract:
- This module provides virtual hosts (vhosts) based on a MySQL table
-
+ This module provides virtual hosts (vhosts) based on a MySQL table
+
.. meta::
:keywords: lighttpd, mysql, vhost
-
+
.. contents:: Table of Contents
Description
===========
-With MySQL based vhosting you can put the information where to look for a
-document-root of a given host into a MySQL database.
+With MySQL-based vhosting you can store the path to a given host's
+document root in a MySQL database.
-.. note:: Keep in mind that only one vhost-module should be active at a time.
+.. note:: Keep in mind that only one vhost module should be active at a time.
Don't mix mod_simple_vhost with mod_mysql_vhost.
Options
@@ -38,8 +37,8 @@ Example: ::
mysql-vhost.pass = "secret"
mysql-vhost.sock = "/var/mysql.lighttpd.sock"
mysql-vhost.sql = "SELECT docroot FROM domains WHERE domain='?'"
-
-
+
+
MySQL setup: ::
GRANT SELECT ON lighttpd.* TO lighttpd@localhost IDENTIFIED BY 'secret';
diff --git a/doc/performance.txt b/doc/performance.txt
index 06a767b..3a5b964 100644
--- a/doc/performance.txt
+++ b/doc/performance.txt
@@ -12,10 +12,10 @@ Module: core
:abstract:
handling performance issues in lighttpd
-
+
.. meta::
:keywords: lighttpd, performance
-
+
.. contents:: Table of Contents
Description
@@ -24,17 +24,17 @@ Description
Performance Issues
------------------
-lighttpd is optimized into various directions. The most important is
-performance. The operation system has two major facalities to help lighttpd
-a deliver it best performance.
+lighttpd is optimized into varying directions. The most important direction is
+performance. The operation system has two major facilities to help lighttpd
+a deliver its best performance.
HTTP Keep-Alive
---------------
Disabling keep-alive might help your server if you suffer from a large
-number of open file-descriptors.
+number of open file descriptors.
-The defaults fo the server is: ::
+The defaults for the server are: ::
server.max-keep-alive-requests = 128
server.max-keep-alive-idle = 30
@@ -42,7 +42,7 @@ The defaults fo the server is: ::
server.max-write-idle = 360
handling 128 keep-alive requests in a row on a single connection, waiting 30 seconds
-before a unused keep-alive connection get dropped by lighttpd.
+before an unused keep-alive connection gets dropped by lighttpd.
If you handle several connections at once under a high load (let's assume 500 connections
in parallel for 24h) you might run into the out-of-fd problem described below. ::
@@ -50,22 +50,22 @@ in parallel for 24h) you might run into the out-of-fd problem described below. :
server.max-keep-alive-requests = 4
server.max-keep-alive-idle = 4
-would release the connections earlier and would free file-descriptors without a to large
-performance loss.
+would release the connections earlier and would free file descriptors without a
+detrimental performance loss.
-Disabling keep-alive completly is the last choice if you are still short in filedescriptors: ::
+Disabling keep-alive completely is the last resort if you are still short on file descriptors: ::
server.max-keep-alive-requests = 0
Event Handlers
--------------
-The first one is the Event Handler which cares about notifying the server
-that one of the connections is ready to send or to recieve. As you can see
-every OS has at least the select() call which has some limitations.
+The first one is the Event Handler which takes care of notifying the server
+that one of the connections is ready to send or receive. As you can see,
+every OS has at least the select() call which has some limitations.
============ ========== ===============
-OS Method Config-Value
+OS Method Config Value
============ ========== ===============
all select select
Unix poll poll
@@ -76,151 +76,157 @@ FreeBSD, ... kqueue freebsd-kqueue
============ ========== ===============
-For more infomation in this topic take a look at http://www.kegel.com/c10k.html
+For more information on this topic take a look at http://www.kegel.com/c10k.html
Configuration
`````````````
-The event-handler can be set by specifying the 'Config-Value' from above
+The event handler can be set by specifying the 'Config Value' from above
in the ``server.event-handler`` variable
e.g.: ::
server.event-handler = "linux-sysepoll"
-
+
Network Handlers
----------------
The basic network interface for all platforms at the syscalls read() and
-write(). Each modern OS provides its own syscall to help network servers
-to transfer files as fast as possible.
+write(). Every modern OS provides its own syscall to help network servers
+transfer files as fast as possible.
-If you want to send out a file from the webserver it does make any sense
+If you want to send out a file from the webserver, it doesn't make any sense
to copy the file into the webserver just to write() it back into a socket
in the next step.
sendfile() minimizes the work in the application and pushes a file directly
-into the network card (idealy spoken).
+into the network card (ideally).
-lighttpd supports all major platform specific calls:
+lighttpd supports all major platform-specific calls:
-========== ==========
-OS Method
========== ==========
-all write
-Unix writev
-Linux 2.4+ sendfile
-Linux 2.6+ sendfile64
+OS Method
+========== ==========
+all write
+Unix writev
+Linux 2.4+ sendfile
+Linux 2.6+ sendfile64
Solaris sendfilev
FreeBSD sendfile
-========== ==========
+========== ==========
-They are selected automaticly on compile-time. If you have problems check
+They are selected automatically at compile-time. If you have problems, check
./src/network_backend.h and disable the corresponding USE\_... define.
Max Connections
---------------
-As lighttpd is a single-threaded server its main resource limit is the
-number of file-descriptors which is (on most systems) set to 1024 by default.
+As lighttpd is a single-threaded server, its main resource limit is the
+number of file descriptors, which is set to 1024 by default (on most systems).
If you are running a high-traffic site you might want to increase this limit
by setting ::
server.max-fds = 2048
-
+
This only works if lighttpd is started as root.
Out-of-fd condition
-------------------
-As fds are used for tcp/ip sockets, files, directories, ... a simple request
-for a PHP page might result in using 3 fds:
+Since file descriptors are used for TCP/IP sockets, files and directories,
+a simple request for a PHP page might result in using 3 file descriptors:
1. the TCP/IP socket to the client
2. the TCP/IP and Unix domain socket to the FastCGI process
-3. the filehandle to the file in the document-root to check if it is really existing
+3. the filehandle to the file in the document root to check if it exists
-If lighttpd runs out of file-descriptors it will stop accepting new
-connections for while to use the currently available fds (file-descriptors)
-to handle the currently running requests.
+If lighttpd runs out of file descriptors, it will stop accepting new
+connections for awhile to use the existing file descriptors to handle the
+currently-running requests.
-If more than 90% of the fds are used the the handling of new connections is
-disabled, if it dropes below 80% again new connection will accepted again.
+If more than 90% of the file descriptors are used then the handling of new
+connections is disabled. If it drops below 80% again new connections will
+be accepted again.
Under some circumstances you will see ::
... accept() failed: Too many open files
-in the error-log. This tells you the you had to many new requests at once
-and lighttpd could not disable the incomming connections soon enough. The
-connection is drop and the client will get a error-message like 'connection
-failed'. This is very rare and might only occur in test-setups.
+in the error log. This tells you there were too many new requests at once
+and lighttpd could not disable the incoming connections soon enough. The
+connection was dropped and the client received an error message like 'connection
+failed'. This is very rare and might only occur in test setups.
-Increasing the ``server.max-fds`` limit will reduce the propability of this
+Increasing the ``server.max-fds`` limit will reduce the probability of this
problem.
stat() cache
============
-A stat(2) can be expensive, caching it saves time adn context-switches..
+A stat(2) can be expensive; caching it saves time and context switches.
-Instead of stat() for the existence of the file you can stat() it once and
-monitor the directory the file is in for modifications. As long as the
-directiry doesn't change, the files in it are all the same.
+Instead of using stat() every time to check for the existence of a file
+you can stat() it once and monitor the directory the file is in for
+modifications. As long as the directory doesn't change, the files in it
+must all still be the same.
With the help of FAM or gamin you can use kernel events to assure that
-your stat-cache is up to date. ::
+your stat cache is up to date. ::
server.stat-cache-engine = "fam" # either fam, simple or disabled
-Plattform Specific Notes
-========================
+Platform-Specific Notes
+=======================
Linux
-----
-For Linux 2.4.x should should think about compiling lighttpd with the option
-``--disable-lfs`` to disable the support for files larger than 2Gb. lighttpd will
+For Linux 2.4.x you should think about compiling lighttpd with the option
+``--disable-lfs`` to disable the support for files larger than 2GB. lighttpd will
fall back to the ``writev() + mmap()`` network calls which is ok, but not as
-fast as possible but support files larger than 2Gb.
+fast as possible but support files larger than 2GB.
Disabling the TCP options reduces the overhead of each TCP packet and might
-help to get the last few percent of performance out of the server.
+help to get the last few percent of performance out of the server. Be aware that
+disabling these options most likely decreases performance for high-latency and lossy
+links.
-- net.ipv4.tcp_sack = 0
+- net.ipv4.tcp_sack = 0
- net.ipv4.tcp_timestamps = 0
Increasing the TCP send and receive buffers will increase the performance a
-lot if (and only if) you have a lot large files to send.
+lot if (and only if) you have a lot of large files to send.
- net.ipv4.tcp_wmem = 4096 65536 524288
- net.core.wmem_max = 1048576
-If you have a lot large file uploads increasing the receive buffers will help.
+If you have a lot of large file uploads, increasing the receive buffers will help.
- net.ipv4.tcp_rmem = 4096 87380 524288
- net.core.rmem_max = 1048576
-Keep in mind that the buffers have to multiplied by server.max-fds and be
-allocated in the Kernel area. Be carefull with that.
+Keep in mind that every TCP connection uses the configured amount of memory for socket
+buffers. If you've got many connections this can quickly drain the available memory.
+
+See http://www.acc.umu.se/~maswan/linux-netperf.txt for more information on these parameters.
FreeBSD
-------
-On FreeBSD you might gain some performance by enabling accept-filters. Just
+On FreeBSD you might gain some performance by enabling accept filters. Just
compile your kernel with: ::
options ACCEPT_FILTER_HTTP
-For more ideas in tuning FreeBSD read: tuning(7)
+For more ideas about tuning FreeBSD read: tuning(7)
Reducing the recvspace should always be ok if the server only handles HTTP
requests without large uploads. Increasing the sendspace would reduce the
-system-load if you have a lot large files to be sent, but keep in mind that
-you to provide the memory in kernel for each connection. 1024 * 64k would mean
-64M of kernel-ram. Keep this in mind.
+system load if you have a lot of large files to be sent, but keep in mind that
+you have to provide the memory in the kernel for each connection. 1024 * 64KB
+would mean 64MB of kernel RAM. Keep this in mind.
- net.inet.tcp.recvspace = 4096
diff --git a/doc/plugins.txt b/doc/plugins.txt
index 8a755fe..91c81fd 100644
--- a/doc/plugins.txt
+++ b/doc/plugins.txt
@@ -11,8 +11,8 @@ Module: core
:Revision: $Revision: 1.1 $
:abstract:
- The plugin interface is the integral part of lighttpd provide
- a flexible way to add specific functionality to lighttpd.
+ The plugin interface is an integral part of lighttpd which
+ provides a flexible way to add specific functionality to lighttpd.
.. meta::
:keywords: lighttpd, plugins
@@ -22,9 +22,9 @@ Module: core
Description
===========
-Plugins allow you to enhance to functionality of lighttpd without
-changing the core of the webserver. They can be loaded at startup-time
-and can change hardly any aspect of the behaviour of the webserver.
+Plugins allow you to enhance the functionality of lighttpd without
+changing the core of the webserver. They can be loaded at startup time
+and can change virtually any aspect of the behaviour of the webserver.
Plugin Entry Points
-------------------
@@ -49,17 +49,17 @@ Serverwide hooks
Connectionwide hooks
````````````````````
-Most of these hooks are call in ``http_response_prepare()`` after some
-field in the connection structure are set.
+Most of these hooks are called in ``http_response_prepare()`` after some
+fields in the connection structure are set.
:handle_uri_raw_:
called after uri.path_raw, uri.authority and uri.scheme are set
:handle_uri_clean_:
- called after uri.path (a clean uri without .. and %20) is set
+ called after uri.path (a clean URI without .. and %20) is set
:handle_docroot_:
called at the end of the logical path handle to get a docroot
:handle_subrequest_start_:
- called if the physical path is setup and checked
+ called if the physical path is set up and checked
:handle_subrequest_:
called at the end of ``http_response_prepare()``
:handle_physical_path_:
@@ -82,9 +82,9 @@ Plugin Interface
\*_plugin_init
``````````````
-Every plugin has a uniquely named function which is called after the
-plugin is loaded. It is used to setup the ``plugin`` structure with
-some usefull data:
+Every plugin has a uniquely-named function which is called after the
+plugin is loaded. It is used to set up the ``plugin`` structure with
+some useful data:
- name of the plugin ``name``
- all hooks
@@ -99,7 +99,7 @@ of the internal plugin data.
init
````
-The first real call of a plugin function is the init-hook which is used
+The first real call of a plugin function is the init hook which is used
to set up the internal plugin data. The internal plugin is assigned the
``data`` field mentioned in the \*_plugin_init description.
@@ -123,12 +123,12 @@ set_defaults
set_defaults is your entry point into the configfile parsing. It should
pass a list of options to ``config_insert_values`` and check if
the plugin configuration is valid. If it is not valid yet, it should
-set usefull defaults or return with HANDLER_ERROR and an error message.
+set useful defaults or return with HANDLER_ERROR and an error message.
:returns:
HANDLER_GO_ON if ok
- HANDLER_ERROR will terminated lighttpd
+ HANDLER_ERROR will terminate lighttpd
connection_reset
````````````````
diff --git a/doc/rrdtool.txt b/doc/rrdtool.txt
index ce0145c..0e05cd3 100644
--- a/doc/rrdtool.txt
+++ b/doc/rrdtool.txt
@@ -12,17 +12,17 @@ Module: mod_rrdtool
:abstract:
mod_rrdtool is used to monitor the traffic and load on the webserver
-
+
.. meta::
:keywords: lighttpd, skeleton
-
+
.. contents:: Table of Contents
Description
===========
RRD_ is a system to store and display time-series data (i.e. network
-bandwidth, machine-room temperature, server load average).
+bandwidth, machine-room temperature, server load average).
.. _RRD: http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
@@ -33,17 +33,17 @@ rrdtool.binary
path to the rrdtool binary
e.g.: ::
-
+
rrdtool.binary = "/usr/bin/rrdtool"
rrdtool.db-name
- filename of the rrd-database. Make sure that <rrdtool.db-name> doesn't exists
- before the first run as lighttpd has to create the DB for you.
+ filename of the rrd-database. Make sure that <rrdtool.db-name> doesn't exist
+ before the first run, as lighttpd has to create the DB for you.
e.g.: ::
-
+
rrdtool.db-name = "/var/www/lighttpd.rrd"
-
+
Generating Graphs
=================
diff --git a/doc/scgi.txt b/doc/scgi.txt
index ff849fe..eeb694c 100644
--- a/doc/scgi.txt
+++ b/doc/scgi.txt
@@ -25,7 +25,7 @@ Description
The SCGI module is heavily based on the FastCGI when it comes
to configuration. Only the internal protocol between server
and client has been replaced. Please check the documentation
-of the fastcgi module for more information.
+of the FastCGI module for more information.
History
=======
diff --git a/doc/secdownload.txt b/doc/secdownload.txt
index fb946ed..570b911 100644
--- a/doc/secdownload.txt
+++ b/doc/secdownload.txt
@@ -11,12 +11,12 @@ Module: mod_secdownload
:Revision: $Revision: 1.1 $
:abstract:
- authenticated file requests and a counter measurement against
+ authenticated file requests and a countermeasure against
deep-linking can be achieved easily by using mod_secdownload
-
+
.. meta::
:keywords: lighttpd, secure, fast, downloads
-
+
.. contents:: Table of Contents
Options
@@ -32,77 +32,77 @@ Options
Description
===========
-there are multiple way to handle secured download mechanisms:
+there are multiple ways to handle secured download mechanisms:
-1. use the webserver and the internal HTTP-authentication
-2. use the application to authenticate and send the file
+1. use the webserver and the internal HTTP authentication
+2. use the application to authenticate and send the file
through the application
-
-Both way have limitations:
+
+Both ways have limitations:
webserver:
-- ``+`` fast download
-- ``+`` no additional system load
-- ``-`` unflexible authentication handling
-
+- ``+`` fast download
+- ``+`` no additional system load
+- ``-`` inflexible authentication handling
+
application:
- ``+`` integrated into the overall layout
- ``+`` very flexible permission management
-- ``-`` the download occupies a application thread/process
-
-A simple way to combine the two way could be:
+- ``-`` the download occupies an application thread/process
+
+A simple way to combine the two ways could be:
1. app authenticates user and checks permissions to
download the file.
-2. app redirectes user the file accessable by the webserver
- for further downloading
-3. the webserver transfers the file to the user
+2. app redirects user to the file accessable by the webserver
+ for further downloading.
+3. the webserver transfers the file to the user.
As the webserver doesn't know anything about the permissions
-used in the app the resulting URL would be available to every
-user who knows the URL.
-
-mod_secdownload removes this problem by introducing a way to
+used in the app, the resulting URL would be available to every
+user who knows the URL.
+
+mod_secdownload removes this problem by introducing a way to
authenticate a URL for a specified time. The application has
to generate a token and a timestamp which are checked by the
-webserver before it allows the file to be downloaded by the
+webserver before it allows the file to be downloaded by the
webserver.
The generated URL has to have the format:
<uri-prefix><token>/<timestamp-in-hex><rel-path>
-<token> is a MD5 of
+<token> is an MD5 of
1. a secret string (user supplied)
-2. <rel-path> (startes with /)
+2. <rel-path> (starts with /)
3. <timestamp-in-hex>
-As you can see the token is not bound to the user at all. The
-only limiting factor is the timestamp which is used to
+As you can see, the token is not bound to the user at all. The
+only limiting factor is the timestamp which is used to
invalidate the URL after a given timeout (secdownload.timeout).
.. Note::
- Be sure to choose a another secret then used in the examples
- as this is the only part of the token that is not known to
- the user.
-
-
-
-If the user tries to fake the URL by choosing a random token
+ Be sure to choose a another secret than the one used in the
+ examples, as this is the only part of the token that is not
+ known to the user.
+
+
+
+If the user tries to fake the URL by choosing a random token,
status 403 'Forbidden' will be sent out.
-If the timeout is reached status 408 'Request Timeout' will be
-sent (this not really standard conforming but should do the
-trick).
+If the timeout is reached, status 408 'Request Timeout' will be
+sent. (This does not really conform to the standard, but should
+do the trick).
-If token and timeout are valid the <rel-path> is taken and
-appended at the configured (secdownload.document-root) and
-passed to the normal internal file transfer functionality.
-This might lead to status 200 or 404.
+If token and timeout are valid, the <rel-path> is appended to
+the configured (secdownload.document-root) and passed to the
+normal internal file transfer functionality. This might lead to
+status 200 or 404.
Example
=======
@@ -135,8 +135,8 @@ code for PHP should be easily adaptable to any other language: ::
Webserver
---------
-The server has to configured in the same way. The uri-prefix and secret have
-to match: ::
+The server has to be configured in the same way. The URI prefix and
+secret have to match: ::
server.modules = ( ..., "mod_secdownload", ... )
diff --git a/doc/security.txt b/doc/security.txt
index d4e9147..ebbbf68 100644
--- a/doc/security.txt
+++ b/doc/security.txt
@@ -33,7 +33,7 @@ Limiting POST requests
System Security
---------------
-Running daemons as root will full privileges is a bad idea in general.
+Running daemons as root with full privileges is a bad idea in general.
lighttpd runs best without any extra privileges and runs perfectly in chroot.
Change Root
@@ -41,7 +41,7 @@ Change Root
server.chroot = "..."
-Drop root-privileges
+Drop root privileges
````````````````````
server.username = "..."
diff --git a/doc/setenv.txt b/doc/setenv.txt
index b04b083..0238c10 100644
--- a/doc/setenv.txt
+++ b/doc/setenv.txt
@@ -31,7 +31,7 @@ setenv.add-environment
setenv.add-response-header
- add a header to the HTTP-response sent to the client
+ adds a header to the HTTP response sent to the client
setenv.add-request-header
- add a header to the HTTP-request that was received by the client
+ adds a header to the HTTP request that was received from the client
diff --git a/doc/simple-vhost.txt b/doc/simple-vhost.txt
index b0776f0..d4b4db2 100644
--- a/doc/simple-vhost.txt
+++ b/doc/simple-vhost.txt
@@ -23,17 +23,17 @@ Description
Simple assumption:
-Every virtual host is in a direction below a base directory in a path that
-is the same as the name of the vhost. Below this vhost-path might be a
-extra directory which is the document-root of the vhost.
+Every virtual host is in a directory below a base directory in a path that
+is the same as the name of the vhost. Below this vhost path might be an
+extra directory which is the document root of the vhost.
-The document-root for each vhost is build from three values:
+The document root for each vhost is built from three values:
- server-root
- hostname
- document-root
-Either the absolute documentroot is build by ::
+The complete document root is constructed either by ::
server-root + hostname + document-root
@@ -41,7 +41,7 @@ or if this path does not exist by ::
server-root + default-host + document-root
-A small example should make this thinking clean: ::
+A small example should make this idea clear: ::
/var/www/
/var/www/logs/
@@ -62,7 +62,8 @@ You can use symbolic links to map several hostnames to the same directory.
Conditionals vs. simple-vhost
-----------------------------
-You have to keep in mind that conditionals and simple-vhost interfere. ::
+You have to keep in mind that conditionals and simple-vhost interfere
+with one another. ::
simple-vhost.server-root = "/var/www/servers/"
simple-vhost.default-host = "www.example.org"
@@ -72,14 +73,15 @@ You have to keep in mind that conditionals and simple-vhost interfere. ::
server.document-root = "/var/www/servers/news2.example.org/pages/"
}
-Even if the ``server.document-root`` will be set to ``/var/www/servers/news2.example.org/pages/``
-if ``news.example.org`` is requested simple-vhost will overwrite ``server.document-root`` shortly
-afterwards.
+When ``news.example.org`` is requested, the ``server.document-root``
+will be set to ``/var/www/servers/news2.example.org/pages/``, but
+simple-vhost will overwrite it shortly afterwards.
-If ``/var/www/servers/news.example.org/pages/`` exists it will be taken, if not
-``/var/www/servers/www.example.org/pages/`` will be taken as it is the default.
+If ``/var/www/servers/news.example.org/pages/`` exists, that will be
+used. If not, ``/var/www/servers/www.example.org/pages/`` will be taken
+because it is the default.
-To get them working in parallel you should use: ::
+To use conditionals together with simple-vhost, you should do this: ::
$HTTP["host"] !~ "^(news\.example\.org)$" {
simple-vhost.server-root = "/var/www/servers/"
@@ -91,17 +93,17 @@ To get them working in parallel you should use: ::
server.document-root = "/var/www/servers/news2.example.org/pages/"
}
-It will enable simple-vhosting for all host with are not named ``news.example.org``.
+It will enable simple vhosting for all hosts other than ``news.example.org``.
Options
=======
simple-vhost.server-root
- root of the virtual hosting
+ root of the virtual host
simple-vhost.default-host
- use this hostname if the
+ use this hostname if the requested hostname does not have its own directory
simple-vhost.document-root
- path below the vhost-directory
-
+ path below the vhost directory
+
diff --git a/doc/spawn-php.sh b/doc/spawn-php.sh
index 73abf67..83b7b16 100755
--- a/doc/spawn-php.sh
+++ b/doc/spawn-php.sh
@@ -6,22 +6,22 @@ SPAWNFCGI="/home/weigon/projects/spawn-fcgi/src/spawn-fcgi"
## ABSOLUTE path to the PHP binary
FCGIPROGRAM="/usr/local/bin/php"
-## bind to tcp-port on localhost
+## TCP port to which to bind on localhost
FCGIPORT="1026"
-## number of PHP childs to spawn
+## number of PHP children to spawn
PHP_FCGI_CHILDREN=10
-## number of request server by a single php-process until is will be restarted
+## maximum number of requests a single PHP process can serve before it is restarted
PHP_FCGI_MAX_REQUESTS=1000
-## IP adresses where PHP should access server connections from
+## IP addresses from which PHP should access server connections
FCGI_WEB_SERVER_ADDRS="127.0.0.1,192.168.2.10"
-# allowed environment variables sperated by spaces
+# allowed environment variables, separated by spaces
ALLOWED_ENV="ORACLE_HOME PATH USER"
-## if this script is run as root switch to the following user
+## if this script is run as root, switch to the following user
USERID=wwwrun
GROUPID=wwwrun
@@ -50,5 +50,5 @@ for i in $ALLOWED_ENV; do
E="$E $i=${!i}"
done
-# clean environment and set up a new one
+# clean the environment and set up a new one
env - $E $EX
diff --git a/doc/ssi.txt b/doc/ssi.txt
index c5791a2..8761416 100644
--- a/doc/ssi.txt
+++ b/doc/ssi.txt
@@ -11,8 +11,8 @@ Module: mod_ssi
:Revision: $Revision: 1.2 $
:abstract:
- The module for server-side includes provides a compat layer for
- NSCA/Apache SSI.
+ The module for server-side includes provides a compatability
+ layer for NSCA/Apache SSI.
.. meta::
:keywords: lighttpd, ssi, Server-Side Includes
@@ -60,7 +60,7 @@ Every ''expr'' is interpreted:
Flow Control
------------
-if, elif, else and endif can be used the insert content only under special
+if, elif, else and endif can only be used to insert content under special
conditions.
Unsupported Features
diff --git a/doc/ssl.txt b/doc/ssl.txt
index 81b9215..447da4e 100644
--- a/doc/ssl.txt
+++ b/doc/ssl.txt
@@ -11,30 +11,30 @@ Module: core
:Revision: $Revision: 1.2 $
:abstract:
- How to setup SSL in lighttpd
-
+ How to set up SSL in lighttpd
+
.. meta::
:keywords: lighttpd, ssl
-
+
.. contents:: Table of Contents
Description
===========
-lighttpd support SSLv2 and SSLv3 if it compiled against openssl.
+lighttpd supports SSLv2 and SSLv3 if it is compiled against openssl.
Configuration
-------------
-To enable SSL for the whole server you have to provide a valid
+To enable SSL for the whole server you have to provide a valid
certificate and have to enable the SSL engine.::
ssl.engine = "enable"
ssl.pemfile = "/path/to/server.pem"
-
-As SSL and named-based virtual hosting can not work together you
-have to use IP-based virtual hosting if you want to run multiple
-SSL-servers with one lighttpd: ::
+
+The HTTPS protocol does not allow you to use name-based virtual
+hosting with SSL. If you want to run multiple SSL servers with
+one lighttpd instance you must use IP-based virtual hosting: ::
$SERVER["socket"] == "10.0.0.1:443" {
ssl.engine = "enable"
@@ -44,7 +44,8 @@ SSL-servers with one lighttpd: ::
server.document-root = "/www/servers/www.example.org/pages/"
}
-If you have a .crt and a .key file cat them together into a single PEM file:
+If you have a .crt and a .key file, cat them together into a
+single PEM file:
::
$ cat host.key host.crt > host.pem
@@ -53,9 +54,9 @@ If you have a .crt and a .key file cat them together into a single PEM file:
Self-Signed Certificates
------------------------
-A self-signed SSL cerifitcate can be generated with: ::
-
+A self-signed SSL certificate can be generated like this: ::
+
$ openssl req -new -x509 \
-keyout server.pem -out server.pem \
-days 365 -nodes
-
+
diff --git a/doc/status.txt b/doc/status.txt
index 3e0acab..c64e993 100644
--- a/doc/status.txt
+++ b/doc/status.txt
@@ -11,7 +11,7 @@ Module: mod_status
:Revision: $Revision: 1.2 $
:abstract:
- mod_status displays server-status and server-config
+ mod_status displays the server's status and configuration
.. meta::
:keywords: lighttpd, server status
@@ -21,15 +21,81 @@ Module: mod_status
Description
===========
-The server status module generates the ...
+The server status module generates the status overview of the webserver. The
+information covers:
+
+- uptime
+- average throughput
+- current throughput
+- active connections and their state
+
+By default the status page is disabled to hide internal information from
+unauthorized users. ::
+
+ status.status-url = "/server-status"
+
+If you want to open the status page just for users from the local network
+cover it in a conditional. ::
+
+ $HTTP["remoteip"] == "10.0.0.0/8" {
+ status.status-url = "/server-status"
+ }
+
+Or require authorization: ::
+
+ auth.require = ( "/server-status" =>
+ ( "realm" ... ) )
+
+
+Output Format
+-------------
+
+By default a nice looking HTML page is generated. If you append ?auto to the
+status-url you can get a text version which is simpler to parse. ::
+
+ Total Accesses: 1234
+ Total kBytes: 1043
+ Uptime: 1234
+ BusyServers: 123
+
+Total Accesses is the number of handled requests, kBytes the overall outgoing
+traffic, Uptime the uptime in seconds and BusyServers the number of currently
+active connections.
+
+The naming is kept compatible to Apache even if we have another concept and
+don't start new servers for each connection.
+
Options
=======
status.status-url
+ relative URL which is used to retrieve the status-page
+
Default: unset
+ Example: status.status-url = "/server-status"
+
+status.enable-sort
+
+ add JavaScript which allows client-side sorting for the connection overview
+
+ Default: enable
+
status.config-url
+ relative URL for the config page which displays the loaded modules
+
Default: unset
+
+ Example: status.status-url = "/server-config"
+
+status.statistics-url
+
+ relative URL for a plain-text page containing the internal statistics
+
+ Default: unset
+
+ Example: status.status-url = "/server-stats"
+
diff --git a/doc/traffic-shaping.txt b/doc/traffic-shaping.txt
index 7d16638..1076686 100644
--- a/doc/traffic-shaping.txt
+++ b/doc/traffic-shaping.txt
@@ -11,45 +11,45 @@ Module: core
:Revision: $Revision: 1.2 $
:abstract:
- limiting the bandwith usage
-
+ limiting bandwidth usage
+
.. meta::
:keywords: lighttpd, bandwidth limit, traffic shaping
-
+
.. contents:: Table of Contents
Description
===========
-Starting with 1.3.8 lighttpd supports limiting the bandwith for a single connection
-or config-context like virtual-host or URL.
+Starting with 1.3.8, lighttpd supports limiting the bandwidth for
+a single connection or config context like a virtual host or a URL.
Options
=======
:connection.kbytes-per-second:
- limit the through-put for each single connection to the given
+ limit the throughput for each single connection to the given
limit in kbyte/s
-
+
default: 0 (no limit)
:server.kbytes-per-second:
- limit the through-put for all connections to the given limit
+ limit the throughput for all connections to the given limit
in kbyte/s
-
- if you want to specify a limit for a special virtual server
+
+ if you want to specify a limit for a special virtual server
use: ::
-
+
$HTTP["host"] == "www.example.org" {
server.kbytes-per-second = 128
}
-
- which will overwrite the default for this host.
-
+
+ which will override the default for this host.
+
default: 0 (no limit)
Additional Notes
================
-Keep in mind that a limit below 32kb/s might actually limit the traffic to 32kb/s. This
-is caused by by the size of the TCP-sendbuffer.
+Keep in mind that a limit below 32kb/s might actually limit the traffic to 32kb/s. This
+is caused by the size of the TCP send buffer.
diff --git a/doc/trigger_b4_dl.txt b/doc/trigger_b4_dl.txt
index ffdfb53..f5c9d29 100644
--- a/doc/trigger_b4_dl.txt
+++ b/doc/trigger_b4_dl.txt
@@ -11,11 +11,11 @@ Module: mod_trigger_b4_dl
:Revision: $Revision: 1.2 $
:abstract:
- another anti hot-linking module
-
+ another anti-hot-linking module
+
.. meta::
:keywords: lighttpd, hot-linking, deep-linking
-
+
.. contents:: Table of Contents
Description
@@ -23,11 +23,11 @@ Description
Anti Hotlinking:
- * if user requests ''download-url'' directly the request is denied and he is redirected to ''deny-url'
- * if user visits ''trigger-url'' before requesting ''download-url'' access is granted
- * if user visits ''download-url'' again after ''trigger-timeout'' has run down to the request is denied and he is redirected to ''deny-url''
+ * if user requests ''download-url'' directly, the request is denied and he is redirected to ''deny-url'
+ * if user visits ''trigger-url'' before requesting ''download-url'', access is granted
+ * if user visits ''download-url'' again after ''trigger-timeout'' has elapsed, the request is denied and he is redirected to ''deny-url''
-The storage for the trigger information is either stored locally in a gdbm file or remotly in memcached.
+The trigger information is either stored locally in a gdbm file or remotely in memcached.
Requirements
------------
@@ -47,8 +47,8 @@ Options
trigger-before-download.deny-url = "http://192.168.1.5:1025/index.html"
trigger-before-download.trigger-timeout = 10
-If both trigger-before-download.gdbm-filename and
-trigger-before-download.memcache-hosts is set gdbm will be prefered.
+If both trigger-before-download.gdbm-filename and
+trigger-before-download.memcache-hosts is set gdbm will take precedence.
Installation
============
diff --git a/doc/userdir.txt b/doc/userdir.txt
index 65cc9d0..10ba065 100644
--- a/doc/userdir.txt
+++ b/doc/userdir.txt
@@ -23,8 +23,8 @@ Description
The userdir module provides a simple way to link user-based directories into the global namespace of the webserver.
-Requests in the form ``/~user/page.html`` are rewritten to take the file ``page.html`` from the home-directory of the user.
-If ``userdir.path`` is set, the path will be appended at the home-directory
+Requests in the form ``/~user/page.html`` are rewritten to take the file ``page.html`` from the home directory of the user.
+If ``userdir.path`` is set, the path will be appended to the home directory
building the classic mapping of: ::
userdir.path = "public_html"
@@ -32,9 +32,9 @@ building the classic mapping of: ::
URL: http://www.example.org/~jan/index.html
Path: /home/jan/public_html/
-To control which users should be able to use this feature you can set a include- or a exclude list for username.
+To control which users should be able to use this feature you can set a list of usernames to include or exclude.
-In case you mapping is independent of /etc/passwd you can use
+In case your mapping is independent of /etc/passwd you can use
``userdir.basepath``: ::
userdir.path = "htdocs"
@@ -47,15 +47,15 @@ Options
=======
userdir.path
- usually it should set the "public_html" to take ~/public_html/ as the document-root
+ usually it should be set to "public_html" to take ~/public_html/ as the document root
- Default: empty (document-root is the home-directory)
+ Default: empty (document root is the home directory)
Example: ::
userdir.path = "public_html"
userdir.exclude-user
- list of usernames which should not be able to use this feature
+ list of usernames which may not use this feature
Default: empty (all users may use it)
Example: ::
@@ -66,7 +66,7 @@ userdir.exclude-user
userdir.include-user
if set, only users from this list may use the feature
- Default: empty (all user may use it)
+ Default: empty (all users may use it)
userdir.basepath
if set, don't check /etc/passwd for homedir
diff --git a/doc/webdav.txt b/doc/webdav.txt
index 175f33f..b10012f 100644
--- a/doc/webdav.txt
+++ b/doc/webdav.txt
@@ -22,7 +22,7 @@ Description
===========
The WebDAV module is a very minimalistic implementation of RFC 2518.
-Minimalistic means that not all operations are implementated yet.
+Minimalistic means that not all operations are implemented yet.
So far we have
@@ -34,15 +34,15 @@ So far we have
and the usual GET, POST, HEAD from HTTP/1.1.
-So far mounting a webdav resource into Windows XP works and the basic litmus
+So far, mounting a WebDAV resource into Windows XP works and the basic litmus
tests are passed.
Options
=======
webdav.activate
- If you load the webdav module the WebDAV functionality has to be
- enabled for the directories you want to the provide to the user.
+ If you load the webdav module, the WebDAV functionality has to be
+ enabled for the directories you want to provide to the user.
Default: disable
@@ -54,9 +54,9 @@ webdav.is-readonly
Examples
========
-To enable WebDAV for the /dav directory you take a conditional and wrap around
-your webdav options. You have to use the regex like below as you want to match
-the directory /dav and everything below it, but not /davos. ::
+To enable WebDAV for the /dav directory, you wrap your webdav options in
+a conditional. You have to use the regex like below as you want to match
+the directory /dav and everything below it, but not e.g. /davos. ::
$HTTP["url"] =~ "^/dav($|/)" {
webdav.activate = "enable"
diff --git a/lighttpd.spec b/lighttpd.spec
index 3dbc637..70c8278 100644
--- a/lighttpd.spec
+++ b/lighttpd.spec
@@ -1,6 +1,6 @@
Summary: A fast webserver with minimal memory-footprint (lighttpd)
Name: lighttpd
-Version: 1.4.8
+Version: 1.4.9
Release: 1
Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz
Packager: Jan Kneschke <jan@kneschke.de>
@@ -48,8 +48,8 @@ install -m 644 doc/sysconfig.lighttpd %{buildroot}%{_sysconfdir}/sysconfig/light
rm -rf %{buildroot}
%post
-
-if test "$1" = "0"; then
+## read http://www.fedora.us/docs/spec.html next time :)
+if test "$1" = "1"; then
# real install, not upgrade
/sbin/chkconfig --add lighttpd
fi
diff --git a/lighttpd.spec.in b/lighttpd.spec.in
index 2eab259..182297d 100644
--- a/lighttpd.spec.in
+++ b/lighttpd.spec.in
@@ -48,8 +48,8 @@ install -m 644 doc/sysconfig.lighttpd %{buildroot}%{_sysconfdir}/sysconfig/light
rm -rf %{buildroot}
%post
-
-if test "$1" = "0"; then
+## read http://www.fedora.us/docs/spec.html next time :)
+if test "$1" = "1"; then
# real install, not upgrade
/sbin/chkconfig --add lighttpd
fi
diff --git a/openwrt/control b/openwrt/control
index d7a7de3..f3acf51 100644
--- a/openwrt/control
+++ b/openwrt/control
@@ -1,8 +1,8 @@
Package: lighttpd
-Version: 1.4.8
+Version: 1.4.9
Architecture: mipsel
Maintainer: Jan Kneschke <jan@kneschke.de>
-Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.8.tar.gz
+Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.9.tar.gz
Section: net
Priority: optional
Depends:
diff --git a/openwrt/lighttpd.mk b/openwrt/lighttpd.mk
index 08debee..0abc37f 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.8
+LIGHTTPD=lighttpd-1.4.9
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 8caace2..7e9fc9e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -68,6 +68,12 @@ src += $(common_src)
common_libadd =
endif
+lib_LTLIBRARIES += mod_evasive.la
+mod_evasive_la_SOURCES = mod_evasive.c
+mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_evasive_la_LIBADD = $(common_libadd)
+
+
lib_LTLIBRARIES += mod_webdav.la
mod_webdav_la_SOURCES = mod_webdav.c
mod_webdav_la_CFLAGS = $(XML_CFLAGS)
diff --git a/src/Makefile.in b/src/Makefile.in
index e892092..cc6fab9 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -16,7 +16,7 @@
-SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
+SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
srcdir = @srcdir@
top_srcdir = @top_srcdir@
@@ -145,6 +145,9 @@ mod_dirlisting_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \
$(am__DEPENDENCIES_1)
am_mod_dirlisting_la_OBJECTS = mod_dirlisting.lo
mod_dirlisting_la_OBJECTS = $(am_mod_dirlisting_la_OBJECTS)
+mod_evasive_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
+am_mod_evasive_la_OBJECTS = mod_evasive.lo
+mod_evasive_la_OBJECTS = $(am_mod_evasive_la_OBJECTS)
mod_evhost_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
am_mod_evhost_la_OBJECTS = mod_evhost.lo
mod_evhost_la_OBJECTS = $(am_mod_evhost_la_OBJECTS)
@@ -282,23 +285,7 @@ SOURCES = $(liblightcomp_la_SOURCES) $(mod_access_la_SOURCES) \
$(mod_accesslog_la_SOURCES) $(mod_alias_la_SOURCES) \
$(mod_auth_la_SOURCES) $(mod_cgi_la_SOURCES) \
$(mod_cml_la_SOURCES) $(mod_compress_la_SOURCES) \
- $(mod_dirlisting_la_SOURCES) $(mod_evhost_la_SOURCES) \
- $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) \
- $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) \
- $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) \
- $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) \
- $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) \
- $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) \
- $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \
- $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) \
- $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) \
- $(mod_webdav_la_SOURCES) $(lemon_SOURCES) $(lighttpd_SOURCES) \
- $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
-DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \
- $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) \
- $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) \
- $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) \
- $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) \
+ $(mod_dirlisting_la_SOURCES) $(mod_evasive_la_SOURCES) \
$(mod_evhost_la_SOURCES) $(mod_expire_la_SOURCES) \
$(mod_fastcgi_la_SOURCES) $(mod_indexfile_la_SOURCES) \
$(mod_mysql_vhost_la_SOURCES) $(mod_proxy_la_SOURCES) \
@@ -309,8 +296,26 @@ DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \
$(mod_staticfile_la_SOURCES) $(mod_status_la_SOURCES) \
$(mod_trigger_b4_dl_la_SOURCES) $(mod_userdir_la_SOURCES) \
$(mod_usertrack_la_SOURCES) $(mod_webdav_la_SOURCES) \
- $(lemon_SOURCES) $(am__lighttpd_SOURCES_DIST) \
- $(proc_open_SOURCES) $(spawn_fcgi_SOURCES)
+ $(lemon_SOURCES) $(lighttpd_SOURCES) $(proc_open_SOURCES) \
+ $(spawn_fcgi_SOURCES)
+DIST_SOURCES = $(am__liblightcomp_la_SOURCES_DIST) \
+ $(mod_access_la_SOURCES) $(mod_accesslog_la_SOURCES) \
+ $(mod_alias_la_SOURCES) $(mod_auth_la_SOURCES) \
+ $(mod_cgi_la_SOURCES) $(mod_cml_la_SOURCES) \
+ $(mod_compress_la_SOURCES) $(mod_dirlisting_la_SOURCES) \
+ $(mod_evasive_la_SOURCES) $(mod_evhost_la_SOURCES) \
+ $(mod_expire_la_SOURCES) $(mod_fastcgi_la_SOURCES) \
+ $(mod_indexfile_la_SOURCES) $(mod_mysql_vhost_la_SOURCES) \
+ $(mod_proxy_la_SOURCES) $(mod_redirect_la_SOURCES) \
+ $(mod_rewrite_la_SOURCES) $(mod_rrdtool_la_SOURCES) \
+ $(mod_scgi_la_SOURCES) $(mod_secdownload_la_SOURCES) \
+ $(mod_setenv_la_SOURCES) $(mod_simple_vhost_la_SOURCES) \
+ $(mod_ssi_la_SOURCES) $(mod_staticfile_la_SOURCES) \
+ $(mod_status_la_SOURCES) $(mod_trigger_b4_dl_la_SOURCES) \
+ $(mod_userdir_la_SOURCES) $(mod_usertrack_la_SOURCES) \
+ $(mod_webdav_la_SOURCES) $(lemon_SOURCES) \
+ $(am__lighttpd_SOURCES_DIST) $(proc_open_SOURCES) \
+ $(spawn_fcgi_SOURCES)
HEADERS = $(noinst_HEADERS)
ETAGS = etags
CTAGS = ctags
@@ -480,20 +485,24 @@ spawn_fcgi_SOURCES = spawn-fcgi.c
#mod_httptls_la_SOURCES = mod_httptls.c
#mod_httptls_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
#mod_httptls_la_LIBADD = $(common_libadd)
-lib_LTLIBRARIES = $(am__append_1) mod_webdav.la mod_cml.la \
- mod_trigger_b4_dl.la mod_mysql_vhost.la mod_cgi.la mod_scgi.la \
- mod_staticfile.la mod_dirlisting.la mod_indexfile.la \
- mod_setenv.la mod_alias.la mod_userdir.la mod_rrdtool.la \
- mod_usertrack.la mod_proxy.la mod_ssi.la mod_secdownload.la \
- mod_expire.la mod_evhost.la mod_simple_vhost.la mod_fastcgi.la \
- mod_access.la mod_compress.la mod_auth.la mod_rewrite.la \
- mod_redirect.la mod_status.la mod_accesslog.la
+lib_LTLIBRARIES = $(am__append_1) mod_evasive.la mod_webdav.la \
+ mod_cml.la mod_trigger_b4_dl.la mod_mysql_vhost.la mod_cgi.la \
+ mod_scgi.la mod_staticfile.la mod_dirlisting.la \
+ mod_indexfile.la mod_setenv.la mod_alias.la mod_userdir.la \
+ mod_rrdtool.la mod_usertrack.la mod_proxy.la mod_ssi.la \
+ mod_secdownload.la mod_expire.la mod_evhost.la \
+ mod_simple_vhost.la mod_fastcgi.la mod_access.la \
+ mod_compress.la mod_auth.la mod_rewrite.la mod_redirect.la \
+ mod_status.la mod_accesslog.la
@NO_RDYNAMIC_TRUE@liblightcomp_la_SOURCES = $(common_src)
@NO_RDYNAMIC_TRUE@liblightcomp_la_CFLAGS = $(AM_CFLAGS) $(FAM_CFLAGS)
@NO_RDYNAMIC_TRUE@liblightcomp_la_LDFLAGS = -avoid-version -no-undefined
@NO_RDYNAMIC_TRUE@liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS)
@NO_RDYNAMIC_FALSE@common_libadd =
@NO_RDYNAMIC_TRUE@common_libadd = liblightcomp.la
+mod_evasive_la_SOURCES = mod_evasive.c
+mod_evasive_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
+mod_evasive_la_LIBADD = $(common_libadd)
mod_webdav_la_SOURCES = mod_webdav.c
mod_webdav_la_CFLAGS = $(XML_CFLAGS)
mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
@@ -693,6 +702,8 @@ mod_compress.la: $(mod_compress_la_OBJECTS) $(mod_compress_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(mod_compress_la_LDFLAGS) $(mod_compress_la_OBJECTS) $(mod_compress_la_LIBADD) $(LIBS)
mod_dirlisting.la: $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(mod_dirlisting_la_LDFLAGS) $(mod_dirlisting_la_OBJECTS) $(mod_dirlisting_la_LIBADD) $(LIBS)
+mod_evasive.la: $(mod_evasive_la_OBJECTS) $(mod_evasive_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(mod_evasive_la_LDFLAGS) $(mod_evasive_la_OBJECTS) $(mod_evasive_la_LIBADD) $(LIBS)
mod_evhost.la: $(mod_evhost_la_OBJECTS) $(mod_evhost_la_DEPENDENCIES)
$(LINK) -rpath $(libdir) $(mod_evhost_la_LDFLAGS) $(mod_evhost_la_OBJECTS) $(mod_evhost_la_LIBADD) $(LIBS)
mod_expire.la: $(mod_expire_la_OBJECTS) $(mod_expire_la_DEPENDENCIES)
@@ -897,6 +908,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_cml_la-mod_cml_lua.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_compress.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_dirlisting.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evasive.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_evhost.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_expire.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mod_fastcgi.Plo@am__quote@
diff --git a/src/base.h b/src/base.h
index 506fdad..98e23b8 100644
--- a/src/base.h
+++ b/src/base.h
@@ -260,7 +260,7 @@ typedef struct {
unsigned short use_ipv6;
unsigned short is_ssl;
unsigned short allow_http11;
- unsigned short force_lower_case; /* if the FS is case-insensitive, force all files to lower-case */
+ unsigned short force_lowercase_filenames; /* if the FS is case-insensitive, force all files to lower-case */
unsigned short max_request_size;
unsigned short kbytes_per_second; /* connection kb/s limit */
@@ -289,7 +289,21 @@ typedef struct {
#endif
} specific_config;
-typedef enum { CON_STATE_CONNECT, CON_STATE_REQUEST_START, CON_STATE_READ, CON_STATE_REQUEST_END, CON_STATE_READ_POST, CON_STATE_HANDLE_REQUEST, CON_STATE_RESPONSE_START, CON_STATE_WRITE, CON_STATE_RESPONSE_END, CON_STATE_ERROR, CON_STATE_CLOSE } connection_state_t;
+/* the order of the items should be the same as they are processed
+ * read before write as we use this later */
+typedef enum {
+ CON_STATE_CONNECT,
+ CON_STATE_REQUEST_START,
+ CON_STATE_READ,
+ CON_STATE_REQUEST_END,
+ CON_STATE_READ_POST,
+ CON_STATE_HANDLE_REQUEST,
+ CON_STATE_RESPONSE_START,
+ CON_STATE_WRITE,
+ CON_STATE_RESPONSE_END,
+ CON_STATE_ERROR,
+ CON_STATE_CLOSE
+} connection_state_t;
typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
typedef struct {
@@ -459,6 +473,7 @@ typedef struct {
STAT_CACHE_ENGINE_SIMPLE,
STAT_CACHE_ENGINE_FAM
} stat_cache_engine;
+ unsigned short enable_cores;
} server_config;
typedef struct {
@@ -558,6 +573,21 @@ typedef struct server {
connections *fdwaitqueue;
stat_cache *stat_cache;
+
+ /**
+ * The status array can carry all the status information you want
+ * the key to the array is <module-prefix>.<name>
+ * and the values are counters
+ *
+ * example:
+ * fastcgi.backends = 10
+ * fastcgi.active-backends = 6
+ * fastcgi.backend.<key>.load = 24
+ * fastcgi.backend.<key>....
+ *
+ * fastcgi.backend.<key>.disconnects = ...
+ */
+ array *status;
fdevent_handler_t event_handler;
diff --git a/src/buffer.c b/src/buffer.c
index cd4a72a..40b8cb9 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -685,6 +685,28 @@ const char encoded_chars_html[] = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* F0 - FF */
};
+const char encoded_chars_minimal_xml[] = {
+ /*
+ 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
+ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 - 5F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 6F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 70 - 7F DEL */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
+};
+
const char encoded_chars_hex[] = {
/*
0 1 2 3 4 5 6 7 8 9 A B C D E F
@@ -731,6 +753,9 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
case ENCODING_HTML:
map = encoded_chars_html;
break;
+ case ENCODING_MINIMAL_XML:
+ map = encoded_chars_minimal_xml;
+ break;
case ENCODING_HEX:
map = encoded_chars_hex;
break;
@@ -749,6 +774,7 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
d_len += 3;
break;
case ENCODING_HTML:
+ case ENCODING_MINIMAL_XML:
d_len += 6;
break;
case ENCODING_HEX:
@@ -774,6 +800,7 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_
d[d_len++] = hex_chars[(*ds) & 0x0F];
break;
case ENCODING_HTML:
+ case ENCODING_MINIMAL_XML:
d[d_len++] = '&';
d[d_len++] = '#';
d[d_len++] = 'x';
diff --git a/src/buffer.h b/src/buffer.h
index c304d76..3ca22e5 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -88,6 +88,7 @@ typedef enum {
ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
ENCODING_HTML, /* & becomes &amp; and so on */
+ ENCODING_MINIMAL_XML, /* minimal encoding for xml */
ENCODING_HEX /* encode string as hex */
} buffer_encoding_t;
diff --git a/src/configfile.c b/src/configfile.c
index e9080c3..6f13cd6 100644
--- a/src/configfile.c
+++ b/src/configfile.c
@@ -44,7 +44,7 @@ static int config_insert(server *srv) {
{ "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
{ "server.max-worker", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 13 */
{ "server.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
- { "server.force-lower-case-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 15 */
+ { "server.force-lowercase-filenames", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 15 */
{ "debug.log-condition-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 16 */
{ "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
{ "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
@@ -79,6 +79,7 @@ static int config_insert(server *srv) {
{ "server.max-connections", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 42 */
{ "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
{ "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
+ { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
{ "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
@@ -88,6 +89,7 @@ static int config_insert(server *srv) {
{ "server.userid", "use server.username instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.groupid", "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ "server.use-keep-alive", "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
+ { "server.force-lower-case-files", "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -116,6 +118,7 @@ static int config_insert(server *srv) {
cv[41].destination = stat_cache_string;
cv[43].destination = srv->srvconf.network_backend;
cv[44].destination = srv->srvconf.upload_tempdirs;
+ cv[45].destination = &(srv->srvconf.enable_cores);
cv[42].destination = &(srv->srvconf.max_conns);
cv[12].destination = &(srv->srvconf.max_request_size);
@@ -147,7 +150,7 @@ static int config_insert(server *srv) {
s->kbytes_per_second = 0;
s->allow_http11 = 1;
s->range_requests = 1;
- s->force_lower_case = 0;
+ s->force_lowercase_filenames = 0;
s->global_kbytes_per_second = 0;
s->global_bytes_per_second_cnt = 0;
s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
@@ -160,7 +163,7 @@ static int config_insert(server *srv) {
/* 13 max-worker */
cv[14].destination = s->document_root;
- cv[15].destination = &(s->force_lower_case);
+ cv[15].destination = &(s->force_lowercase_filenames);
cv[16].destination = &(s->log_condition_handling);
cv[17].destination = &(s->max_keep_alive_requests);
cv[18].destination = s->server_name;
@@ -244,7 +247,7 @@ int config_setup_connection(server *srv, connection *con) {
PATCH(log_file_not_found);
PATCH(range_requests);
- PATCH(force_lower_case);
+ PATCH(force_lowercase_filenames);
PATCH(is_ssl);
PATCH(ssl_pemfile);
@@ -316,8 +319,8 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
PATCH(log_file_not_found);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
PATCH(allow_http11);
- } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lower-case-files"))) {
- PATCH(force_lower_case);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
+ PATCH(force_lowercase_filenames);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
PATCH(global_kbytes_per_second);
PATCH(global_bytes_per_second_cnt);
@@ -1085,7 +1088,7 @@ int config_set_defaults(server *srv) {
* an other filename, no need to stat(),
* just assume it is case-sensitive. */
- s->force_lower_case = 0;
+ s->force_lowercase_filenames = 0;
} else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
/* upper case exists too, doesn't the FS handle this ? */
@@ -1095,7 +1098,7 @@ int config_set_defaults(server *srv) {
if (st1.st_ino == st2.st_ino) {
/* upper and lower have the same inode -> case-insensitve FS */
- s->force_lower_case = 1;
+ s->force_lowercase_filenames = 1;
}
}
}
diff --git a/src/configparser.c b/src/configparser.c
index 68d9c62..2ce169a 100644
--- a/src/configparser.c
+++ b/src/configparser.c
@@ -1194,8 +1194,8 @@ static void yy_reduce(
dc->string = buffer_init_buffer(rvalue);
}
#else
- fprintf(stderr, "regex conditionals are not allowed as pcre-support" \
- "is missing: $%s[%s]\n",
+ fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
+ "(perhaps just a missing pcre-devel package ?) \n",
yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy1->ptr);
ctx->ok = 0;
#endif
diff --git a/src/configparser.y b/src/configparser.y
index 4ca4fa0..767024f 100644
--- a/src/configparser.y
+++ b/src/configparser.y
@@ -447,8 +447,8 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio
dc->string = buffer_init_buffer(rvalue);
}
#else
- fprintf(stderr, "regex conditionals are not allowed as pcre-support" \
- "is missing: $%s[%s]\n",
+ fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
+ "(perhaps just a missing pcre-devel package ?) \n",
B->ptr, C->ptr);
ctx->ok = 0;
#endif
diff --git a/src/connections.c b/src/connections.c
index acd8880..ea3a66c 100644
--- a/src/connections.c
+++ b/src/connections.c
@@ -352,7 +352,13 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
case HTTP_METHOD_PROPPATCH:
break;
case HTTP_METHOD_OPTIONS:
- if (con->uri.path->ptr[0] != '*') {
+ /*
+ * 400 is coming from the request-parser BEFORE uri.path is set
+ * 403 is from the response handler when noone else catched it
+ *
+ * */
+ if (con->uri.path->used &&
+ con->uri.path->ptr[0] != '*') {
response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
con->http_status = 200;
@@ -364,6 +370,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) {
default:
switch(con->http_status) {
case 400: /* bad request */
+ case 414: /* overload request header */
case 505: /* unknown protocol */
case 207: /* this was webdav */
break;
@@ -864,6 +871,7 @@ int connection_handle_read_state(server *srv, connection *con) {
c->next = cq->unused;
cq->unused = c;
+ cq->unused_chunks++;
c = cq->first;
} else if (c->next && c->next->mem->used == 0) {
@@ -876,6 +884,7 @@ int connection_handle_read_state(server *srv, connection *con) {
fc->next = cq->unused;
cq->unused = fc;
+ cq->unused_chunks++;
/* the last node was empty */
if (c->next == NULL) {
@@ -981,11 +990,11 @@ int connection_handle_read_state(server *srv, connection *con) {
if (h_term) {
connection_set_state(srv, con, CON_STATE_REQUEST_END);
} else if (con->request.request->used > 64 * 1024) {
- log_error_write(srv, __FILE__, __LINE__, "sd", "http-header larger then 64k -> disconnected", chunkqueue_length(cq));
+ log_error_write(srv, __FILE__, __LINE__, "s", "oversized request-header -> sending Status 414");
con->http_status = 414; /* Request-URI too large */
con->keep_alive = 0;
- connection_set_state(srv, con, CON_STATE_REQUEST_END);
+ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
}
break;
case CON_STATE_READ_POST:
diff --git a/src/http_auth.c b/src/http_auth.c
index 478a2f7..9976c15 100644
--- a/src/http_auth.c
+++ b/src/http_auth.c
@@ -350,19 +350,25 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha
/* from r to r + r_len is a rule */
if (0 == strncmp(r, "valid-user", r_len)) {
- log_error_write(srv, __FILE__, __LINE__, "s", "valid-user cannot be combined with other require rules");
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
+ require->value);
return -1;
}
/* search for = in the rules */
if (NULL == (eq = strchr(r, '='))) {
- log_error_write(srv, __FILE__, __LINE__, "s", "= is missing");
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing the 'require' section in 'auth.require' failed: a = is missing",
+ require->value);
return -1;
}
/* = out of range */
if (eq > r + r_len) {
- log_error_write(srv, __FILE__, __LINE__, "s", "= out of range");
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "parsing the 'require' section in 'auth.require' failed: = out of range",
+ require->value);
return -1;
}
diff --git a/src/http_auth_digest.c b/src/http_auth_digest.c
index 8f7086f..e440430 100644
--- a/src/http_auth_digest.c
+++ b/src/http_auth_digest.c
@@ -17,85 +17,3 @@ void CvtHex(IN HASH Bin, OUT HASHHEX Hex) {
Hex[HASHHEXLEN] = '\0';
}
-/* calculate H(A1) as per spec */
-void DigestCalcHA1(
- IN char * pszAlg,
- IN char * pszUserName,
- IN char * pszRealm,
- IN char * pszPassword,
- IN char * pszNonce,
- IN char * pszCNonce,
- OUT HASHHEX SessionKey
- )
-{
- MD5_CTX Md5Ctx;
- HASH HA1;
-
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)pszUserName, strlen(pszUserName));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszRealm, strlen(pszRealm));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszPassword, strlen(pszPassword));
- MD5_Final(HA1, &Md5Ctx);
- if (strcasecmp(pszAlg, "md5-sess") == 0) {
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)HA1, HASHLEN);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszNonce, strlen(pszNonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszCNonce, strlen(pszCNonce));
- MD5_Final(HA1, &Md5Ctx);
- }
- CvtHex(HA1, SessionKey);
-}
-
-/* calculate request-digest/response-digest as per HTTP Digest spec */
-void DigestCalcResponse(
- IN HASHHEX HA1, /* H(A1) */
- IN char * pszNonce, /* nonce from server */
- IN char * pszNonceCount, /* 8 hex digits */
- IN char * pszCNonce, /* client nonce */
- IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
- IN char * pszMethod, /* method from the request */
- IN char * pszDigestUri, /* requested URL */
- IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
- OUT HASHHEX Response /* request-digest or response-digest */
- )
-{
- MD5_CTX Md5Ctx;
- HASH HA2;
- HASH RespHash;
- HASHHEX HA2Hex;
-
- /* calculate H(A2) */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)pszMethod, strlen(pszMethod));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszDigestUri, strlen(pszDigestUri));
- if (strcasecmp(pszQop, "auth-int") == 0) {
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)HEntity, HASHHEXLEN);
- };
- MD5_Final(HA2, &Md5Ctx);
- CvtHex(HA2, HA2Hex);
-
- /* calculate response */
- MD5_Init(&Md5Ctx);
- MD5_Update(&Md5Ctx, (unsigned char *)HA1, HASHHEXLEN);
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszNonce, strlen(pszNonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- if (*pszQop) {
- MD5_Update(&Md5Ctx, (unsigned char *)pszNonceCount, strlen(pszNonceCount));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszCNonce, strlen(pszCNonce));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- MD5_Update(&Md5Ctx, (unsigned char *)pszQop, strlen(pszQop));
- MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
- }
- MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
- MD5_Final(RespHash, &Md5Ctx);
- CvtHex(RespHash, Response);
-}
-
diff --git a/src/http_auth_digest.h b/src/http_auth_digest.h
index 3f11d70..8bffce4 100644
--- a/src/http_auth_digest.h
+++ b/src/http_auth_digest.h
@@ -16,30 +16,6 @@ typedef char HASHHEX[HASHHEXLEN+1];
#endif
#define OUT
-/* calculate H(A1) as per HTTP Digest spec */
-void DigestCalcHA1(
- IN char * pszAlg,
- IN char * pszUserName,
- IN char * pszRealm,
- IN char * pszPassword,
- IN char * pszNonce,
- IN char * pszCNonce,
- OUT HASHHEX SessionKey
- );
-
-/* calculate request-digest/response-digest as per HTTP Digest spec */
-void DigestCalcResponse(
- IN HASHHEX HA1, /* H(A1) */
- IN char * pszNonce, /* nonce from server */
- IN char * pszNonceCount, /* 8 hex digits */
- IN char * pszCNonce, /* client nonce */
- IN char * pszQop, /* qop-value: "", "auth", "auth-int" */
- IN char * pszMethod, /* method from the request */
- IN char * pszDigestUri, /* requested URL */
- IN HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
- OUT HASHHEX Response /* request-digest or response-digest */
- );
-
void CvtHex(
IN HASH Bin,
OUT HASHHEX Hex
diff --git a/src/keyvalue.c b/src/keyvalue.c
index c438a43..b26588f 100644
--- a/src/keyvalue.c
+++ b/src/keyvalue.c
@@ -29,6 +29,7 @@ static keyvalue http_methods[] = {
{ HTTP_METHOD_CHECKIN, "CHECKIN" },
{ HTTP_METHOD_UNCHECKOUT, "UNCHECKOUT" },
{ HTTP_METHOD_VERSION_CONTROL, "VERSION-CONTROL" },
+ { HTTP_METHOD_CONNECT, "CONNECT" },
{ HTTP_METHOD_UNSET, NULL }
};
diff --git a/src/keyvalue.h b/src/keyvalue.h
index 7c78037..e1c940f 100644
--- a/src/keyvalue.h
+++ b/src/keyvalue.h
@@ -27,7 +27,8 @@ typedef enum {
HTTP_METHOD_CHECKIN,
HTTP_METHOD_VERSION_CONTROL,
HTTP_METHOD_UNCHECKOUT,
- HTTP_METHOD_LABEL
+ HTTP_METHOD_LABEL,
+ HTTP_METHOD_CONNECT
} http_method_t;
typedef enum { HTTP_VERSION_UNSET = -1, HTTP_VERSION_1_0, HTTP_VERSION_1_1 } http_version_t;
diff --git a/src/mod_access.c b/src/mod_access.c
index aa8d16f..f3f7071 100644
--- a/src/mod_access.c
+++ b/src/mod_access.c
@@ -129,11 +129,21 @@ URIHANDLER_FUNC(mod_access_uri_handler) {
if (ct_len > s_len) continue;
if (ds->value->used == 0) continue;
-
- if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
- con->http_status = 403;
+
+ /* if we have a case-insensitive FS we have to lower-case the URI here too */
+
+ if (con->conf.force_lowercase_filenames) {
+ if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+ con->http_status = 403;
- return HANDLER_FINISHED;
+ return HANDLER_FINISHED;
+ }
+ } else {
+ if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+ con->http_status = 403;
+
+ return HANDLER_FINISHED;
+ }
}
}
diff --git a/src/mod_auth.c b/src/mod_auth.c
index 703107c..9b791d4 100644
--- a/src/mod_auth.c
+++ b/src/mod_auth.c
@@ -193,11 +193,23 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
/* search auth-directives for path */
for (k = 0; k < p->conf.auth_require->used; k++) {
- if (p->conf.auth_require->data[k]->key->used == 0) continue;
-
- if (0 == strncmp(con->uri.path->ptr, p->conf.auth_require->data[k]->key->ptr, p->conf.auth_require->data[k]->key->used - 1)) {
- auth_required = 1;
- break;
+ buffer *req = p->conf.auth_require->data[k]->key;
+
+ if (req->used == 0) continue;
+ if (con->uri.path->used < req->used) continue;
+
+ /* if we have a case-insensitive FS we have to lower-case the URI here too */
+
+ if (con->conf.force_lowercase_filenames) {
+ if (0 == strncasecmp(con->uri.path->ptr, req->ptr, req->used - 1)) {
+ auth_required = 1;
+ break;
+ }
+ } else {
+ if (0 == strncmp(con->uri.path->ptr, req->ptr, req->used - 1)) {
+ auth_required = 1;
+ break;
+ }
}
}
diff --git a/src/mod_cgi.c b/src/mod_cgi.c
index d747ccf..9480032 100644
--- a/src/mod_cgi.c
+++ b/src/mod_cgi.c
@@ -5,7 +5,6 @@
#include <sys/socket.h>
#include <sys/wait.h>
#include <sys/mman.h>
-#include <sys/fcntl.h>
#include <netinet/in.h>
@@ -22,6 +21,7 @@
#include <assert.h>
#include <stdio.h>
+#include <fcntl.h>
#include "server.h"
#include "keyvalue.h"
@@ -1278,7 +1278,7 @@ int mod_cgi_plugin_init(plugin *p) {
p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("cgi");
- p->handle_connection_close = cgi_connection_close_callback;
+ p->connection_reset = cgi_connection_close_callback;
p->handle_subrequest_start = cgi_is_handled;
p->handle_subrequest = mod_cgi_handle_subrequest;
#if 0
diff --git a/src/mod_cml.c b/src/mod_cml.c
index def16c7..0be9747 100644
--- a/src/mod_cml.c
+++ b/src/mod_cml.c
@@ -47,6 +47,7 @@ FREE_FUNC(mod_cml_free) {
buffer_free(s->ext);
buffer_free(s->mc_namespace);
+ buffer_free(s->power_magnet);
array_free(s->mc_hosts);
#if defined(HAVE_MEMCACHE_H)
@@ -78,6 +79,7 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) {
{ "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
{ "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
{ "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -92,6 +94,7 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) {
s->ext = buffer_init();
s->mc_hosts = array_init();
s->mc_namespace = buffer_init();
+ s->power_magnet = buffer_init();
#if defined(HAVE_MEMCACHE_H)
s->mc = NULL;
#endif
@@ -99,6 +102,7 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) {
cv[0].destination = s->ext;
cv[1].destination = s->mc_hosts;
cv[2].destination = s->mc_namespace;
+ cv[3].destination = s->power_magnet;
p->config_storage[i] = s;
@@ -144,6 +148,7 @@ static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p
PATCH(mc);
#endif
PATCH(mc_namespace);
+ PATCH(power_magnet);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
@@ -165,6 +170,8 @@ static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p
#endif
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
PATCH(mc_namespace);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
+ PATCH(power_magnet);
}
}
}
@@ -289,36 +296,11 @@ int cache_get_session_id(server *srv, connection *con, plugin_data *p) {
}
-
-URIHANDLER_FUNC(mod_cml_is_handled) {
- int ct_len, s_len;
+int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
buffer *b;
char *c;
- buffer *fn = con->physical.path;
- plugin_data *p = p_d;
int ret;
-
- if (fn->used == 0) return HANDLER_ERROR;
-
- mod_cml_patch_connection(srv, con, p);
-
- buffer_reset(p->basedir);
- buffer_reset(p->baseurl);
- buffer_reset(p->session_id);
- buffer_reset(p->trigger_handler);
-
- if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
-
- ct_len = p->conf.ext->used - 1;
- s_len = fn->used - 1;
-
- if (s_len < ct_len) return HANDLER_GO_ON;
-
- if (0 != strncmp(fn->ptr + s_len - ct_len, p->conf.ext->ptr, ct_len)) {
- /* not my job */
- return HANDLER_GO_ON;
- }
-
+
/* cleanup basedir */
b = p->baseurl;
buffer_copy_string_buffer(b, con->uri.path);
@@ -330,7 +312,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
}
b = p->basedir;
- buffer_copy_string_buffer(b, fn);
+ buffer_copy_string_buffer(b, con->physical.path);
for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
if (*c == '/') {
@@ -338,6 +320,7 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
*(c+1) = '\0';
}
+
/* prepare variables
* - session-id
* - cookie-based
@@ -346,9 +329,82 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
cache_get_session_id(srv, con, p);
- ret = cache_parse_lua(srv, con, p, fn);
+ return cache_parse_lua(srv, con, p, cml_file);
+
+}
+
+URIHANDLER_FUNC(mod_cml_power_magnet) {
+ plugin_data *p = p_d;
+
+ mod_cml_patch_connection(srv, con, p);
+
+ buffer_reset(p->basedir);
+ buffer_reset(p->baseurl);
+ buffer_reset(p->session_id);
+ buffer_reset(p->trigger_handler);
+
+ if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
+
+ /*
+ * power-magnet:
+ * cml.power-magnet = server.docroot + "/rewrite.cml"
+ *
+ * is called on EACH request, take the original REQUEST_URI and modifies the
+ * request header as neccesary.
+ *
+ * First use:
+ * if file_exists("/maintainance.html") {
+ * output_include = ( "/maintainance.html" )
+ * return CACHE_HIT
+ * }
+ *
+ * as we only want to rewrite HTML like requests we should cover it in a conditional
+ *
+ * */
+
+ switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
+ case -1:
+ /* error */
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-error");
+ }
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
+ case 0:
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "cache-hit");
+ }
+ /* cache-hit */
+ buffer_reset(con->physical.path);
+ return HANDLER_FINISHED;
+ case 1:
+ /* cache miss */
+ return HANDLER_GO_ON;
+ default:
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
+ }
+}
+
+URIHANDLER_FUNC(mod_cml_is_handled) {
+ plugin_data *p = p_d;
+
+ if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
+
+ mod_cml_patch_connection(srv, con, p);
+
+ buffer_reset(p->basedir);
+ buffer_reset(p->baseurl);
+ buffer_reset(p->session_id);
+ buffer_reset(p->trigger_handler);
+
+ if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
- switch(ret) {
+ if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
+ return HANDLER_GO_ON;
+ }
+
+ switch(cache_call_lua(srv, con, p, con->physical.path)) {
case -1:
/* error */
if (con->conf.log_request_handling) {
@@ -369,9 +425,10 @@ URIHANDLER_FUNC(mod_cml_is_handled) {
}
/* cache miss */
return HANDLER_COMEBACK;
+ default:
+ con->http_status = 500;
+ return HANDLER_COMEBACK;
}
-
- return 0;
}
int mod_cml_plugin_init(plugin *p) {
@@ -383,6 +440,7 @@ int mod_cml_plugin_init(plugin *p) {
p->set_defaults = mod_cml_set_defaults;
p->handle_subrequest_start = mod_cml_is_handled;
+ p->handle_physical = mod_cml_power_magnet;
p->data = NULL;
diff --git a/src/mod_cml.h b/src/mod_cml.h
index 9b09877..a2e9df4 100644
--- a/src/mod_cml.h
+++ b/src/mod_cml.h
@@ -22,6 +22,7 @@ typedef struct {
#if defined(HAVE_MEMCACHE_H)
struct memcache *mc;
#endif
+ buffer *power_magnet;
} plugin_config;
typedef struct {
diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c
index 5023b43..4e780e1 100644
--- a/src/mod_cml_lua.c
+++ b/src/mod_cml_lua.c
@@ -247,19 +247,19 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
}
- if (!lua_to_c_is_table(L, "output_include")) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "output_include is missing or not a table");
- ret = -1;
-
- goto error;
- }
-
if (ret == 0) {
/* up to now it is a cache-hit, check if all files exist */
int curelem;
time_t mtime = 0;
+
+ if (!lua_to_c_is_table(L, "output_include")) {
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "output_include is missing or not a table");
+ ret = -1;
+
+ goto error;
+ }
lua_pushstring(L, "output_include");
@@ -376,13 +376,7 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
}
}
- if (ret == 1 && buffer_is_empty(p->trigger_handler)) {
- log_error_write(srv, __FILE__, __LINE__, "s",
- "cache-miss, but not trigger_handler set");
- ret = -1;
- }
-
- if (ret == 1) {
+ if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
/* cache-miss */
buffer_copy_string_buffer(con->uri.path, p->baseurl);
buffer_append_string_buffer(con->uri.path, p->trigger_handler);
diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c
index 9b06fdb..69eb1e9 100644
--- a/src/mod_dirlisting.c
+++ b/src/mod_dirlisting.c
@@ -51,6 +51,9 @@ typedef struct {
unsigned short dir_listing;
unsigned short hide_dot_files;
unsigned short show_readme;
+ unsigned short hide_readme_file;
+ unsigned short show_header;
+ unsigned short hide_header_file;
excludes_buffer *excludes;
@@ -62,6 +65,7 @@ typedef struct {
PLUGIN_DATA;
buffer *tmp_buf;
+ buffer *content_charset;
plugin_config **config_storage;
@@ -144,7 +148,9 @@ INIT_FUNC(mod_dirlisting_init) {
plugin_data *p;
p = calloc(1, sizeof(*p));
+
p->tmp_buf = buffer_init();
+ p->content_charset = buffer_init();
return p;
}
@@ -174,6 +180,7 @@ FREE_FUNC(mod_dirlisting_free) {
}
buffer_free(p->tmp_buf);
+ buffer_free(p->content_charset);
free(p);
@@ -228,13 +235,16 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
size_t i = 0;
config_values_t cv[] = {
- { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
- { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
- { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
- { "dir-listing.external-css", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
- { "dir-listing.encoding", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
- { "dir-listing.show-readme", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
- { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
+ { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
+ { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
+ { "dir-listing.external-css", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
+ { "dir-listing.encoding", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
+ { "dir-listing.show-readme", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
+ { "dir-listing.hide-readme-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
+ { "dir-listing.show-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
+ { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
+ { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -253,6 +263,9 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
s->external_css = buffer_init();
s->hide_dot_files = 0;
s->show_readme = 0;
+ s->hide_readme_file = 0;
+ s->show_header = 0;
+ s->hide_header_file = 0;
s->encoding = buffer_init();
cv[0].destination = s->excludes;
@@ -261,7 +274,10 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
cv[3].destination = s->external_css;
cv[4].destination = s->encoding;
cv[5].destination = &(s->show_readme);
- cv[6].destination = &(s->dir_listing); /* old name */
+ cv[6].destination = &(s->hide_readme_file);
+ cv[7].destination = &(s->show_header);
+ cv[8].destination = &(s->hide_header_file);
+ cv[9].destination = &(s->dir_listing); /* old name */
p->config_storage[i] = s;
ca = ((data_config *)srv->config_context->data[i])->value;
@@ -287,6 +303,9 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH(hide_dot_files);
PATCH(encoding);
PATCH(show_readme);
+ PATCH(hide_readme_file);
+ PATCH(show_header);
+ PATCH(hide_header_file);
PATCH(excludes);
/* skip the first, the global context */
@@ -312,6 +331,12 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_
PATCH(encoding);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
PATCH(show_readme);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
+ PATCH(hide_readme_file);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
+ PATCH(show_header);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
+ PATCH(hide_header_file);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
PATCH(excludes);
}
@@ -414,7 +439,7 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
"<head>\n"
"<title>Index of "
);
- buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_HTML);
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out, "</title>\n");
if (p->conf.external_css->used > 1) {
@@ -461,8 +486,27 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data
);
}
- BUFFER_APPEND_STRING_CONST(out, "</head>\n<body>\n<h2>Index of ");
- buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_HTML);
+ BUFFER_APPEND_STRING_CONST(out, "</head>\n<body>\n");
+
+ /* HEADER.txt */
+ if (p->conf.show_header) {
+ stream s;
+ /* if we have a HEADER file, display it in <pre class="header"></pre> */
+
+ buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
+ BUFFER_APPEND_SLASH(p->tmp_buf);
+ BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
+
+ if (-1 != stream_open(&s, p->tmp_buf)) {
+ BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
+ buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
+ BUFFER_APPEND_STRING_CONST(out, "</pre>");
+ }
+ stream_close(&s);
+ }
+
+ BUFFER_APPEND_STRING_CONST(out, "<h2>Index of ");
+ buffer_append_string_encoded(out, CONST_BUF_LEN(con->uri.path), ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out,
"</h2>\n"
"<div class=\"list\">\n"
@@ -504,7 +548,7 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data
if (-1 != stream_open(&s, p->tmp_buf)) {
BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
- buffer_append_string_encoded(out, s.start, s.size, ENCODING_HTML);
+ buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out, "</pre>");
}
stream_close(&s);
@@ -602,6 +646,15 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
continue;
}
+ if (p->conf.hide_readme_file) {
+ if (strcmp(dent->d_name, "README.txt") == 0)
+ continue;
+ }
+ if (p->conf.hide_header_file) {
+ if (strcmp(dent->d_name, "HEADER.txt") == 0)
+ continue;
+ }
+
/* compare d_name against excludes array
* elements, skipping any that match.
*/
@@ -691,7 +744,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
BUFFER_APPEND_STRING_CONST(out, "/\">");
- buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_HTML);
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out, "</a>/</td><td class=\"m\">");
buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">- &nbsp;</td><td class=\"t\">Directory</td></tr>\n");
@@ -747,7 +800,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
BUFFER_APPEND_STRING_CONST(out, "\">");
- buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_HTML);
+ buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_MINIMAL_XML);
BUFFER_APPEND_STRING_CONST(out, "</a></td><td class=\"m\">");
buffer_append_string_len(out, datebuf, sizeof(datebuf) - 1);
BUFFER_APPEND_STRING_CONST(out, "</td><td class=\"s\">");
@@ -764,7 +817,16 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf
free(path);
http_list_directory_footer(srv, con, p, out);
- response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+
+ /* Insert possible charset to Content-Type */
+ if (buffer_is_empty(p->conf.encoding)) {
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
+ } else {
+ buffer_copy_string(p->content_charset, "text/html; charset=");
+ buffer_append_string_buffer(p->content_charset, p->conf.encoding);
+ response_header_insert(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->content_charset));
+ }
+
con->file_finished = 1;
return 0;
diff --git a/src/mod_evasive.c b/src/mod_evasive.c
new file mode 100644
index 0000000..b9d19ca
--- /dev/null
+++ b/src/mod_evasive.c
@@ -0,0 +1,178 @@
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "base.h"
+#include "log.h"
+#include "buffer.h"
+
+#include "plugin.h"
+
+#include "inet_ntop_cache.h"
+
+/**
+ * mod_evasive
+ *
+ * we indent to implement all features the mod_evasive from apache has
+ *
+ * - limit of connections per IP
+ * - provide a list of block-listed ip/networks (no access)
+ * - provide a white-list of ips/network which is not affected by the limit
+ * (hmm, conditionals might be enough)
+ * - provide a bandwidth limiter per IP
+ *
+ * started by:
+ * - w1zzard@techpowerup.com
+ */
+
+typedef struct {
+ unsigned short max_conns;
+} plugin_config;
+
+typedef struct {
+ PLUGIN_DATA;
+
+ plugin_config **config_storage;
+
+ plugin_config conf;
+} plugin_data;
+
+INIT_FUNC(mod_evasive_init) {
+ plugin_data *p;
+
+ p = calloc(1, sizeof(*p));
+
+ return p;
+}
+
+FREE_FUNC(mod_evasive_free) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (!p) return HANDLER_GO_ON;
+
+ if (p->config_storage) {
+ size_t i;
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s = p->config_storage[i];
+
+ free(s);
+ }
+ free(p->config_storage);
+ }
+
+ free(p);
+
+ return HANDLER_GO_ON;
+}
+
+SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
+ plugin_data *p = p_d;
+ size_t i = 0;
+
+ config_values_t cv[] = {
+ { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
+ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
+ };
+
+ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
+
+ for (i = 0; i < srv->config_context->used; i++) {
+ plugin_config *s;
+
+ s = calloc(1, sizeof(plugin_config));
+ s->max_conns = 0;
+
+ cv[0].destination = &(s->max_conns);
+
+ p->config_storage[i] = s;
+
+ if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
+ return HANDLER_ERROR;
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+#define PATCH(x) \
+ p->conf.x = s->x;
+static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
+ size_t i, j;
+ plugin_config *s = p->config_storage[0];
+
+ PATCH(max_conns);
+
+ /* skip the first, the global context */
+ for (i = 1; i < srv->config_context->used; i++) {
+ data_config *dc = (data_config *)srv->config_context->data[i];
+ s = p->config_storage[i];
+
+ /* condition didn't match */
+ if (!config_check_cond(srv, con, dc)) continue;
+
+ /* merge config */
+ for (j = 0; j < dc->value->used; j++) {
+ data_unset *du = dc->value->data[j];
+
+ if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
+ PATCH(max_conns);
+ }
+ }
+ }
+
+ return 0;
+}
+#undef PATCH
+
+URIHANDLER_FUNC(mod_evasive_uri_handler) {
+ plugin_data *p = p_d;
+ size_t conns_by_ip = 0;
+ size_t j;
+
+ if (con->uri.path->used == 0) return HANDLER_GO_ON;
+
+ mod_evasive_patch_connection(srv, con, p);
+
+ /* no limit set, nothing to block */
+ if (p->conf.max_conns == 0) return HANDLER_GO_ON;
+
+ for (j = 0; j < srv->conns->used; j++) {
+ connection *c = srv->conns->ptr[j];
+
+ /* check if other connections are already actively serving data for the same IP
+ * we can only ban connections which are already behind the 'read request' state
+ * */
+ if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
+ c->state > CON_STATE_REQUEST_END) {
+ conns_by_ip++;
+
+ if (conns_by_ip > p->conf.max_conns) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
+ "turned away. Too many connections.");
+
+ con->http_status = 403;
+ return HANDLER_FINISHED;
+ }
+ }
+ }
+
+ return HANDLER_GO_ON;
+}
+
+
+int mod_evasive_plugin_init(plugin *p) {
+ p->version = LIGHTTPD_VERSION_ID;
+ p->name = buffer_init_string("evasive");
+
+ p->init = mod_evasive_init;
+ p->set_defaults = mod_evasive_set_defaults;
+ p->handle_uri_clean = mod_evasive_uri_handler;
+ p->cleanup = mod_evasive_free;
+
+ p->data = NULL;
+
+ return 0;
+}
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index 890062c..8b1be0a 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -69,20 +69,24 @@ typedef struct fcgi_proc {
size_t requests; /* see max_requests */
struct fcgi_proc *prev, *next; /* see first */
- time_t disable_ts; /* replace by host->something */
+ time_t disabled_until; /* this proc is disabled until, use something else until than */
int is_local;
- enum { PROC_STATE_UNSET, /* init-phase */
- PROC_STATE_RUNNING, /* alive */
- PROC_STATE_DIED_WAIT_FOR_PID,
- PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
- PROC_STATE_DIED, /* marked as dead, should be restarted */
- PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
+ enum {
+ PROC_STATE_UNSET, /* init-phase */
+ PROC_STATE_RUNNING, /* alive */
+ PROC_STATE_DIED_WAIT_FOR_PID,
+ PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
+ PROC_STATE_DIED, /* marked as dead, should be restarted */
+ PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
} state;
} fcgi_proc;
typedef struct {
+ /* the key that is used to reference this value */
+ buffer *id;
+
/* list of processes handling this extension
* sorted by lowest load
*
@@ -300,6 +304,8 @@ typedef struct {
buffer *path;
buffer *parse_response;
+
+ buffer *statuskey;
plugin_config **config_storage;
@@ -307,13 +313,19 @@ typedef struct {
} plugin_data;
/* connection specific data */
-typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
- FCGI_STATE_WRITE, FCGI_STATE_READ
+typedef enum {
+ FCGI_STATE_UNSET,
+ FCGI_STATE_INIT,
+ FCGI_STATE_CONNECT_DELAYED,
+ FCGI_STATE_PREPARE_WRITE,
+ FCGI_STATE_WRITE,
+ FCGI_STATE_READ
} fcgi_connection_state_t;
typedef struct {
fcgi_proc *proc;
fcgi_extension_host *host;
+ fcgi_extension *ext;
fcgi_connection_state_t state;
time_t state_timestamp;
@@ -325,8 +337,6 @@ typedef struct {
buffer *response_header;
- int delayed; /* flag to mark that the connect() is delayed */
-
size_t request_id;
int fd; /* fd to the fastcgi process */
int fde_ndx; /* index into the fd-event buffer */
@@ -348,7 +358,74 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc);
+data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
+ data_integer *di;
+
+ if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
+ /* not found, create it */
+
+ if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
+ di = data_integer_init();
+ }
+ buffer_copy_string_len(di->key, s, len);
+ di->value = 0;
+
+ array_insert_unique(srv->status, (data_unset *)di);
+ }
+ return di;
+}
+
+/* dummies of the statistic framework functions
+ * they will be moved to a statistics.c later */
+int status_counter_inc(server *srv, const char *s, size_t len) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ di->value++;
+
+ return 0;
+}
+
+int status_counter_dec(server *srv, const char *s, size_t len) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ if (di->value > 0) di->value--;
+
+ return 0;
+}
+
+int status_counter_set(server *srv, const char *s, size_t len, int val) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ di->value = val;
+ return 0;
+}
+
+int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
+ buffer_copy_string(b, "fastcgi.backend.");
+ buffer_append_string_buffer(b, host->id);
+ buffer_append_string(b, ".");
+ buffer_append_long(b, proc->id);
+
+ return 0;
+}
+
+int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
+#define CLEAN(x) \
+ fastcgi_status_copy_procname(b, host, proc); \
+ buffer_append_string(b, x); \
+ status_counter_set(srv, CONST_BUF_LEN(b), 0);
+
+ CLEAN(".disabled");
+ CLEAN(".died");
+ CLEAN(".overloaded");
+ CLEAN(".connected");
+ CLEAN(".load");
+
+#undef CLEAN
+
+ return 0;
+}
static handler_ctx * handler_ctx_init() {
handler_ctx * hctx;
@@ -366,8 +443,6 @@ static handler_ctx * handler_ctx_init() {
hctx->fd = -1;
- hctx->delayed = 0;
-
hctx->reconnects = 0;
hctx->send_content_body = 1;
@@ -413,6 +488,7 @@ fcgi_extension_host *fastcgi_host_init() {
f = calloc(1, sizeof(*f));
+ f->id = buffer_init();
f->host = buffer_init();
f->unixsocket = buffer_init();
f->docroot = buffer_init();
@@ -427,6 +503,7 @@ fcgi_extension_host *fastcgi_host_init() {
void fastcgi_host_free(fcgi_extension_host *h) {
if (!h) return;
+ buffer_free(h->id);
buffer_free(h->host);
buffer_free(h->unixsocket);
buffer_free(h->docroot);
@@ -540,6 +617,8 @@ INIT_FUNC(mod_fastcgi_init) {
p->path = buffer_init();
p->parse_response = buffer_init();
+
+ p->statuskey = buffer_init();
return p;
}
@@ -556,6 +635,7 @@ FREE_FUNC(mod_fastcgi_free) {
buffer_free(p->fcgi_env);
buffer_free(p->path);
buffer_free(p->parse_response);
+ buffer_free(p->statuskey);
if (p->config_storage) {
size_t i, j, n;
@@ -824,6 +904,7 @@ static int fcgi_spawn_connection(server *srv,
switch ((child = fork())) {
case 0: {
size_t i = 0;
+ char *c;
char_array env;
char_array arg;
@@ -888,6 +969,20 @@ static int fcgi_spawn_connection(server *srv,
parse_binpath(&arg, host->bin_path);
+ /* chdir into the base of the bin-path,
+ * search for the last / */
+ if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
+ *c = '\0';
+
+ /* change to the physical directory */
+ if (-1 == chdir(arg.ptr[0])) {
+ *c = '/';
+ log_error_write(srv, __FILE__, __LINE__, "sss", "chdir failed:", strerror(errno), arg.ptr[0]);
+ }
+ *c = '/';
+ }
+
+
/* exec the cgi */
execve(arg.ptr[0], arg.ptr, env.ptr);
@@ -1058,7 +1153,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
for (n = 0; n < da_ext->value->used; n++) {
data_array *da_host = (data_array *)da_ext->value->data[n];
- fcgi_extension_host *df;
+ fcgi_extension_host *host;
config_values_t fcv[] = {
{ "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
@@ -1094,54 +1189,56 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
return HANDLER_ERROR;
}
- df = fastcgi_host_init();
+ host = fastcgi_host_init();
- df->check_local = 1;
- df->min_procs = 4;
- df->max_procs = 4;
- df->max_load_per_proc = 1;
- df->idle_timeout = 60;
- df->mode = FCGI_RESPONDER;
- df->disable_time = 60;
- df->break_scriptfilename_for_php = 0;
- df->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
+ buffer_copy_string_buffer(host->id, da_host->key);
+
+ host->check_local = 1;
+ host->min_procs = 4;
+ host->max_procs = 4;
+ host->max_load_per_proc = 1;
+ host->idle_timeout = 60;
+ host->mode = FCGI_RESPONDER;
+ host->disable_time = 60;
+ host->break_scriptfilename_for_php = 0;
+ host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
- fcv[0].destination = df->host;
- fcv[1].destination = df->docroot;
+ fcv[0].destination = host->host;
+ fcv[1].destination = host->docroot;
fcv[2].destination = fcgi_mode;
- fcv[3].destination = df->unixsocket;
- fcv[4].destination = df->bin_path;
+ fcv[3].destination = host->unixsocket;
+ fcv[4].destination = host->bin_path;
- fcv[5].destination = &(df->check_local);
- fcv[6].destination = &(df->port);
- fcv[7].destination = &(df->min_procs);
- fcv[8].destination = &(df->max_procs);
- fcv[9].destination = &(df->max_load_per_proc);
- fcv[10].destination = &(df->idle_timeout);
- fcv[11].destination = &(df->disable_time);
+ fcv[5].destination = &(host->check_local);
+ fcv[6].destination = &(host->port);
+ fcv[7].destination = &(host->min_procs);
+ fcv[8].destination = &(host->max_procs);
+ fcv[9].destination = &(host->max_load_per_proc);
+ fcv[10].destination = &(host->idle_timeout);
+ fcv[11].destination = &(host->disable_time);
- fcv[12].destination = df->bin_env;
- fcv[13].destination = df->bin_env_copy;
- fcv[14].destination = &(df->break_scriptfilename_for_php);
- fcv[15].destination = &(df->allow_xsendfile);
- fcv[16].destination = df->strip_request_uri;
+ fcv[12].destination = host->bin_env;
+ fcv[13].destination = host->bin_env_copy;
+ fcv[14].destination = &(host->break_scriptfilename_for_php);
+ fcv[15].destination = &(host->allow_xsendfile);
+ fcv[16].destination = host->strip_request_uri;
if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
return HANDLER_ERROR;
}
- if ((!buffer_is_empty(df->host) || df->port) &&
- !buffer_is_empty(df->unixsocket)) {
+ if ((!buffer_is_empty(host->host) || host->port) &&
+ !buffer_is_empty(host->unixsocket)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"either host+port or socket");
return HANDLER_ERROR;
}
- if (!buffer_is_empty(df->unixsocket)) {
+ if (!buffer_is_empty(host->unixsocket)) {
/* unix domain socket */
- if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
+ if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
log_error_write(srv, __FILE__, __LINE__, "s",
"path of the unixdomain socket is too large");
return HANDLER_ERROR;
@@ -1149,8 +1246,8 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
} else {
/* tcp/ip */
- if (buffer_is_empty(df->host) &&
- buffer_is_empty(df->bin_path)) {
+ if (buffer_is_empty(host->host) &&
+ buffer_is_empty(host->bin_path)) {
log_error_write(srv, __FILE__, __LINE__, "sbbbs",
"missing key (string):",
da->key,
@@ -1159,7 +1256,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
"host");
return HANDLER_ERROR;
- } else if (df->port == 0) {
+ } else if (host->port == 0) {
log_error_write(srv, __FILE__, __LINE__, "sbbbs",
"missing key (short):",
da->key,
@@ -1170,37 +1267,37 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
}
}
- if (!buffer_is_empty(df->bin_path)) {
+ if (!buffer_is_empty(host->bin_path)) {
/* a local socket + self spawning */
size_t pno;
/* HACK: just to make sure the adaptive spawing is disabled */
- df->min_procs = df->max_procs;
+ host->min_procs = host->max_procs;
- if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
- if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
+ if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
+ if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
"--- fastcgi spawning local",
- "\n\tproc:", df->bin_path,
- "\n\tport:", df->port,
- "\n\tsocket", df->unixsocket,
- "\n\tmin-procs:", df->min_procs,
- "\n\tmax-procs:", df->max_procs);
+ "\n\tproc:", host->bin_path,
+ "\n\tport:", host->port,
+ "\n\tsocket", host->unixsocket,
+ "\n\tmin-procs:", host->min_procs,
+ "\n\tmax-procs:", host->max_procs);
}
- for (pno = 0; pno < df->min_procs; pno++) {
+ for (pno = 0; pno < host->min_procs; pno++) {
fcgi_proc *proc;
proc = fastcgi_process_init();
- proc->id = df->num_procs++;
- df->max_id++;
+ proc->id = host->num_procs++;
+ host->max_id++;
- if (buffer_is_empty(df->unixsocket)) {
- proc->port = df->port + pno;
+ if (buffer_is_empty(host->unixsocket)) {
+ proc->port = host->port + pno;
} else {
- buffer_copy_string_buffer(proc->socket, df->unixsocket);
+ buffer_copy_string_buffer(proc->socket, host->unixsocket);
buffer_append_string(proc->socket, "-");
buffer_append_long(proc->socket, pno);
}
@@ -1208,49 +1305,53 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
"--- fastcgi spawning",
- "\n\tport:", df->port,
- "\n\tsocket", df->unixsocket,
- "\n\tcurrent:", pno, "/", df->min_procs);
+ "\n\tport:", host->port,
+ "\n\tsocket", host->unixsocket,
+ "\n\tcurrent:", pno, "/", host->min_procs);
}
- if (fcgi_spawn_connection(srv, p, df, proc)) {
+ if (fcgi_spawn_connection(srv, p, host, proc)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"[ERROR]: spawning fcgi failed.");
return HANDLER_ERROR;
}
+
+ fastcgi_status_init(srv, p->statuskey, host, proc);
- proc->next = df->first;
- if (df->first) df->first->prev = proc;
+ proc->next = host->first;
+ if (host->first) host->first->prev = proc;
- df->first = proc;
+ host->first = proc;
}
} else {
- fcgi_proc *fp;
+ fcgi_proc *proc;
- fp = fastcgi_process_init();
- fp->id = df->num_procs++;
- df->max_id++;
- df->active_procs++;
- fp->state = PROC_STATE_RUNNING;
+ proc = fastcgi_process_init();
+ proc->id = host->num_procs++;
+ host->max_id++;
+ host->active_procs++;
+ proc->state = PROC_STATE_RUNNING;
- if (buffer_is_empty(df->unixsocket)) {
- fp->port = df->port;
+ if (buffer_is_empty(host->unixsocket)) {
+ proc->port = host->port;
} else {
- buffer_copy_string_buffer(fp->socket, df->unixsocket);
+ buffer_copy_string_buffer(proc->socket, host->unixsocket);
}
- df->first = fp;
+ fastcgi_status_init(srv, p->statuskey, host, proc);
+
+ host->first = proc;
- df->min_procs = 1;
- df->max_procs = 1;
+ host->min_procs = 1;
+ host->max_procs = 1;
}
if (!buffer_is_empty(fcgi_mode)) {
if (strcmp(fcgi_mode->ptr, "responder") == 0) {
- df->mode = FCGI_RESPONDER;
+ host->mode = FCGI_RESPONDER;
} else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {
- df->mode = FCGI_AUTHORIZER;
- if (buffer_is_empty(df->docroot)) {
+ host->mode = FCGI_AUTHORIZER;
+ if (buffer_is_empty(host->docroot)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: docroot is required for authorizer mode.");
return HANDLER_ERROR;
@@ -1261,9 +1362,9 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
fcgi_mode, "(ignored, mode set to responder)");
}
}
-
+
/* if extension already exists, take it */
- fastcgi_extension_insert(s->exts, da_ext->key, df);
+ fastcgi_extension_insert(s->exts, da_ext->key, host);
}
}
}
@@ -1327,7 +1428,6 @@ static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
return 0;
}
-
void fcgi_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
@@ -1360,6 +1460,13 @@ void fcgi_connection_close(server *srv, handler_ctx *hctx) {
/* after the connect the process gets a load */
hctx->proc->load--;
+ status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".load");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddb",
"release proc:",
@@ -1397,11 +1504,13 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
* we have a connection but the child died by some other reason
*
*/
-
- fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
- fdevent_unregister(srv->ev, hctx->fd);
- close(hctx->fd);
- srv->cur_fds--;
+
+ if (hctx->fd != -1) {
+ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
+ fdevent_unregister(srv->ev, hctx->fd);
+ close(hctx->fd);
+ srv->cur_fds--;
+ }
fcgi_requestid_del(srv, p, hctx->request_id);
@@ -1416,9 +1525,14 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
hctx->fd,
hctx->proc->pid, hctx->proc->socket);
}
-
- hctx->proc->load--;
- fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
+
+ if (hctx->proc) {
+ hctx->proc->load--;
+ fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
+ }
+
+ /* perhaps another host gives us more luck */
+ hctx->host = NULL;
return 0;
}
@@ -1491,7 +1605,15 @@ static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_
* 1 not connected yet
*/
-static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
+typedef enum {
+ CONNECTION_UNSET,
+ CONNECTION_OK,
+ CONNECTION_DELAYED, /* retry after event, take same host */
+ CONNECTION_OVERLOADED, /* disable for 1 seconds, take another backend */
+ CONNECTION_DEAD /* disable for 60 seconds, take another backend */
+} connection_result_t;
+
+static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) {
struct sockaddr *fcgi_addr;
struct sockaddr_in fcgi_addr_in;
#ifdef HAVE_SYS_UN_H
@@ -1540,57 +1662,37 @@ static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
errno == EALREADY ||
errno == EINTR) {
if (hctx->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "connect delayed, will continue later:", fcgi_fd);
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "connect delayed, will continue later:", host->host);
}
- return 1;
+ return CONNECTION_DELAYED;
} else if (errno == EAGAIN) {
-#if 0
- if(hctx->delayed == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sdsdsdb",
- "need reconnect, will continue later:", fcgi_fd,
- "reconnects:", hctx->reconnects,
- "load:", host->load,
- host->unixsocket);
+ if (hctx->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
+ "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
+ "The load for this fastcgi backend is:", proc->load);
}
-#endif
- hctx->reconnects++;
- return -1;
+
+ return CONNECTION_OVERLOADED;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sdsddb",
- "connect failed:", fcgi_fd,
- strerror(errno), errno,
+ log_error_write(srv, __FILE__, __LINE__, "ssdb",
+ "connect failed:",
+ strerror(errno),
proc->port, proc->socket);
-#if 0
- if (errno == EAGAIN) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
- "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
- "The load for this fastcgi backend is:", proc->load);
- }
-#endif
-
- return -1;
+ return CONNECTION_DEAD;
}
}
-#if 0
- if(hctx->delayed == 1) {
- log_error_write(srv, __FILE__, __LINE__, "sdsdsdb",
- "reconnected:", fcgi_fd,
- "reconnects:", hctx->reconnects,
- "load:", host->load,
- host->unixsocket);
- }
-#endif
+
hctx->reconnects = 0;
if (hctx->conf.debug > 1) {
log_error_write(srv, __FILE__, __LINE__, "sd",
"connect succeeded: ", fcgi_fd);
}
- return 0;
+ return CONNECTION_OK;
}
static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
@@ -1639,9 +1741,15 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
for (j = 0; j < ds->key->used - 1; j++) {
- srv->tmp_buf->ptr[srv->tmp_buf->used++] =
- isalpha((unsigned char)ds->key->ptr[j]) ?
- toupper((unsigned char)ds->key->ptr[j]) : '_';
+ char c = '_';
+ if (light_isalpha(ds->key->ptr[j])) {
+ /* upper-case */
+ c = ds->key->ptr[j] & ~32;
+ } else if (light_isdigit(ds->key->ptr[j])) {
+ /* copy */
+ c = ds->key->ptr[j];
+ }
+ srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
}
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
@@ -2156,7 +2264,7 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
/* no header */
buffer_free(packet->b);
- log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header to small");
+ log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header too small");
return -1;
}
@@ -2260,11 +2368,12 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
b->used = r + 1; /* one extra for the fake \0 */
b->ptr[b->used - 1] = '\0';
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssdsdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsbsd",
"unexpected end-of-file (perhaps the fastcgi process died):",
"pid:", proc->pid,
- "fcgi-fd:", fcgi_fd,
- "remote-fd:", con->fd);
+ "socket:", proc->socket,
+ "host:", host->host,
+ "port:", proc->port);
return -1;
}
@@ -2279,9 +2388,6 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
/* check if we have at least one packet */
if (0 != fastcgi_get_packet(srv, hctx, &packet)) {
/* no full packet */
-
- hctx->delayed = 1;
-
break;
}
@@ -2546,7 +2652,7 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
proc->pid);
}
- if (0 == proc->is_local) {
+ if (!proc->is_local) {
/*
* external servers might get disabled
*
@@ -2554,10 +2660,15 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
*/
if ((proc->state == PROC_STATE_DISABLED) &&
- (srv->cur_ts - proc->disable_ts > host->disable_time)) {
+ (srv->cur_ts > proc->disabled_until)) {
proc->state = PROC_STATE_RUNNING;
host->active_procs++;
+ fastcgi_status_copy_procname(p->statuskey, host, proc);
+ buffer_append_string(p->statuskey, ".disabled");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 0);
+
log_error_write(srv, __FILE__, __LINE__, "sbdb",
"fcgi-server re-enabled:",
host->host, host->port,
@@ -2626,7 +2737,6 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
return 0;
}
-
static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
fcgi_extension_host *host= hctx->host;
@@ -2645,10 +2755,60 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
host->unixsocket->used);
return HANDLER_ERROR;
}
+
+ /* we can't handle this in the switch as we have to fall through in it */
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
+ int socket_error;
+ socklen_t socket_error_len = sizeof(socket_error);
+
+ /* try to finish the connect() */
+ if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "getsockopt failed:", strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+ if (socket_error != 0) {
+ if (!hctx->proc->is_local || p->conf.debug) {
+ /* local procs get restarted */
+
+ log_error_write(srv, __FILE__, __LINE__, "sssd",
+ "establishing connection failed:", strerror(socket_error),
+ "port:", hctx->proc->port);
+ }
+ hctx->proc->disabled_until = srv->cur_ts + 10;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".died");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ return HANDLER_ERROR;
+ }
+ /* go on with preparing the request */
+ hctx->state = FCGI_STATE_PREPARE_WRITE;
+ }
+
switch(hctx->state) {
+ case FCGI_STATE_CONNECT_DELAYED:
+ /* should never happen */
+ break;
case FCGI_STATE_INIT:
+ /* do we have a running process for this host (max-procs) ? */
+
+ for (hctx->proc = hctx->host->first;
+ hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
+ hctx->proc = hctx->proc->next);
+
+ /* all childs are dead */
+ if (hctx->proc == NULL) {
+ hctx->fde_ndx = -1;
+
+ return HANDLER_ERROR;
+ }
+
ret = host->unixsocket->used ? AF_UNIX : AF_INET;
if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
@@ -2672,80 +2832,88 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss",
- "fcntl failed: ", strerror(errno));
+ "fcntl failed:", strerror(errno));
return HANDLER_ERROR;
}
-
- /* fall through */
- case FCGI_STATE_CONNECT:
- if (hctx->state == FCGI_STATE_INIT || hctx->delayed == 1) {
- for (hctx->proc = hctx->host->first;
- hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
- hctx->proc = hctx->proc->next);
-
- /* all childs are dead */
- if (hctx->proc == NULL) {
- hctx->fde_ndx = -1;
-
- return HANDLER_ERROR;
- }
- if (hctx->proc->is_local) {
- hctx->pid = hctx->proc->pid;
- }
+ if (hctx->proc->is_local) {
+ hctx->pid = hctx->proc->pid;
+ }
- switch (fcgi_establish_connection(srv, hctx)) {
- case 1:
- fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
-
- /* connection is in progress, wait for an event and call getsockopt() below */
-
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
- hctx->delayed = 0;
- return HANDLER_WAIT_FOR_EVENT;
- case -1:
- /* if ECONNREFUSED/EAGAIN re-try connect() */
-
- fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
- hctx->delayed = 1;
- return HANDLER_WAIT_FOR_EVENT;
- default:
- /* everything is ok, go on */
- break;
- }
+ switch (fcgi_establish_connection(srv, hctx)) {
+ case CONNECTION_DELAYED:
+ /* connection is in progress, wait for an event and call getsockopt() below */
+
+ fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
+ fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
+ return HANDLER_WAIT_FOR_EVENT;
+ case CONNECTION_OVERLOADED:
+ /* cool down the backend, it is overloaded
+ * -> EAGAIN */
- } else {
- int socket_error;
- socklen_t socket_error_len = sizeof(socket_error);
+ log_error_write(srv, __FILE__, __LINE__, "ssdsdb",
+ "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:"
+ "reconnects:", hctx->reconnects,
+ "load:", host->load,
+ host->unixsocket);
+
+
+ hctx->proc->disabled_until = srv->cur_ts + 2;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".overloaded");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
- /* try to finish the connect() */
- if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "getsockopt failed:", strerror(errno));
-
- return HANDLER_ERROR;
- }
- if (socket_error != 0) {
- if (!hctx->proc->is_local || p->conf.debug) {
- /* local procs get restarted */
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "establishing connection failed:", strerror(socket_error),
- "port:", hctx->proc->port);
- }
-
- return HANDLER_ERROR;
- }
+ return HANDLER_ERROR;
+ case CONNECTION_DEAD:
+ /* we got a hard error from the backend like
+ * - ECONNREFUSED for tcp-ip sockets
+ * - ENOENT for unix-domain-sockets
+ *
+ * for check if the host is back in 10 seconds
+ * */
+
+ hctx->proc->disabled_until = srv->cur_ts + 10;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".died");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ return HANDLER_ERROR;
+ case CONNECTION_OK:
+ /* everything is ok, go on */
+
+ fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
+
+ break;
+ case CONNECTION_UNSET:
+ break;
}
+ case FCGI_STATE_PREPARE_WRITE:
/* ok, we have the connection */
hctx->proc->load++;
hctx->proc->last_used = srv->cur_ts;
hctx->got_proc = 1;
-
+
+ status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
+ status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".connected");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".load");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddbdd",
"got proc:",
@@ -2766,9 +2934,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
"fcgi-request is already in use:", hctx->request_id);
}
- fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
/* fall through */
- case FCGI_STATE_PREPARE_WRITE:
fcgi_create_env(srv, hctx, hctx->request_id);
fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
@@ -2847,6 +3013,9 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
return HANDLER_WAIT_FOR_EVENT;
}
+
+/* might be called on fdevent after a connect() is delay too
+ * */
SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
plugin_data *p = p_d;
@@ -2858,83 +3027,118 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
/* not my job */
if (con->mode != p->id) return HANDLER_GO_ON;
+
+ /* we don't have a host yet, choose one
+ * -> this happens in the first round
+ * and when the host died and we have to select a new one */
+ if (hctx->host == NULL) {
+ size_t k;
+ int ndx, used = -1;
+
+ /* get best server */
+ for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
+ host = hctx->ext->hosts[k];
+
+ /* we should have at least one proc that can do somthing */
+ if (host->active_procs == 0) continue;
+
+ if (used == -1 || host->load < used) {
+ used = host->load;
+
+ ndx = k;
+ }
+ }
+ /* found a server */
+ if (ndx == -1) {
+ /* all hosts are down */
+
+ fcgi_connection_close(srv, hctx);
+
+ con->http_status = 500;
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+ }
+
+ host = hctx->ext->hosts[ndx];
+
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
+ */
+
+ /* init handler-context */
+ hctx->host = host;
+ hctx->proc = NULL;
+ } else {
+ host = hctx->host;
+ }
+
/* ok, create the request */
switch(fcgi_write_request(srv, hctx)) {
case HANDLER_ERROR:
proc = hctx->proc;
host = hctx->host;
-#if 0
- if (proc &&
- 0 == proc->is_local &&
- proc->state != PROC_STATE_DISABLED) {
- /* only disable remote servers as we don't manage them*/
-
- log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
- host->host,
- proc->port,
- proc->socket);
-
- /* disable this server */
- proc->disable_ts = srv->cur_ts;
- proc->state = PROC_STATE_DISABLED;
- host->active_procs--;
- }
-#endif
-
if (hctx->state == FCGI_STATE_INIT ||
- hctx->state == FCGI_STATE_CONNECT) {
+ hctx->state == FCGI_STATE_CONNECT_DELAYED) {
/* connect() or getsockopt() failed,
* restart the request-handling
*/
- if (proc && proc->is_local) {
+ if (proc) {
+ if (proc->is_local) {
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to fastcgi failed, restarting the request-handling:",
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sbdb",
+ "connect() to fastcgi failed, restarting the request-handling:",
host->host,
proc->port,
proc->socket);
- }
+ }
- /*
- * several hctx might reference the same proc
- *
- * Only one of them should mark the proc as dead all the other
- * ones should just take a new one.
- *
- * If a new proc was started with the old struct this might lead
- * the mark a perfect proc as dead otherwise
- *
- */
- if (proc->state == PROC_STATE_RUNNING &&
- hctx->pid == proc->pid) {
- proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
+ /*
+ * several hctx might reference the same proc
+ *
+ * Only one of them should mark the proc as dead all the other
+ * ones should just take a new one.
+ *
+ * If a new proc was started with the old struct this might lead
+ * the mark a perfect proc as dead otherwise
+ *
+ */
+ if (proc->state == PROC_STATE_RUNNING &&
+ hctx->pid == proc->pid) {
+ proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
+ }
+ } else {
+ proc->state = PROC_STATE_DISABLED;
}
+ host->active_procs--;
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".disabled");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 1);
}
+
fcgi_restart_dead_procs(srv, p, host);
-
- fcgi_connection_close(srv, hctx);
-
- buffer_reset(con->physical.path);
- con->mode = DIRECT;
- joblist_append(srv, con); /* really ? */
- /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
- * and hope that the childs will be restarted
- *
- */
-
- /* we might get into a LOOP here
- *
- * but how to handle this ?
- *
- * if we enter a endless loop, we will burn the CPU
- *
- * let this handle by the loop-detection
- */
+ /* cleanup this request and let the request handler start this request again */
+ if (hctx->reconnects < 5) {
+ fcgi_reconnect(srv, hctx);
+ joblist_append(srv, con); /* in case we come from the event-handler */
+
+ return HANDLER_WAIT_FOR_FD;
+ } else {
+ fcgi_connection_close(srv, hctx);
- return HANDLER_WAIT_FOR_FD;
+ buffer_reset(con->physical.path);
+ con->mode = DIRECT;
+ con->http_status = 500;
+ joblist_append(srv, con); /* in case we come from the event-handler */
+
+ return HANDLER_FINISHED;
+ }
} else {
fcgi_connection_close(srv, hctx);
@@ -3054,7 +3258,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
fcgi_reconnect(srv, hctx);
log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "response not sent, request not sent, reconnection.",
+ "response not received, request not sent, reconnecting.",
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
@@ -3062,7 +3266,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
}
log_error_write(srv, __FILE__, __LINE__, "sosdsd",
- "response not sent, request sent:", hctx->wb->bytes_out,
+ "response not received, request sent:", hctx->wb->bytes_out,
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
@@ -3093,7 +3297,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
}
if (revents & FDEVENT_OUT) {
- if (hctx->state == FCGI_STATE_CONNECT ||
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
hctx->state == FCGI_STATE_WRITE) {
/* we are allowed to send something out
*
@@ -3110,7 +3314,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
/* perhaps this issue is already handled */
if (revents & FDEVENT_HUP) {
- if (hctx->state == FCGI_STATE_CONNECT) {
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
/* getoptsock will catch this one (right ?)
*
* if we are in connect we might get a EINPROGRESS
@@ -3193,16 +3397,15 @@ static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
plugin_data *p = p_d;
size_t s_len;
- int used = -1;
- int ndx;
size_t k;
buffer *fn;
fcgi_extension *extension = NULL;
+ fcgi_extension_host *host = NULL;
/* Possibly, we processed already this request */
if (con->file_started == 1) return HANDLER_GO_ON;
-
- fn = con->uri.path;
+
+ fn = uri_path_handler ? con->uri.path : con->physical.path;
if (fn->used == 0) {
return HANDLER_ERROR;
@@ -3237,124 +3440,118 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
if (k == p->conf.exts->used) {
return HANDLER_GO_ON;
}
-
+
/* get best server */
- for (k = 0, ndx = -1; k < extension->used; k++) {
- fcgi_extension_host *host = extension->hosts[k];
-
+ for (k = 0; k < extension->used; k++) {
+ host = extension->hosts[k];
+
/* we should have at least one proc that can do somthing */
- if (host->active_procs == 0) continue;
+ if (host->active_procs == 0) {
+ host = NULL;
- if (used == -1 || host->load < used) {
- used = host->load;
-
- ndx = k;
+ continue;
}
+
+ /* we found one host that is alive */
+ break;
}
- /* found a server */
- if (ndx != -1) {
- fcgi_extension_host *host = extension->hosts[ndx];
+ if (!host) {
+ /* sorry, we don't have a server alive for this ext */
+ buffer_reset(con->physical.path);
+ con->http_status = 500;
- /*
- * if check-local is disabled, use the uri.path handler
- *
- */
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "no fcgi-handler found for:",
+ fn);
- /* init handler-context */
- if (uri_path_handler) {
- if (host->check_local == 0) {
- handler_ctx *hctx;
- char *pathinfo;
-
- hctx = handler_ctx_init();
-
- hctx->remote_conn = con;
- hctx->plugin_data = p;
- hctx->host = host;
- hctx->proc = NULL;
+ return HANDLER_FINISHED;
+ }
- hctx->conf.exts = p->conf.exts;
- hctx->conf.debug = p->conf.debug;
-
- con->plugin_ctx[p->id] = hctx;
-
- host->load++;
-
- con->mode = p->id;
-
- if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
- }
-
- /* the prefix is the SCRIPT_NAME,
- * everthing from start to the next slash
- * this is important for check-local = "disable"
- *
- * if prefix = /admin.fcgi
- *
- * /admin.fcgi/foo/bar
- *
- * SCRIPT_NAME = /admin.fcgi
- * PATH_INFO = /foo/bar
- *
- * if prefix = /fcgi-bin/
- *
- * /fcgi-bin/foo/bar
- *
- * SCRIPT_NAME = /fcgi-bin/foo
- * PATH_INFO = /bar
- *
- */
-
- /* the rewrite is only done for /prefix/? matches */
- if (extension->key->ptr[0] == '/' &&
- con->uri.path->used > extension->key->used &&
- NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
- /* rewrite uri.path and pathinfo */
-
- buffer_copy_string(con->request.pathinfo, pathinfo);
-
- con->uri.path->used -= con->request.pathinfo->used - 1;
- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
- }
- }
- return HANDLER_GO_ON;
- } else {
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
+ */
+
+ /* init handler-context */
+ if (uri_path_handler) {
+ if (host->check_local == 0) {
handler_ctx *hctx;
+ char *pathinfo;
+
hctx = handler_ctx_init();
hctx->remote_conn = con;
hctx->plugin_data = p;
- hctx->host = host;
- hctx->proc = NULL;
-
+ hctx->proc = NULL;
+ hctx->ext = extension;
+
+
hctx->conf.exts = p->conf.exts;
hctx->conf.debug = p->conf.debug;
-
+
con->plugin_ctx[p->id] = hctx;
-
- host->load++;
-
+
con->mode = p->id;
-
+
if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "handling it in mod_fastcgi");
}
+
+ /* the prefix is the SCRIPT_NAME,
+ * everthing from start to the next slash
+ * this is important for check-local = "disable"
+ *
+ * if prefix = /admin.fcgi
+ *
+ * /admin.fcgi/foo/bar
+ *
+ * SCRIPT_NAME = /admin.fcgi
+ * PATH_INFO = /foo/bar
+ *
+ * if prefix = /fcgi-bin/
+ *
+ * /fcgi-bin/foo/bar
+ *
+ * SCRIPT_NAME = /fcgi-bin/foo
+ * PATH_INFO = /bar
+ *
+ */
- return HANDLER_GO_ON;
+ /* the rewrite is only done for /prefix/? matches */
+ if (extension->key->ptr[0] == '/' &&
+ con->uri.path->used > extension->key->used &&
+ NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
+ /* rewrite uri.path and pathinfo */
+
+ buffer_copy_string(con->request.pathinfo, pathinfo);
+
+ con->uri.path->used -= con->request.pathinfo->used - 1;
+ con->uri.path->ptr[con->uri.path->used - 1] = '\0';
+ }
}
} else {
- /* no handler found */
- buffer_reset(con->physical.path);
- con->http_status = 500;
+ handler_ctx *hctx;
+ hctx = handler_ctx_init();
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "no fcgi-handler found for:",
- fn);
+ hctx->remote_conn = con;
+ hctx->plugin_data = p;
+ hctx->proc = NULL;
+ hctx->ext = extension;
- return HANDLER_FINISHED;
+ hctx->conf.exts = p->conf.exts;
+ hctx->conf.debug = p->conf.debug;
+
+ con->plugin_ctx[p->id] = hctx;
+
+ con->mode = p->id;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
+ }
}
+
return HANDLER_GO_ON;
}
@@ -3380,7 +3577,7 @@ JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
break;
- case FCGI_STATE_CONNECT:
+ case FCGI_STATE_CONNECT_DELAYED:
case FCGI_STATE_WRITE:
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
@@ -3598,7 +3795,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
int mod_fastcgi_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
+ p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("fastcgi");
p->init = mod_fastcgi_init;
diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c
index ebe7657..bf13e09 100644
--- a/src/mod_mysql_vhost.c
+++ b/src/mod_mysql_vhost.c
@@ -413,7 +413,7 @@ int mod_mysql_vhost_plugin_init(plugin *p) {
p->init = mod_mysql_vhost_init;
p->cleanup = mod_mysql_vhost_cleanup;
- p->handle_connection_close = mod_mysql_vhost_handle_connection_close;
+ p->handle_request_done = mod_mysql_vhost_handle_connection_close;
p->set_defaults = mod_mysql_vhost_set_defaults;
p->handle_docroot = mod_mysql_vhost_handle_docroot;
diff --git a/src/mod_proxy.c b/src/mod_proxy.c
index c6a4660..6baf459 100644
--- a/src/mod_proxy.c
+++ b/src/mod_proxy.c
@@ -439,7 +439,12 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) {
BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
- proxy_set_header(con, "X-Host", con->request.http_host->ptr);
+ /* http_host is NOT is just a pointer to a buffer
+ * which is NULL if it is not set */
+ if (con->request.http_host &&
+ !buffer_is_empty(con->request.http_host)) {
+ proxy_set_header(con, "X-Host", con->request.http_host->ptr);
+ }
proxy_set_header(con, "X-Forwarded-Proto", con->conf.is_ssl ? "https" : "http");
/* request header */
diff --git a/src/mod_scgi.c b/src/mod_scgi.c
index 06713e9..a27b28a 100644
--- a/src/mod_scgi.c
+++ b/src/mod_scgi.c
@@ -2677,7 +2677,7 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i
/* Possibly, we processed already this request */
if (con->file_started == 1) return HANDLER_GO_ON;
- fn = con->uri.path;
+ fn = uri_path_handler ? con->uri.path : con->physical.path;
if (fn->used == 0) {
return HANDLER_ERROR;
diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c
index 5139507..1ea5a50 100644
--- a/src/mod_secure_download.c
+++ b/src/mod_secure_download.c
@@ -37,7 +37,7 @@ typedef struct {
buffer *secret;
buffer *uri_prefix;
- time_t timeout;
+ unsigned short timeout;
} plugin_config;
typedef struct {
diff --git a/src/mod_setenv.c b/src/mod_setenv.c
index 001b238..9501554 100644
--- a/src/mod_setenv.c
+++ b/src/mod_setenv.c
@@ -12,6 +12,10 @@
/* plugin config for all request/connections */
typedef struct {
+ int handled; /* make sure that we only apply the headers once */
+} handler_ctx;
+
+typedef struct {
array *request_header;
array *response_header;
@@ -26,6 +30,21 @@ typedef struct {
plugin_config conf;
} plugin_data;
+static handler_ctx * handler_ctx_init() {
+ handler_ctx * hctx;
+
+ hctx = calloc(1, sizeof(*hctx));
+
+ hctx->handled = 0;
+
+ return hctx;
+}
+
+static void handler_ctx_free(handler_ctx *hctx) {
+ free(hctx);
+}
+
+
/* init the plugin data */
INIT_FUNC(mod_setenv_init) {
plugin_data *p;
@@ -140,7 +159,22 @@ static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data
URIHANDLER_FUNC(mod_setenv_uri_handler) {
plugin_data *p = p_d;
size_t k;
-
+ handler_ctx *hctx;
+
+ if (con->plugin_ctx[p->id]) {
+ hctx = con->plugin_ctx[p->id];
+ } else {
+ hctx = handler_ctx_init();
+
+ con->plugin_ctx[p->id] = hctx;
+ }
+
+ if (hctx->handled) {
+ return HANDLER_GO_ON;
+ }
+
+ hctx->handled = 1;
+
mod_setenv_patch_connection(srv, con, p);
for (k = 0; k < p->conf.request_header->used; k++) {
@@ -181,6 +215,19 @@ URIHANDLER_FUNC(mod_setenv_uri_handler) {
return HANDLER_GO_ON;
}
+REQUESTDONE_FUNC(mod_setenv_reset) {
+ plugin_data *p = p_d;
+
+ UNUSED(srv);
+
+ if (con->plugin_ctx[p->id]) {
+ handler_ctx_free(con->plugin_ctx[p->id]);
+ con->plugin_ctx[p->id] = NULL;
+ }
+
+ return HANDLER_GO_ON;
+}
+
/* this function is called at dlopen() time and inits the callbacks */
int mod_setenv_plugin_init(plugin *p) {
@@ -192,6 +239,8 @@ int mod_setenv_plugin_init(plugin *p) {
p->set_defaults = mod_setenv_set_defaults;
p->cleanup = mod_setenv_free;
+ p->handle_request_done = mod_setenv_reset;
+
p->data = NULL;
return 0;
diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c
index 6496689..cbc443d 100644
--- a/src/mod_staticfile.c
+++ b/src/mod_staticfile.c
@@ -372,17 +372,11 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
/* ignore certain extensions */
for (k = 0; k < p->conf.exclude_ext->used; k++) {
- int ct_len;
-
ds = (data_string *)p->conf.exclude_ext->data[k];
-
- ct_len = ds->value->used - 1;
-
- if (ct_len > s_len) continue;
if (ds->value->used == 0) continue;
-
- if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
+
+ if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
return HANDLER_GO_ON;
}
}
@@ -446,13 +440,27 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) {
if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
return HANDLER_FINISHED;
} else if (con->request.http_range && con->conf.range_requests) {
- /* content prepared, I'm done */
- con->file_finished = 1;
+ int do_range_request = 1;
+ /* check if we have a conditional GET */
+
+ if (NULL != (ds = array_get_element(con->request.headers, "If-Range"))) {
+ /* if the value is the same as our ETag, we do a Range-request,
+ * otherwise a full 200 */
+
+ if (!buffer_is_equal(ds->value, con->physical.etag)) {
+ do_range_request = 0;
+ }
+ }
+
+ if (do_range_request) {
+ /* content prepared, I'm done */
+ con->file_finished = 1;
- if (0 == http_response_parse_range(srv, con, p)) {
- con->http_status = 206;
+ if (0 == http_response_parse_range(srv, con, p)) {
+ con->http_status = 206;
+ }
+ return HANDLER_FINISHED;
}
- return HANDLER_FINISHED;
}
/* if we are still here, prepare body */
diff --git a/src/mod_status.c b/src/mod_status.c
index f69a1f4..f5a35e9 100644
--- a/src/mod_status.c
+++ b/src/mod_status.c
@@ -22,6 +22,8 @@
typedef struct {
buffer *config_url;
buffer *status_url;
+ buffer *statistics_url;
+
int sort;
} plugin_config;
@@ -84,6 +86,7 @@ FREE_FUNC(mod_status_free) {
plugin_config *s = p->config_storage[i];
buffer_free(s->status_url);
+ buffer_free(s->statistics_url);
buffer_free(s->config_url);
free(s);
@@ -104,7 +107,8 @@ SETDEFAULTS_FUNC(mod_status_set_defaults) {
config_values_t cv[] = {
{ "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
- { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
+ { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
+ { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
{ NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
};
@@ -119,10 +123,12 @@ SETDEFAULTS_FUNC(mod_status_set_defaults) {
s->config_url = buffer_init();
s->status_url = buffer_init();
s->sort = 1;
+ s->statistics_url = buffer_init();
cv[0].destination = s->status_url;
cv[1].destination = s->config_url;
cv[2].destination = &(s->sort);
+ cv[3].destination = s->statistics_url;
p->config_storage[i] = s;
@@ -575,6 +581,40 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c
return 0;
}
+static handler_t mod_status_handle_server_statistics(server *srv, connection *con, void *p_d) {
+ plugin_data *p = p_d;
+ buffer *b, *m = p->module_list;
+ size_t i;
+ array *st = srv->status;
+
+ if (0 == st->used) {
+ /* we have nothing to send */
+ con->http_status = 204;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+ }
+
+ b = chunkqueue_get_append_buffer(con->write_queue);
+
+ for (i = 0; i < st->used; i++) {
+ size_t ndx = st->sorted[i];
+
+ buffer_append_string_buffer(b, st->data[ndx]->key);
+ buffer_append_string(b, ": ");
+ buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
+ buffer_append_string(b, "\n");
+ }
+
+ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
+
+ con->http_status = 200;
+ con->file_finished = 1;
+
+ return HANDLER_FINISHED;
+}
+
+
static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
@@ -638,9 +678,9 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v
mod_status_header_append(b, "Server-Features");
#ifdef HAVE_PCRE_H
- mod_status_row_append(b, "Rewrite Engine", "enabled");
+ mod_status_row_append(b, "RegEx Conditionals", "enabled");
#else
- mod_status_row_append(b, "Rewrite Engine", "disabled - pcre missing");
+ mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
#endif
mod_status_header_append(b, "Network Engine");
@@ -692,6 +732,7 @@ static int mod_status_patch_connection(server *srv, connection *con, plugin_data
PATCH(status_url);
PATCH(config_url);
PATCH(sort);
+ PATCH(statistics_url);
/* skip the first, the global context */
for (i = 1; i < srv->config_context->used; i++) {
@@ -711,6 +752,8 @@ static int mod_status_patch_connection(server *srv, connection *con, plugin_data
PATCH(config_url);
} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
PATCH(sort);
+ } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
+ PATCH(statistics_url);
}
}
}
@@ -729,6 +772,9 @@ static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
} else if (!buffer_is_empty(p->conf.config_url) &&
buffer_is_equal(p->conf.config_url, con->uri.path)) {
return mod_status_handle_server_config(srv, con, p_d);
+ } else if (!buffer_is_empty(p->conf.statistics_url) &&
+ buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
+ return mod_status_handle_server_statistics(srv, con, p_d);
}
return HANDLER_GO_ON;
diff --git a/src/mod_webdav.c b/src/mod_webdav.c
index 0e7a682..3306c73 100644
--- a/src/mod_webdav.c
+++ b/src/mod_webdav.c
@@ -291,6 +291,7 @@ static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data
PATCH(enabled);
PATCH(is_readonly);
+ PATCH(log_xml);
#ifdef USE_PROPPATCH
PATCH(sql);
@@ -1175,19 +1176,23 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
d.rel_path = buffer_init();
while(NULL != (de = readdir(dir))) {
- if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
- (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
+ if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
continue;
/* ignore the parent dir */
}
buffer_copy_string_buffer(d.path, dst->path);
BUFFER_APPEND_SLASH(d.path);
- buffer_append_string(d.path, de->d_name);
-
+
buffer_copy_string_buffer(d.rel_path, dst->rel_path);
BUFFER_APPEND_SLASH(d.rel_path);
- buffer_append_string(d.rel_path, de->d_name);
+
+ if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
+ /* don't append the . */
+ } else {
+ buffer_append_string(d.path, de->d_name);
+ buffer_append_string(d.rel_path, de->d_name);
+ }
buffer_reset(prop_200);
buffer_reset(prop_404);
@@ -1247,6 +1252,9 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
free(req_props);
}
+ buffer_free(prop_200);
+ buffer_free(prop_404);
+
buffer_append_string(b,"</D:multistatus>\n");
if (p->conf.log_xml) {
@@ -1531,10 +1539,10 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
buffer_path_simplify(p->uri.path, p->tmp_buf);
/* we now have a URI which is clean. transform it into a physical path */
- buffer_copy_string_buffer(p->physical.doc_root, con->conf.document_root);
+ buffer_copy_string_buffer(p->physical.doc_root, con->physical.doc_root);
buffer_copy_string_buffer(p->physical.rel_path, p->uri.path);
- if (con->conf.force_lower_case) {
+ if (con->conf.force_lowercase_filenames) {
buffer_to_lower(p->physical.rel_path);
}
diff --git a/src/network.c b/src/network.c
index 40e9bba..922009f 100644
--- a/src/network.c
+++ b/src/network.c
@@ -71,6 +71,7 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
const char *host;
buffer *b;
int is_unix_domain_socket = 0;
+ int fd;
#ifdef SO_ACCEPTFILTER
struct accept_filter_arg afa;
@@ -254,6 +255,33 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
addr_len = strlen(host) + sizeof(srv_socket->addr.un.sun_family);
#endif
+ /* check if the socket exists and try to connect to it. */
+ if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
+ close(fd);
+
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "server socket is still in use:",
+ host);
+
+
+ return -1;
+ }
+
+ /* connect failed */
+ switch(errno) {
+ case ECONNREFUSED:
+ unlink(host);
+ break;
+ case ENOENT:
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "testing socket failed:",
+ host, strerror(errno));
+
+ return -1;
+ }
+
break;
default:
addr_len = 0;
@@ -262,7 +290,18 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) {
}
if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
- log_error_write(srv, __FILE__, __LINE__, "sds", "can't bind to port", port, strerror(errno));
+ switch(srv_socket->addr.plain.sa_family) {
+ case AF_UNIX:
+ log_error_write(srv, __FILE__, __LINE__, "sds",
+ "can't bind to socket:",
+ host, strerror(errno));
+ break;
+ default:
+ log_error_write(srv, __FILE__, __LINE__, "ssds",
+ "can't bind to port:",
+ host, port, strerror(errno));
+ break;
+ }
return -1;
}
diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c
index 5628a94..5752385 100644
--- a/src/network_linux_sendfile.c
+++ b/src/network_linux_sendfile.c
@@ -173,6 +173,11 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd,
return -1;
}
}
+
+ if (r == 0) {
+ /* we got a event to write put we couldn't. remote side closed ? */
+ return -2;
+ }
c->offset += r;
cq->bytes_out += r;
diff --git a/src/plugin.c b/src/plugin.c
index b375017..e74d8b0 100644
--- a/src/plugin.c
+++ b/src/plugin.c
@@ -66,6 +66,7 @@ static void plugin_free(plugin *p) {
/*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
#endif
+#ifndef LIGHTTPD_STATIC
if (use_dlclose && p->lib) {
#ifdef __WIN32
FreeLibrary(p->lib);
@@ -73,6 +74,7 @@ static void plugin_free(plugin *p) {
dlclose(p->lib);
#endif
}
+#endif
free(p);
}
@@ -100,7 +102,23 @@ static int plugins_register(server *srv, plugin *p) {
*
*/
+#ifdef LIGHTTPD_STATIC
+int plugins_load(server *srv) {
+ plugin *p;
+#define PLUGIN_INIT(x)\
+ p = plugin_init(); \
+ if (x ## _plugin_init(p)) { \
+ log_error_write(srv, __FILE__, __LINE__, "ss", #x, "plugin init failed" ); \
+ plugin_free(p); \
+ return -1;\
+ }\
+ plugins_register(srv, p);
+
+#include "plugin-static.h"
+ return 0;
+}
+#else
int plugins_load(server *srv) {
plugin *p;
int (*init)(plugin *pl);
@@ -205,6 +223,7 @@ int plugins_load(server *srv) {
return 0;
}
+#endif
#define PLUGIN_TO_SLOT(x, y) \
handler_t plugins_call_##y(server *srv, connection *con) {\
diff --git a/src/request.c b/src/request.c
index 0935725..db58671 100644
--- a/src/request.c
+++ b/src/request.c
@@ -791,6 +791,12 @@ int http_request_parse(server *srv, connection *con) {
* -> (10.4.18) 417 (close)
*
* (not handled at all yet, we always send 417 here)
+ *
+ * What has to be added ?
+ * 1. handling of chunked request body
+ * 2. out-of-order sending from the HTTP/1.1 100 Continue
+ * header
+ *
*/
con->http_status = 417;
@@ -815,9 +821,14 @@ int http_request_parse(server *srv, connection *con) {
return 0;
}
} else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
- /* if dup, only the first one will survive */
+ /* Proxies sometimes send dup headers
+ * if they are the same we ignore the second
+ * if not, we raise an error */
if (!con->request.http_if_modified_since) {
con->request.http_if_modified_since = ds->value->ptr;
+ } else if (0 == strcasecmp(con->request.http_if_modified_since,
+ ds->value->ptr)) {
+ /* ignore it if they are the same */
} else {
con->http_status = 400;
con->keep_alive = 0;
@@ -963,22 +974,25 @@ int http_request_parse(server *srv, connection *con) {
return 0;
}
-
- /* check if we have read post data */
- if (con->request.http_method == HTTP_METHOD_POST
- || (con->request.http_method != HTTP_METHOD_GET
- && con->request.http_method != HTTP_METHOD_HEAD
- && con->request.http_method != HTTP_METHOD_OPTIONS
- && con_length_set)) {
-#if 0
- if (con->request.http_content_type == NULL) {
+ switch(con->request.http_method) {
+ case HTTP_METHOD_GET:
+ case HTTP_METHOD_HEAD:
+ case HTTP_METHOD_OPTIONS:
+ /* content-length is forbidden for those */
+ if (con_length_set && con->request.content_length != 0) {
+ /* content-length is missing */
log_error_write(srv, __FILE__, __LINE__, "s",
- "Content-Length request, but content-type not set");
+ "GET/HEAD/OPTIONS with content-length -> 400");
+ con->keep_alive = 0;
+
+ con->http_status = 400;
+ return 0;
}
-#endif
-
- if (con_length_set == 0) {
+ break;
+ case HTTP_METHOD_POST:
+ /* content-length is required for them */
+ if (!con_length_set) {
/* content-length is missing */
log_error_write(srv, __FILE__, __LINE__, "s",
"POST-request, but content-length missing -> 411");
@@ -986,8 +1000,17 @@ int http_request_parse(server *srv, connection *con) {
con->http_status = 411;
return 0;
+
}
-
+ break;
+ default:
+ /* the may have a content-length */
+ break;
+ }
+
+
+ /* check if we have read post data */
+ if (con_length_set) {
/* don't handle more the SSIZE_MAX bytes in content-length */
if (con->request.content_length > SSIZE_MAX) {
con->http_status = 413;
diff --git a/src/response.c b/src/response.c
index 2617842..d955cec 100644
--- a/src/response.c
+++ b/src/response.c
@@ -133,6 +133,18 @@ handler_t http_response_prepare(server *srv, connection *con) {
/* no decision yet, build conf->filename */
if (con->mode == DIRECT && con->physical.path->used == 0) {
char *qstr;
+
+ /* we only come here when we have the parse the full request again
+ *
+ * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
+ * problem here as mod_setenv might get called multiple times
+ *
+ * fastcgi-auth might lead to a COMEBACK too
+ * fastcgi again dead server too
+ *
+ * mod_compress might add headers twice too
+ *
+ * */
if (con->conf.log_condition_handling) {
log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
@@ -334,7 +346,7 @@ handler_t http_response_prepare(server *srv, connection *con) {
*
* convert to lower-case
*/
- if (con->conf.force_lower_case) {
+ if (con->conf.force_lowercase_filenames) {
buffer_to_lower(con->physical.rel_path);
}
diff --git a/src/server.c b/src/server.c
index 5c515e3..9eb9eb4 100644
--- a/src/server.c
+++ b/src/server.c
@@ -50,6 +50,10 @@
#include <sys/resource.h>
#endif
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
#ifndef __sgi
/* IRIX doesn't like the alarm based time() optimization */
/* #define USE_ALARM */
@@ -67,7 +71,11 @@ static void sigaction_handler(int sig, siginfo_t *si, void *context) {
switch (sig) {
case SIGTERM: srv_shutdown = 1; break;
- case SIGINT: graceful_shutdown = 1; break;
+ case SIGINT:
+ if (graceful_shutdown) srv_shutdown = 1;
+ else graceful_shutdown = 1;
+
+ break;
case SIGALRM: handle_sig_alarm = 1; break;
case SIGHUP: handle_sig_hup = 1; break;
case SIGCHLD: break;
@@ -77,7 +85,11 @@ static void sigaction_handler(int sig, siginfo_t *si, void *context) {
static void signal_handler(int sig) {
switch (sig) {
case SIGTERM: srv_shutdown = 1; break;
- case SIGINT: graceful_shutdown = 1; break;
+ case SIGINT:
+ if (graceful_shutdown) srv_shutdown = 1;
+ else graceful_shutdown = 1;
+
+ break;
case SIGALRM: handle_sig_alarm = 1; break;
case SIGHUP: handle_sig_hup = 1; break;
case SIGCHLD: break;
@@ -144,6 +156,7 @@ static server *server_init(void) {
CLEAN(config_context);
CLEAN(config_touched);
+ CLEAN(status);
#undef CLEAN
for (i = 0; i < FILE_CACHE_MAX; i++) {
@@ -241,6 +254,7 @@ static void server_free(server *srv) {
CLEAN(config_context);
CLEAN(config_touched);
+ CLEAN(status);
#undef CLEAN
joblist_free(srv, srv->joblist);
@@ -323,7 +337,7 @@ int main (int argc, char **argv) {
setlocale(LC_TIME, "C");
if (NULL == (srv = server_init())) {
- fprintf(stderr, "did this really happend ?\n");
+ fprintf(stderr, "did this really happen?\n");
return -1;
}
@@ -521,6 +535,12 @@ int main (int argc, char **argv) {
} else {
srv->max_fds = rlim.rlim_cur;
}
+
+ /* set core file rlimit, if enable_cores is set */
+ if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit(RLIMIT_CORE, &rlim);
+ }
#endif
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
/* don't raise the limit above FD_SET_SIZE */
@@ -593,6 +613,11 @@ int main (int argc, char **argv) {
initgroups(srv->srvconf.username->ptr, grp->gr_gid);
if (srv->srvconf.username->used) setuid(pwd->pw_uid);
#endif
+#ifdef HAVE_PRCTL
+ if (srv->srvconf.enable_cores) {
+ prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
+ }
+#endif
} else {
#ifdef HAVE_GETRLIMIT
@@ -608,6 +633,13 @@ int main (int argc, char **argv) {
} else {
srv->max_fds = rlim.rlim_cur;
}
+
+ /* set core file rlimit, if enable_cores is set */
+ if (srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit(RLIMIT_CORE, &rlim);
+ }
+
#endif
if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
/* don't raise the limit above FD_SET_SIZE */
diff --git a/tests/LightyTest.pm b/tests/LightyTest.pm
index 37023d3..85a08ef 100755
--- a/tests/LightyTest.pm
+++ b/tests/LightyTest.pm
@@ -158,6 +158,8 @@ sub handle_http {
close $remote;
+ my $full_response = $lines;
+
my $href;
foreach $href ( @{ $t->{RESPONSE} }) {
# first line is always response header
@@ -181,13 +183,12 @@ sub handle_http {
if ($line =~ /^([^:]+):\s*(.+)$/) {
(my $h = $1) =~ tr/[A-Z]/[a-z]/;
-# if (defined $resp_hdr{$h}) {
-# diag(sprintf("header %s is duplicated: %s and %s\n",
-# $h, $resp_hdr{$h}, $2));
-# return -1;
-# }
-
- $resp_hdr{$h} = $2;
+ if (defined $resp_hdr{$h}) {
+ diag(sprintf("header %s is duplicated: %s and %s\n",
+ $h, $resp_hdr{$h}, $2));
+ } else {
+ $resp_hdr{$h} = $2;
+ }
} else {
diag(sprintf("unexpected line '$line'\n"));
return -1;
diff --git a/tests/docroot/www/dummydir/.svn/README.txt b/tests/docroot/www/dummydir/.svn/README.txt
deleted file mode 100644
index 271a8ce..0000000
--- a/tests/docroot/www/dummydir/.svn/README.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-This is a Subversion working copy administrative directory.
-Visit http://subversion.tigris.org/ for more information.
diff --git a/tests/docroot/www/dummydir/.svn/empty-file b/tests/docroot/www/dummydir/.svn/empty-file
deleted file mode 100644
index e69de29..0000000
--- a/tests/docroot/www/dummydir/.svn/empty-file
+++ /dev/null
diff --git a/tests/docroot/www/dummydir/.svn/entries b/tests/docroot/www/dummydir/.svn/entries
deleted file mode 100644
index d0722cd..0000000
--- a/tests/docroot/www/dummydir/.svn/entries
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<wc-entries
- xmlns="svn:">
-<entry
- committed-rev="1"
- name=""
- committed-date="2005-02-12T17:08:04.106079Z"
- url="svn://svn.lighttpd.net/lighttpd/branches/lighttpd-merge-1.4.x/tests/docroot/www/dummydir"
- last-author="jan"
- kind="dir"
- uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
- revision="803"/>
-</wc-entries>
diff --git a/tests/docroot/www/dummydir/.svn/format b/tests/docroot/www/dummydir/.svn/format
deleted file mode 100644
index b8626c4..0000000
--- a/tests/docroot/www/dummydir/.svn/format
+++ /dev/null
@@ -1 +0,0 @@
-4
diff --git a/tests/fastcgi-13.conf b/tests/fastcgi-13.conf
index 2d6a2bd..f351208 100644
--- a/tests/fastcgi-13.conf
+++ b/tests/fastcgi-13.conf
@@ -8,8 +8,6 @@ debug.log-request-handling = "enable"
## bind to port (default: 80)
server.port = 2048
-# server.license = "00000001000000013feccb804014587f000000010000000105911c976a3d462c8eaa2d7ca850432c"
-
## bind to localhost (default: all interfaces)
server.bind = "localhost"
server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
@@ -87,7 +85,7 @@ fastcgi.server = ( ".php" => (
"grisu" => (
"host" => "127.0.0.1",
"port" => 1048,
- "bin-path" => "/home/jan/Documents/php-5.1.0b3/sapi/cgi/php -c /usr/local/lib/php.ini",
+ "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
"bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
)
)
diff --git a/tests/mod-fastcgi.t b/tests/mod-fastcgi.t
index c6acec7..d3ea4a8 100755
--- a/tests/mod-fastcgi.t
+++ b/tests/mod-fastcgi.t
@@ -216,7 +216,7 @@ EOF
}
SKIP: {
- skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0b3/sapi/cgi/php";
+ skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php";
$tf->{CONFIGFILE} = 'fastcgi-13.conf';
ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
$t->{REQUEST} = ( <<EOF
diff --git a/tests/request.t b/tests/request.t
index 4049013..be1f5d8 100755
--- a/tests/request.t
+++ b/tests/request.t
@@ -8,7 +8,7 @@ BEGIN {
use strict;
use IO::Socket;
-use Test::More tests => 29;
+use Test::More tests => 33;
use LightyTest;
my $tf = LightyTest->new();
@@ -300,7 +300,45 @@ EOF
$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
ok($tf->handle_http($t) == 0, 'GET, Range with range-requests-disabled');
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+Content-Length: 4
+
+1234
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
+ok($tf->handle_http($t) == 0, 'GET with Content-Length');
+
+$t->{REQUEST} = ( <<EOF
+OPTIONS / HTTP/1.0
+Content-Length: 4
+
+1234
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
+ok($tf->handle_http($t) == 0, 'OPTIONS with Content-Length');
+$t->{REQUEST} = ( <<EOF
+HEAD / HTTP/1.0
+Content-Length: 4
+
+1234
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ];
+ok($tf->handle_http($t) == 0, 'HEAD with Content-Length');
+
+
+$t->{REQUEST} = ( <<EOF
+GET / HTTP/1.0
+If-Modified-Since: Sun, 1970 Jan 01 00:00:01 GMT
+If-Modified-Since: Sun, 1970 Jan 01 00:00:01 GMT
+EOF
+ );
+$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
+ok($tf->handle_http($t) == 0, 'Duplicate If-Mod-Since, with equal timestamps');
ok($tf->stop_proc == 0, "Stopping lighttpd");