diff options
author | Arno Töll <arno@debian.org> | 2012-11-21 23:03:42 +0100 |
---|---|---|
committer | Arno Töll <arno@debian.org> | 2012-11-21 23:03:42 +0100 |
commit | 1b24d86e6b2179692e60091dec59f797cd308b9e (patch) | |
tree | c5502d40d82fdef69ab9c1e4ed69904fefea9ac1 | |
parent | 6a6df8dc258631c6eaccb03bf08845241f6dfa4a (diff) | |
download | lighttpd-1b24d86e6b2179692e60091dec59f797cd308b9e.tar.gz |
Imported Upstream version 1.4.13upstream/1.4.13
208 files changed, 10457 insertions, 9639 deletions
@@ -17,15 +17,15 @@ modification, are permitted provided that the following conditions are met: be used to endorse or promote products derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @@ -24,14 +24,14 @@ This file is abondend in favour of the NEWS file unified test-scripts to use the same framework -14.06.2005 23:38 +14.06.2005 23:38 - documentation updated docs for mod_proxy and mod_scgi 12.06.2005 12:55 - pre-release - mod_fastcgi - + fixed event handling after delayed connect make retry timeout configurable @@ -85,11 +85,11 @@ This file is abondend in favour of the NEWS file fixed automatic redirects if SSL is used fixed compilation on Solaris [283] - + disable accept-filtering on FreeBSD if ssl is used [320] fixed handling of range-request larger than 2Gb - + fixed comparisions of mime-types to case-insensitive [266] added quotation of ETags [376], [378] @@ -121,7 +121,7 @@ This file is abondend in favour of the NEWS file - fastcgi fixed path-info for prefix-patterns - + fixed path-info for PHP 02.03.2005 14:47 - 1.3.12 @@ -131,8 +131,8 @@ This file is abondend in favour of the NEWS file initd and not to lighttpd. Moving the daemonize before starting the fastcgi procs fixes this. -01.03.2005 23:59 -- irix +01.03.2005 23:59 +- irix fixed minor compile issues with MIPSpro @@ -142,7 +142,7 @@ This file is abondend in favour of the NEWS file handle most duplicate headers as 400, Bug #25 - mod_fastcgi - + added more checks 28.02.2005 18:26 @@ -156,7 +156,7 @@ This file is abondend in favour of the NEWS file really compare timestamps, Bug #34 28.02.2005 11:54 -- buffer +- buffer rewrote int2buffer functions @@ -173,8 +173,8 @@ This file is abondend in favour of the NEWS file - cygwin - moved functions used by plugin and main-program to *-glue.c - + moved functions used by plugin and main-program to *-glue.c + - lemon removed warnings about shadowed variables @@ -190,7 +190,7 @@ This file is abondend in favour of the NEWS file - test cases rewrote to test-framework to use Perl + Test::More - ported more test-cases + ported more test-cases 22.02.2005 01:20 - mod_fastcgi @@ -251,22 +251,22 @@ This file is abondend in favour of the NEWS file compile error on MacOS X due to missing environ (patch by Johan Sörensen) (Bug #2) -- indexfiles +- indexfiles append the detected indexfile only once to uri.path (reported by Thomas Seifert) (Bug #3) - + 06.02.2005 15:16 - 1.3.10 - fastcgi display a error-message if a hostname if specified in fastcgi.server->host we need an IP here - + - debug added debug.log-state-handling - + - spawn-fcgi accept a full commandline for spawning @@ -275,7 +275,7 @@ This file is abondend in favour of the NEWS file - fastcgi fixed openssl handling - + - network_freebsd_sendfilev gracefull handling of connections closed on client-side @@ -294,13 +294,13 @@ This file is abondend in favour of the NEWS file - fastcgi added bin-environment to setup the environment of the spawned process - + added bin-copy-environment to copy only the specified set of options from the old environment - + added handling of cmd-line options to bin-path -- setenv +- setenv fixed crashed in setenv.add-response-header @@ -308,18 +308,18 @@ This file is abondend in favour of the NEWS file - configure fixed docs for --with-mysql - + - fastcgi improved performance of building the header (drop strlen()) -04.02.2005 01:59 +04.02.2005 01:59 - cgi don't send file on error - + check if cgi-handler exists before executing it - + added support for nph-... 02.02.2005 21:18 - pre-release @@ -336,9 +336,9 @@ This file is abondend in favour of the NEWS file - fastcgi delete sockets on shutdown - + - http/1.1 - + adding option to disable http/1.1 01.02.2005 12:03 @@ -352,15 +352,15 @@ This file is abondend in favour of the NEWS file - configure make check for valgrind.h covered by --with-valgrind - + - mod_localizer, mod_maps remove both plugins from the distribution - + - file-not-found handle file not found again - + 30.01.2005 16:44 - HEAD requests @@ -368,9 +368,9 @@ This file is abondend in favour of the NEWS file 30.01.2005 15:16 - 1.3.8 - network-handler - + remove debug output on writev() if the remote side closed the connection - + - directory index handle EACCES correctly @@ -379,7 +379,7 @@ This file is abondend in favour of the NEWS file - mod_alias fixed mod_alias + pathinfo handling - + - mod_accesslog added access-log to syslog patch from allan @@ -387,13 +387,13 @@ This file is abondend in favour of the NEWS file 28.01.2005 17:30 - directory redirect without Host-header - use server-ip instead of client-ip for the Location: + use server-ip instead of client-ip for the Location: - fastcgi + pathinfo if fastcgi-auth redirects to a directory which doesn't exist handle it correctly (bug introduced in 1.3.8) - + - requesting directories clean physical.path if directory is requested and dir-listing is disabled @@ -409,7 +409,7 @@ This file is abondend in favour of the NEWS file - fastcgi send content and headers if authorizer mode is used - + use a new connection if connection is died to fastcgi and we have not used it yet @@ -423,7 +423,7 @@ This file is abondend in favour of the NEWS file fixed write-failed after crash of fastcgi-child -16.01.2005 20:43 +16.01.2005 20:43 - setenv fixed setenv.add-environment @@ -475,10 +475,10 @@ This file is abondend in favour of the NEWS file report an error if ssl.engine is enable but no ssl support compiled in 08.01.2005 12:23 -- mod_status +- mod_status added request time to the output - + (late changelog) added host and filename to the output (fobax) (late changelog) HTMLalized the output (fobax) @@ -493,7 +493,7 @@ This file is abondend in favour of the NEWS file reworked the error-page handling -05.01.2005 13:10 +05.01.2005 13:10 - keep-alive handling made sure that keep-alive is really handled correctly @@ -502,7 +502,7 @@ This file is abondend in favour of the NEWS file - mod_setenv added a module to added request and response headers on the fly - + - error-log send error log to syslog() if no errorlogfile is specified (again) @@ -512,7 +512,7 @@ This file is abondend in favour of the NEWS file cut of body for status 301, 304 and 205 -- buffer +- buffer optimized all _hex functions (Silvan Minghetti) @@ -520,7 +520,7 @@ This file is abondend in favour of the NEWS file - fastcgi if bin-path is not specified, don't die (bug introduced in the last pre-rel) - + - auth if userfile is empty don't auth. @@ -533,18 +533,18 @@ This file is abondend in favour of the NEWS file 02.01.2005 16:10 - conditional config - fixed !~ and != - -- buffer + fixed !~ and != + +- buffer copy empty buffers correctly 31.12.2004 17:45 - ipv6 + pidfile - + don't complain if we can't remove the pidfile (Silvan Minghetti) - - remove ipv6 option from the commandline of lighttpd doesn't support + + remove ipv6 option from the commandline of lighttpd doesn't support ipv6 (Silvan Minghetti) 31.12.2004 15:41 - pre-release @@ -571,7 +571,7 @@ This file is abondend in favour of the NEWS file 28.12.2004 23:26 - traffic shaping - + added traffic shaping per connection 25.12.2004 22:58 @@ -585,15 +585,15 @@ This file is abondend in favour of the NEWS file added check for signal and select (compile fix for netbsd 1.4 and 1.5) 11.12.2004 12:38 - 1.3.7 -- fastcgi + php +- fastcgi + php - retry to connect to another PHP child if one of them dies after + retry to connect to another PHP child if one of them dies after connect - + - cgi + multipart don't transform CONTENT_TYPE to HTTP_CONTENT_TYPE - + - debian more cleanup, updated changelog, added more deps and suggests @@ -601,32 +601,32 @@ This file is abondend in favour of the NEWS file 10.12.2004 22:33 - event handler - - fixed crashes in kqueue + + fixed crashes in kqueue 10.12.2004 13:57 - pre-release -- mod_status +- mod_status fixed wraparound in total requests and total traffic - + - debian updated licence and packaging - + - security call setgroups() to get rid of all groups - + - ssl handle SSL_shutdown() == 0 correctly - + fixed openssl detection in configure - - fixed handling of chunked encoding - + + fixed handling of chunked encoding + - request handling - + handle Connection: keep-alive correctly (case as not ignored) 21.11.2004 02:39 @@ -637,23 +637,23 @@ This file is abondend in favour of the NEWS file 20.11.2004 18:43 - conditional - ported + ported - cgi - secdownload - expire - localizer - - usertrack + - usertrack - status - proxy - + - server-tag Server: ... can now be specified by server.tag = "..." - + - spawn-fcgi fixed typo in usage text - + - ssl fixed detection of libs and headers @@ -666,7 +666,7 @@ This file is abondend in favour of the NEWS file 04.11.2004 23:01 - ssi - added support for ${...} + added support for ${...} 03.11.2004 14:51 - 1.3.6 - fastcgi @@ -681,7 +681,7 @@ This file is abondend in favour of the NEWS file 02.11.2004 15:34 - fastcgi - + handle END-OF-REQUEST correctly if chunk-encoding is not used 02.11.2004 10:53 @@ -694,11 +694,11 @@ This file is abondend in favour of the NEWS file add REMOTE_USER, suppress AUTHORIZATION handle payloads > 4k - + - mod_alias fixed url checking - + - follow-symlink fixed config @@ -736,7 +736,7 @@ This file is abondend in favour of the NEWS file fixed offset calculations - ipv6 - + IPv6 might be disabled at compile-time - rewrite @@ -746,7 +746,7 @@ This file is abondend in favour of the NEWS file - auth forgot to reset the global-config handler - + - symlink add option to disable follow-symlink @@ -768,7 +768,7 @@ This file is abondend in favour of the NEWS file 22.10.2004 17:00 - accesslog - added logging of user-supplied data via %{...}o and + added logging of user-supplied data via %{...}o and X-LIGHTTPD-* header 22.10.2004 14:57 - pre-release @@ -776,18 +776,18 @@ This file is abondend in favour of the NEWS file fixed configure-checks and Makefile.am's to build cleanly with a cross-compiler - + builds cleanly for openwrt -22.10.2004 13:03 +22.10.2004 13:03 - out-of-fd improved the out-of-fd handler - + - cgi, fastcgi - set SERVER_NAME to server.name or the value submitted by Host: - + set SERVER_NAME to server.name or the value submitted by Host: + - error-handler only set old status code if it wasn't set by a handler @@ -796,7 +796,7 @@ This file is abondend in favour of the NEWS file - fastcgi don't crash on out-of-fd condition - + - out-of-fd try handle the out-of-fd condition in a sane way @@ -805,15 +805,15 @@ This file is abondend in favour of the NEWS file - mod_auth seperated auth.backend.*.userfile for plain, htpasswd and htdigest - + added 'digest-auth' against 'plain-backend' - + added auth.debug for debugging 16.10.2004 10:18 - 1.3.3 - mod_simple_vhost, mod_evhost - conditional-ized + conditional-ized - mod_rrdtool @@ -823,7 +823,7 @@ This file is abondend in favour of the NEWS file - accesslogs cycle all access-logs - + - mod_rewrite tell the user to install pcre.h if he wants to use mod_rewrite @@ -836,8 +836,8 @@ This file is abondend in favour of the NEWS file 09.10.2004 16:28 - pre-release - cgi - added support for \n in headers - + added support for \n in headers + - mod_auth added conditional auth @@ -858,11 +858,11 @@ This file is abondend in favour of the NEWS file drop a unused file-cache entry after 10 seconds reuse unused entries - + - request-parser accept IPv6 adresses in Host header - + - tests modified the scripts to work with zsh (check on Linux, Irix and FreeBSD) @@ -876,8 +876,8 @@ This file is abondend in favour of the NEWS file - cgi + cygwin cgi need s SYSTEMROOT environment - - + + 22.09.2004 08:55 - network @@ -894,11 +894,11 @@ This file is abondend in favour of the NEWS file fixed cleanup code (matt) -21.09.2004 20:08 -- rrdtool +21.09.2004 20:08 +- rrdtool rrdtool.db-name is now conditional - + fixed check if write() failed (adam) 17.09.2004 17:50 - 1.3.0 @@ -907,10 +907,10 @@ This file is abondend in favour of the NEWS file added url.rewrite-final = ... 17.09.2004 15:55 -- code cleanup +- code cleanup integrated the fixes from cygwin into the main tree - + - kqueue init kqueue after daemonizing (broken since 12.09.2004 14:02) @@ -939,11 +939,11 @@ This file is abondend in favour of the NEWS file - mod_proxy pass remote-addr as X-Forwarded-For to the real server behind the proxy - + - code cleanup moved all cut'n'paste versions of the inet_ntop cache to inet_ntop_cache.c - + - fcgi don't overwrite the fd in fcgi_establish connection if connect fails. this @@ -956,14 +956,14 @@ This file is abondend in favour of the NEWS file - last-modified - don't complain if the If-Modified-Since contains a valid comment/option + don't complain if the If-Modified-Since contains a valid comment/option like <timestamp>; length = ... 05.09.2004 09:13 - expires overwrite the Expire if it is set by a previous plugin - + - conditional config conditional config as disabled in 1.2.7 by accident @@ -977,34 +977,34 @@ This file is abondend in favour of the NEWS file fixed hanging process if cgi-crash terminates to fast (before we read its response) - + - extented attributes added xattr support, submitted by Ari 29.08.2004 16:00 -- rrdtool +- rrdtool moved the rrdtool support from mod_status into its own module mod_rrdtool - + rrdtool.binary = "/usr/bin/rrdtool" rrdtool.db-name = "/var/www/lighttpd.rrd" - + 29.08.2004 11:00 - pre-release - timeouts - server.max-keep-alive-requests = 0 replaces - server.use-keep-alive = "disable" - - added + server.max-keep-alive-requests = 0 replaces + server.use-keep-alive = "disable" + + added server.max-keep-alive-idle server.max-read-idle - server.max-write-idle - + server.max-write-idle + - docs added a entry for each config-value into configuration.txt - added simple docs for + added simple docs for rewrite redirect compress @@ -1015,23 +1015,23 @@ This file is abondend in favour of the NEWS file - config options complain if no configfile is specified - + - fastcgi removed stupid allocation bug which might cause a problem in really rare cases 26.08.2004 22:06 - 1.2.6 -- optimize +- optimize - use array_strcasecmp() in favour of strcasecmp() as it is slightly + use array_strcasecmp() in favour of strcasecmp() as it is slightly faster. - + apply the case-insentive conversion also on the last character. (adam) - + sort the checked elements in request.c and filter apply the logic to compare some less fields, if the header is not used. - + improved the config-patch function to use our internal buffer-compare functions instead of strcmp @@ -1039,7 +1039,7 @@ This file is abondend in favour of the NEWS file - cgi added missing cleanup code - + - fastcgi remove double-free @@ -1048,7 +1048,7 @@ This file is abondend in favour of the NEWS file - leaks fixed some leaks in the new config code - + - array_strcasecmp fixed alignment in the improved array_strcasecmp function (adam) @@ -1058,9 +1058,9 @@ This file is abondend in favour of the NEWS file optimized a few useless strlen() away as we either know the length from buffer->used - 1 or by sizeof(str) - 1 if it is constant. - + optimized the 'find the \r\n\r\n' function. - + improved the array_strcasecmp() based on another idea from (ralf) - accesslog @@ -1068,20 +1068,20 @@ This file is abondend in favour of the NEWS file enabled the strftime cache again 15.08.2004 23:41 -- accesslog +- accesslog added apache-like CustomLog handling in accesslog.format - + accesslog.format = "..." 15.08.2004 21:08 - test-cases - remove testdir + remove testdir - configfiles - handle escaping of " in strings properly + handle escaping of " in strings properly 13.08.2004 12:07 - array @@ -1089,14 +1089,14 @@ This file is abondend in favour of the NEWS file improved inner-loop of array_strcasecmp() (ralf) 11.08.2004 14:14 -- fcgi socket +- fcgi socket use SUN_LEN if available - + - keep-alive disable keep-alive on request - + server.use-keep-alive = "disable" 10.08.2004 15:59 - 1.2.5 @@ -1108,10 +1108,10 @@ This file is abondend in favour of the NEWS file mod_access mod_compress mod_accesslog - + are ported -10.08.2004 13:05 +10.08.2004 13:05 - pipelining fixed very stupid pipelining bug @@ -1119,13 +1119,13 @@ This file is abondend in favour of the NEWS file 09.08.2004 22:07 - pre-release - conditional config - first code for conditional config + first code for conditional config 09.08.2004 14:21 - fcgi fixed access to free()'d memory (doesn't create any harm) - + - isdigit, warings signed -> unsigned for 2 more isdigit() calls (adam) @@ -1138,17 +1138,17 @@ This file is abondend in favour of the NEWS file 08.08.2004 12:05 - kqueue - + use EV_SET() instead of setting the ev-struct by hand (adam) - -- fcgi + +- fcgi fixed the EINPROGRESS handling to use getsockopt (er) fixed a leak of server is disabled (er) - + - solaris 10 port-api - added a skeleton for the sol10 port api + added a skeleton for the sol10 port api 06.08.2004 10:18 - mod_ssi @@ -1160,12 +1160,12 @@ This file is abondend in favour of the NEWS file dropped usage of MAX() in buffer.c added prober includes for md5.h if openssl is enabled (brad) - + - memory usage documented the way how lighttpd caches memory blocks reset the buffers after they have been written by the network-layer - + - kqueue modify fd-bitmask only if kevent succeeded (adam) @@ -1180,7 +1180,7 @@ This file is abondend in favour of the NEWS file - Makefile fixed dependencies for parallel build in mod_ssi_expr.c - + - combo patch * Tinker with kqueue(). Add a reset method so that the kqueue file @@ -1188,28 +1188,28 @@ This file is abondend in favour of the NEWS file in that adds and deletes are sent to the notification mechanism im- mediately, which should cut down on phantom events. Use ev->kq_results as a sliding window. - + * Change F_SETFD calls to use the preferred FD_CLOEXEC instead of 1. - + * Remove unnecessary fdevent fcntl handlers. It appears that the only driver that needs one is Linux RT signals. - + * Quiet compiler warning about unused parameter. - + * Set the close-on-exec flag for the /dev/poll and epoll_create() file descriptors. - + * Return failure if /dev/poll could not be opened instead of logging and continuing. - + * Detect EAGAIN after writev() failures. FreeBSD sendfile() doesn't need protection, as the man page says: - + When using a socket marked for non-blocking I/O, sendfile() may send fewer bytes than requested. In this case, the number of bytes success- fully written is returned in *sbytes (if specified), and the error EAGAIN is returned. - + (adam, georg, matt) @@ -1217,7 +1217,7 @@ This file is abondend in favour of the NEWS file - mod_ssi check for pcre before compiling the module - + - fdevents dropped fdevent_fcntl added by the last patch (adam) @@ -1244,19 +1244,19 @@ This file is abondend in favour of the NEWS file fd in one kqueue. The handler maintains a separate bitmask for fd filters (1 == EVFILT_IN, 0 == EVFILT_OUT). (adam) - + - server side includes added native server-side includes based on the docs from apache: http://httpd.apache.org/docs/mod/mod_include.html - + not supported are: - - exec - - nested virtual + - exec + - nested virtual - config.errmsg - echo.encoding -24.07.2004 +24.07.2004 - fdevents added a bitset to figure out if we received a event for an unregistered fd @@ -1270,7 +1270,7 @@ This file is abondend in favour of the NEWS file - configfile parse keys correctly that contain a digit (Geoff Adams) - + - fcgi fixed large post uploads (Geoff Adams) @@ -1281,26 +1281,26 @@ This file is abondend in favour of the NEWS file rewrite uri.path to the index-file instead of keeping it at .../ this fixes index-file handling in FastCGI/CGI docroot is used - -- close-on-exec + +- close-on-exec enable close-on-exec handling to simplify FD handling in CGI code - + - cgi keep error-log-fd open to catch the error handling for execve() - + report error if cgi-exec file doesn't exist - + - proxy pass page-content on error to the user (E.R.) code cleanup (E.R.) - -- ssi + +- ssi first skeleton of a plugin for ServerSideIncludes - + - security limit the headerlength again to 64k max @@ -1321,7 +1321,7 @@ This file is abondend in favour of the NEWS file connect stdin, stdout and stderr to /dev/null instead of just closing it use dup2() instead of dup() - + - accesslog if accesslog.filename starts with a | spawn a process which will get data @@ -1362,7 +1362,7 @@ This file is abondend in favour of the NEWS file - mmap cache fixed mmap-caching in network_write.c and network_writev.c after a direct - hint by E.Rodichev + hint by E.Rodichev - sendfile + linux @@ -1391,7 +1391,7 @@ This file is abondend in favour of the NEWS file response headers behaved the same way but are not grouped anymore. They stay seperated. Actually they are concated by \r\n<key>: <value> which is the same in the end. - + - file uploads the handling of longer post requests is fixed now. @@ -1406,7 +1406,7 @@ This file is abondend in favour of the NEWS file the code cleanup is finished successfully. Now all cases of pipelining are handle the right way. POST pipelining was still not working up to now. - + 22.05.2004 12:55 - code cleanup @@ -1417,9 +1417,9 @@ This file is abondend in favour of the NEWS file - network backends enabled sendfile support again (__FreeBSD__ instead of __freebsd__) - + added a mmap cache as part of the filedescriptor cache - + added AIX specific send_file() support (untested) 20.05.2004 10:40 @@ -1431,8 +1431,8 @@ This file is abondend in favour of the NEWS file - documentation reformated the documentation the doc/ directory - -15.05.2004 14:45 + +15.05.2004 14:45 - localizer fixed build of localizer extension @@ -1441,7 +1441,7 @@ This file is abondend in favour of the NEWS file - POST requests there is no need to die if we spot a simple POST request on a static file - + - pipelining fixed HTTP/1.1 pipelining which caused the problems with opera @@ -1458,18 +1458,18 @@ This file is abondend in favour of the NEWS file 1. the application (.php, ...) controls the access to the files 2. the webserver is handling the transfer (and check the app generated tokens) - - the token is based on + + the token is based on - a secret - a timestamp - the filename this means even if the token is is distributed by the user it will get invalid after a given timeout (default 60 seconds) - + - errorfiles check for errorfiles before using them - + - code cleanup applied cleanup fixes from adam @@ -1477,15 +1477,15 @@ This file is abondend in favour of the NEWS file 14.05.2004 18:47 - fdevent handling - added a more generic callback interface to the fdevent structures which + added a more generic callback interface to the fdevent structures which simplifies the writing of plugins. this might destabilize lighttpd for a while - + - cgi fixed header parsing of the header is sent in chunks and the terminator is sent in a single chunk - + - EINTR fixed some occurences of EINTR which read() @@ -1501,8 +1501,8 @@ This file is abondend in favour of the NEWS file added incomplete support for Expect: 100-continue (RFC 2616 8.2.3) by sending always 417 for every Expect-request (see 14.20) - - we have been blamed for not supporting it: + + we have been blamed for not supporting it: http://lists.w3.org/Archives/Public/ietf-http-wg/2004JanMar/0059.html 29.04.2004 23:07 - 1.1.9 @@ -1512,19 +1512,19 @@ This file is abondend in favour of the NEWS file 29.04.2004 19:37 - network-writev - + Adam: * call munmap() on error in write() - + - docs - + E.R: - * documented 'check-local' - + * documented 'check-local' + - test-env made the shell scripts more portable (checked with zsh, bash and ksh) - + fixed compilation on NetBSD 28.04.2004 22:22 @@ -1538,7 +1538,7 @@ This file is abondend in favour of the NEWS file Alexey Slynko: * handle SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE in SSL_write the - right way. + right way. - FastCGI @@ -1560,24 +1560,24 @@ This file is abondend in favour of the NEWS file - mem-leak fixed mem-leak on broken HTTP-headers - + - FastCGI patches from E.Rodichev: - + 1. CONTENT_LENGTH "If no data are attached, then this metavariable is either NULL or not defined". - + 2. QUERY_STRING If the Script-URI does not include a query component, the QUERY_STRING metavariable MUST be defined as an empty string (""). - + 3. Doubling of REMOTE_ADDR removed. - + patches from adam: * fixed bug in the sizeof() patches from yesterday. - * some more *_long to *_off_t + * some more *_long to *_off_t 24.04.2004 14:34 - FastCGI @@ -1588,7 +1588,7 @@ This file is abondend in favour of the NEWS file - POST fixed POST request handling - + - chunk-encoding the generated HEX strings where broken since the 1.1.8 @@ -1601,82 +1601,82 @@ This file is abondend in favour of the NEWS file * sizeof(int) -> sizeof(<variable>) * assign fd_set instead of memcpy() * init fd -> connection fd pointers to -1 - + 16.04.2004 08:48 - 1.1.8 - code cleanup - + don't reuse buffer > 64k (see settings.h) - - added server.max-request-size to limit the maximum request-body size + + added server.max-request-size to limit the maximum request-body size (in kBytes) - + don't accept HTTP-request headers larger then 32kBytes (see settings.h) - + minor speed improvements in the request-parser - + More cleanup patches from adam: - + * change pre-ANSI C/valid C++ syntax for function declarations/definitions from using () to (void). Ex: int foo(); --> int foo(void); * use static linkage as much as possible, to limit possible symbol collisions * whack more unneeded variables * try and prevent any errno clobbering by storing the old errno value before - any subsequent system calls, and restoring before function exit. + any subsequent system calls, and restoring before function exit. * change printf syntax for unsigned variables from %d to %u - + 15.04.2004 18:41 - code cleanup handle all int != size_t cases in fcgi.c correctly - + check headerfields to have a value - + handle both EINVAL cases of writev() before the can occur - - limit content-length to SSIZE_MAX + + limit content-length to SSIZE_MAX disallow negative content-length - - the usage of ltostr() has been reduced to the minimum in favour of + + the usage of ltostr() has been reduced to the minimum in favour of buffer_/append|copy)_(long|off_t) - + dropped ultostr() and ultohex() in favour of buffer_* 15.04.2004 16:35 -- portablity +- portablity more patches from adam: - + * remove warnings for unused parameters and variables * remove warnings for mismatched pointer assignments * change "gtime_r" to "gmtime_r" 13.04.2004 20:48 -- test-cases +- test-cases made the 'make check' target self-contained - + In our case we have to call the targets in the following order: - + $ ./configure ... - $ make + $ make $ make install $ make check - + because the path to the plugins is hardcoded in the binary itself - - using - + + using + $ ./configure --prefix=/tmp/lighttpd-1.1.x/ ... - + will help if you don't really want to install before testing. 13.04.2004 00:05 -- portability +- portability adam sent another patchset: - + * Wrap PCRE-specific data member access with an #ifdef * Add const to pointer using return value from dlerror() * Explicitly initialize pointer in the lemon parser to 0, @@ -1688,14 +1688,14 @@ This file is abondend in favour of the NEWS file - fastcgi strip WS after HTTP-response headers coming from the FastCGI process - + added REMOTE_USER to the Server->FastCGI headers removed HTTP_AUTHORIZATION from the Server->FastCGI headers 12.04.2004 10:24 - cgi - if we don't get a partial HTTP-response-header send the content out as soon + if we don't get a partial HTTP-response-header send the content out as soon as the cgi script is finished 12.04.2004 01:23 @@ -1706,7 +1706,7 @@ This file is abondend in favour of the NEWS file 12.04.2004 00:12 - configfile - add some usefull error messages if the tokenizer or the parser fail to + add some usefull error messages if the tokenizer or the parser fail to read the configfile 11.04.2004 22:04 @@ -1717,29 +1717,29 @@ This file is abondend in favour of the NEWS file 11.04.2004 20:28 - 64bit offset size - disable linux-sendfile support for linux 2.4.x for now as it don't - support 64bit transfers - + disable linux-sendfile support for linux 2.4.x for now as it don't + support 64bit transfers + fixed all assignments on the path from the stat() to the Content-Length HTTP-header - head requests set content-length in HEAD requests - + - accesslog write accesslog entry on network error - + write the correct amount of byte written to the accesslog - + 11.04.2004 11:48 - code cleanup moved the config for the cgi-plugin from config.c to the plugin. - + moved some buffers which were only used by a one or two plugin from the server-structure to the plugins - + keeping the plugins independent from the server-core is a 'good thing' 10.04.2004 19:06 @@ -1758,47 +1758,47 @@ This file is abondend in favour of the NEWS file the hand-written configfile parser has been replaced by a LALR(1) one. 'lemon' from the sqlite guys has been used to generate the parser. -- by-host, by-url, by-file, by ... +- by-host, by-url, by-file, by ... $HTTP["url"] =~ "~$" { access.deny = "all" } - + $HTTP["host"] =~ "." { simple-vhost.server-root = "/home/weigon/wwwroot/servers/" simple-vhost.default-host = "grisu.home.kneschke.de" simple-vhost.document-root = "pages" } - + $HTTP["host"] == "incremental.home.kneschke.de" { server.docroot = "/hasdasd" } - + at least the parser can handle it now. Currently there is no real support for this context-based config-option. But the syntax and the parser are done. - + 09.04.2004 10:58 - ssl support enable ssl support again - + - mmap - enabled mmap+write again - + enabled mmap+write again + 08.04.2004 12:34 - stricter http-parser - based on a thread at - + based on a thread at + http://lists.w3.org/Archives/Public/ietf-http-wg/2004JanMar/0050.html - - the HTTP-parser has been adjusted to be more correct when it comes to + + the HTTP-parser has been adjusted to be more correct when it comes to request-header fieldnames - + the whitespace handling around the ':' has been relaxed as requested - + 07.04.2004 17:06 - sigaction @@ -1823,11 +1823,11 @@ This file is abondend in favour of the NEWS file - pidfile fixed the permissions of the pidfile (Matthijs van der Klip) - + - specfile merge the RedHat and SuSE specfile with Matthijs - + - 64bit file-offsets moved the FILE_OFFSET_BITS settings from the config.h the Makefile to enable @@ -1838,7 +1838,7 @@ This file is abondend in favour of the NEWS file added an apache compatible mod_expire which adds Expires: headers to the request - + expire.url = ( "/buggy/" => "access 2 hours" ) 05.04.2004 22:34 @@ -1847,14 +1847,14 @@ This file is abondend in favour of the NEWS file forgot to provide the infrastructure to actually enable the devpoll event handler. the same has been done for the freebsd-kqueue handler (which doesn't work yet) - + fixed the devpoll support while testing it on a real solaris box 05.04.2004 09:49 - debian added debian packaging support written by Vincent Wagelaar - + - solaris Another set of patches for Solaris from Adam @@ -1879,37 +1879,37 @@ This file is abondend in favour of the NEWS file - fdevent added framework for freebsd_kqueue and solaris_devpoll - + the solaris_devpoll one might event work (untested) 03.04.2004 16:41 -- network +- network added framework for filebased chunks - read-write + mmap-write - linux-sendfile - freebsd-sendfile - solaris-sendfilev (untested) - + and memorybased chunks - write - writev - + made TCP_CORK a 'global' flag around the write_chunkqueue-calls - + the writev() support should improve the performance for all non-static - pages. - + pages. + 170 req/s against 158 req/s for the following script if writev() is used instead of write() - + <?php - + for ($i = 0; $i < 1000; $i++) { print $i."<br />\n"; flush(); } - + ?> 28.03.2004 13:42 @@ -1921,35 +1921,35 @@ This file is abondend in favour of the NEWS file * STD{IN,OUT,ERR}_FILENO preferred instead of {0,1,2} * dieing --> dying * SEGFAULT calls abort directly, instead of derefencing a NULL pointer - + - mod_accesslog modified the accesslog format to be CLF compatible set locale for LC_TIME to C - -26.03.2004 16:13 + +26.03.2004 16:13 - path info enabled the pathinfo code again - + 25.03.2004 13:30 - 1.1.3 -- portability +- portability compiles fine now without any patches on IRIX - + - hostname detection reworked "get the hostname for HTTP/1.0 requests which don't specify a Host: ..." to only query the name in this single case for the server side of the connection - + - errorlog handling stderr is only used until the errorlog is init'ed if no error-log is specified, syslog() is used if cycling error-log fails, syslog() is used - + - accesslog cycling don't fall back to stdout anymore @@ -1967,26 +1967,26 @@ This file is abondend in favour of the NEWS file - configure some protability changes to get the 'inline' working with the MIPS CC - + 21.03.2004 22:00 - mod_rewrite, mod_redirect reading the config for those two plugins was not working - + - fdevents changed the compile time setting for the event handling into a run-time setting. - + server.event-handler = "select" # poll, linux-rtsig, linux-sysepoll - + added sys_epoll() for linux 2.6 - + select - all systems poll - Linux 2.1.23+, all XPG4-UNIX - sigio - linux 2.4.0+ + sigio - linux 2.4.0+ sysepoll - linux 2.5.66+ - + 1000-4k-nok 1000-100k-nok select 1776.99 296.52 poll 678.02 607.28 @@ -2003,20 +2003,20 @@ This file is abondend in favour of the NEWS file as the docroot on external hosts might be different than the webserver docroot it can now be specified in the config: - + fastcgi.server = ( ".php" => - ( "grisu" => - ( + ( "grisu" => + ( "host" => "192.168.2.41", "docroot" => "/home/jan/servers/", "port" => 1026 ) ) ) - + a huge internal cleanup in the config handling made the code more readable. some more warnings and error checking should track most of the config - errors for the fastcgi plugin + errors for the fastcgi plugin 19.03.2004 12:34 - external patches @@ -2026,7 +2026,7 @@ This file is abondend in favour of the NEWS file - fix for a debug message - get the hostname for HTTP/1.0 requests which don't specify a Host: ... - rc-script for RedHat - + - documentation added a documentation section about authentification @@ -2035,22 +2035,22 @@ This file is abondend in favour of the NEWS file 19.03.2004 05:11 - optimizations - implemented special versions of + implemented special versions of - strcasecmp (array_strcasecmp) - isdigit, isalpha, isalnum (light_*) - + added a faster check for a finished header - + after disabling all modules it is still possible to get 20 kreq/s. 15.03.2004 19:45 - 1.1.1 - localizer server - added the localizer-server module to the code - + added the localizer-server module to the code + - chunked-encoding - Apple's Safari or HTTP-Handler doesn't handle chunked-extensions defined by + Apple's Safari or HTTP-Handler doesn't handle chunked-extensions defined by RFC 2616 correctly and doesn't ignore them. Disabled the chunked-extension which were just used for debugging purposes. @@ -2059,28 +2059,28 @@ This file is abondend in favour of the NEWS file moved the checks if a plugins support a given function from the dispatcher (plugins_call) to plugins_call_init() to do the check only once. - + equalized the plugins functions to only two types: SERVER_FUNC() CONNECTION_FUNC() - + replaced all handwritten plugin_call-handlers with macros - + made all plugin-functions 'static' - + with all plugins loaded we are at 15kreq/s gain without any plugin loaded at 16kreq/s - + before the change we were at 13kreq/s -06.03.2004 21:13 +06.03.2004 21:13 - compilation fixes fixed some warnings on FreeBSD and NetBSD by adding - #include <netinet/in.h> - + #include <netinet/in.h> + ifdef'ed a pcre-entry in base.h - + remove #define _XOPEN_SOURCE from http_auth.c for IRIX crypt() on Linux needs _XOPEN_SOURCE @@ -2089,20 +2089,20 @@ This file is abondend in favour of the NEWS file added htpasswd and htdigest backends to work against user-files generated by htpasswd and htdigest. - + for basic auth: - plain - htpasswd (crypt only) - htdigest - + for digest auth: - plain - htdigest - + 06.03.2004 17:35 - authentification - check the method in the authorization header againt the configured method + check the method in the authorization header againt the configured method 06.03.2004 14:54 - hostname parsing @@ -2114,17 +2114,17 @@ This file is abondend in favour of the NEWS file - configuration added a warning for unknown configuration variables. - + dropped the 'specific-for.url' ideas for now as it is not known yet how to implement it the right way - + renamed some config-variables to reflect there actual meaning - server.host -> server.bind - server.virtual-* -> simple-vhost.* - server.userid -> server.username - server.groupid -> server.groupname - server.docroot -> server.document-root - + 05.03.2004 15:36 - fastcgi @@ -2133,26 +2133,26 @@ This file is abondend in favour of the NEWS file plugin itself - vhosting - + got a patch for enhanced virtualhosting from christian kruse -> mod_evhost - + moved the virtual hosting config (server.virtual-*) to it's own module called mod_simple_vhost 23.02.2004 10:06 - configfile - + rearragned the config-file structure again to be able to add settings for - a given URL, Host, Filename, ... + a given URL, Host, Filename, ... This change affects some config-options directly (access.deny, url.rewrite, url.redirect, virtual-hosting, ...) - - added 'specific-for.url' for url specific config settings - + + added 'specific-for.url' for url specific config settings + - digest auth FIX: md5-sess type - + seperate the auth-backend stuff 13.02.2004 22:23 - lighttpd 1.0.3 @@ -2171,47 +2171,47 @@ This file is abondend in favour of the NEWS file FIX: the search for header fields was up to now case-sensitive. Now it is like required by the standard case-in-sensitive. - + - browser bugs - + w3m 0.2.5 adds an additional \r\n at the end of the POST requests which is handled now - + 10.02.2004 10:12 - start script took the suse rc-skeleton which states to be LSB compliant and modified it for lighttpd needs - -09.02.2004 11:48 + +09.02.2004 11:48 - HEAD requests FIX: HEAD requests for static files delived the content from the GET request. (test case is added) -08.02.2004 15:53 +08.02.2004 15:53 - directory listings - - FIX: the pathname has not encoded at all before it was transfered to the + + FIX: the pathname has not encoded at all before it was transfered to the browser. a proper url and html-encoding has been added. - - added modification-time and filesize to the output - + + added modification-time and filesize to the output + added a basic css for the virtual listings 07.02.2004 22:15 - lighttpd 1.0.2 - sample configfile rearranged the config-file to have all the important options at the top - + - docs added a mod-rewrite options - + - mod_accesslog stdout is no longer used a default for the accesslog - + - error-messages the 404 is now reported in the error-log @@ -2220,39 +2220,39 @@ This file is abondend in favour of the NEWS file - configfile handling if a key is used twice like - - url.rewrite = ( "url1" => "url") - url.rewrite = ( "url2" => "url") - + + url.rewrite = ( "url1" => "url") + url.rewrite = ( "url2" => "url") + you get an error now. You have to write: - - url.rewrite = ( "url1" => "url", - "url2" => "url") + + url.rewrite = ( "url1" => "url", + "url2" => "url") 31.01.2004 12:22 - lighttpd 1.0.1 - log cycling added a sighup-handler to the plugin interface and fixed the log-cycling for access-logs - + - portability - + disabled the interval-time optimization on IRIX - documentation - + added a lot of new documentation to README 31.01.2004 10:59 - status module added two new options rrd-dir and rrd-reports: - + rrd-reports = (boolean) # enables RRD-reports rrd-dir = (string) # path for the daily status-files - + fixed the "status-files in /"-bug this way - + 22.01.2004 13:38 - lighttpd 1.0.0 - simple docroot @@ -2269,10 +2269,10 @@ This file is abondend in favour of the NEWS file Verified again that the code compiles and runs cleanly on Linux, FreeBSD, NetBSD and IRIX - + compiling with gcc and the option -pedantic works fine compiling with mipspro cc works fine, too - + - tests added some more tests: 39 tests @@ -2281,11 +2281,11 @@ This file is abondend in favour of the NEWS file - protability some compile fixes for FreeBSD have been applied and a new switch has been - added to choose between IPv4 and IPv6 on FreeBSD. + added to choose between IPv4 and IPv6 on FreeBSD. (cmdline: -6, configfile: server.use-ipv6) - packaging - + cleaned up the specfile for building RPMs 21.12.2003 01:00 @@ -2302,7 +2302,7 @@ This file is abondend in favour of the NEWS file - compression added gzip compression (gzip-header + deflate + crc) - + - test harness framework added a 22 tests to verify the correct behaviour of lighttpd @@ -2310,9 +2310,9 @@ This file is abondend in favour of the NEWS file - request parsing GET http://www.yahoo.com/ HTTP/1.0 - + is handled now as - + GET / HTTP/1.0 - plugins @@ -2325,8 +2325,8 @@ This file is abondend in favour of the NEWS file the directory structure is now build automaticly 15.12.2003 01:00 -- compression - +- compression + added a compression cache to the compression module (mod_compress) Vary: Accept-Encoding is set now as it influences to delivered stream of @@ -2336,19 +2336,19 @@ This file is abondend in favour of the NEWS file - config files a new config-file format is ready for the final release of lighttpd. - + it supports: - + server.docroot = "string" server.host = integer server.modules = ( "string", "string" ) server.mimetypes = ( "key" => "value" ) - server.complex = ( "key" => ( "string", integer ), - "string", + server.complex = ( "key" => ( "string", integer ), + "string", integer ) - + the syntax should look familar to all who worked with Perl or PHP. - + config-file handling has been seperated into a parser and a lexer. Both are currently written by hand and will propably be rewritten into bison + flex if time permits. But that would be a cosmetical change. @@ -2358,11 +2358,11 @@ This file is abondend in favour of the NEWS file improved the status page to display - the current connection-stati - - average throughput over 5 seconds + - average throughput over 5 seconds (requests/s and output-bound traffic) now you can see what is going on in the server - + - access-log the accesslog is now a module and can be disabled by just removing the @@ -2372,36 +2372,36 @@ This file is abondend in favour of the NEWS file - chroot-ing how-to: using chroot - + - chroot to /home/www/ - docroot at /servers/<hostname>/pages/ - defaulthost www.example.org - + e.g. (external view) /home/www/servers/www.example.org/pages/index.html - + (in chroot) /servers/www.example.org/pages/index.html - + config: - + chroot /home/www/ userid wwwrun groupid nogroup - + virtual-server-root /servers/ virtual-server-default-host www.example.org virtual-server-docroot /pages/ - - The FastCGI process is living outside this chroot definition as it is + + The FastCGI process is living outside this chroot definition as it is started seperatly. - + 01.12.2003 02:06 - cleanup in preparation for the first stable release some internals had to be - cleaned up. Basicly it was a cleanup of workflow of the creation of the - response-header. All modules can use a clean interface for this purpose + cleaned up. Basicly it was a cleanup of workflow of the creation of the + response-header. All modules can use a clean interface for this purpose now. This is espacially usefull for all modules which have to pass some HTTP-headers to the client. @@ -2410,9 +2410,9 @@ This file is abondend in favour of the NEWS file finally moved the modules to shared libraries and cleaned up some code path to become more readable. - + So far we have: - + mod_rewrite mod_redirect mod_access @@ -2426,23 +2426,23 @@ This file is abondend in favour of the NEWS file - redirects as lighttpd supports url-rewriting redirection was a few lines of new code. - + redirect ^/wishlist/(.+) http://jan.kneschke.de/wishlist/$1 - + rewrite ^/wishlist/(.+) /new/wishlist/$1 28.11.2003 17:00 -- signal stuff +- signal stuff setitimer is used to send a event every second to call time() only once a second. another system call which has been remove from the main-loop. - + sending HUP to lighttpd will close and re-open the logfiles. this is used for cycling logfiles. - + #! /bin/sh -### +### # # a simple logfile rotator for lighttpd # @@ -2459,7 +2459,7 @@ gzip access.log.${DATE} a first attempt for a native win32 has been done. For now mingw is the base for the development as it provides a basic unix-like framework for building native win32 applications. - + the most internal files have been ported and the over all progress is going well. At the end this will just be a prove of concept. @@ -2467,7 +2467,7 @@ gzip access.log.${DATE} - access denied added a access-deny filter to block specific urls like - + access-deny ~ access-deny .inc @@ -2476,15 +2476,15 @@ gzip access.log.${DATE} a fstat() on a opened fd which has changed reports wrong the file-info. Using stat() again helps to solve this problem. - + the sig-io version doesn't suffer from this problem. - + the etags are now used for verifing file-cache-entries. - + - chat - + enabled the internal login mechanism again - + added support transfering session-infos over MySQL. 15.11.2003 00:19 @@ -2493,24 +2493,24 @@ gzip access.log.${DATE} added a buffer_equal_reverse function which is optimized version of strcmp which is going backwards as pathnames are often the same for in the first bytes. - + wrote a one-pass parser for the request-header. The combination of strstr(..., "\r\n") to seperate lines and strchr(..., ':') to seperate keys from values more or less touched every byte twice. - + we are still at 18.000 req/s for 4kb keep-alive requests even with etags and handling all header fields. 14.11.2003 17:26 - fcgi - + Content-Type wasn't passed correctly to the FastCGI app. HTTP_CONTENT_TYPE was sent instead. - + - cache - + provided access to the Session-ID - + - error-log the timestamp is now written in a human readable form @@ -2519,142 +2519,142 @@ gzip access.log.${DATE} - fcgi, cgi added a special set of array-functions which are optimised for the "insert - only once" case. - + only once" case. + this provides access to the headers which are now forwarded to the external interfaces. Before this change only a limited set of request-headers were forwarded. - + 21.10.2003 11:58 -- modules +- modules added a new module-hook after the basic-init of the module for handling config-settings and prepare the overall operartion (like building db-connections, compiling regexes, ...) - + - cache use turckmm-cache 2.4.3 to get some numbers for the php-latency: - + /usr/sbin/ab -n 10000 -c 10 http://alba.home.kneschke.de:1025/index.php - + handling the cache-decision and the cache-hit in php: - + cache-miss: 100% (-> $version = 0) - + plain : 108.13 req/s turckmm-cache: 218.39 req/s - + cache-hit: 100% (-> $version = 1) - + plain : 164.45 req/s turckmm-cache: 653.98 req/s - + handling the cache-decision and the cache-hit in the server: - + cache-hit: 100%, but using index.cml - + cml: 4918.84 req/s (no keep-alive) cml: 6901.31 req/s (keep-alive) - + cache-miss: 100%, but using index.cml - + plain : 108.39 req/s turckmm-cache: 217.84 req/s - + Conclusion: - there is no loss in the cache-miss case through the cml-handling - the cache-hit case can be improved dramaticly with lighttpd-cache - turckmm-cache improves the cache-miss case alot - + 20.10.2003 00:40 - cache the first 'real-life' test showed dramatic improvements in the req/s handling. - + The basic idea was to move the decision if a php-page can be taken from - the cache from the php-code to the webserver. - + the cache from the php-code to the webserver. + See here why this is a good thing: - + the quite common code which works for http://jan.kneschke.de/ is using templates and is quite static, but depends on 4 external files (the menu-structure, the template, the current content, the class-file). - + the index-file is always: - + include_once "jk.inc"; - + $v = new view(); print $v->get(array(array ("file" => "content.html"))); - + It is more or less the same for all pages. - - This basic setup can deliver 100 requests/s. - - The next step has: + + This basic setup can deliver 100 requests/s. + + The next step has: - application bases caching - + as we know that each pages depends on those 4 files, you can check if they have been modified since the last request and deliver the content from the cache otherwise. - + this increased the throughput to 150 req/s. (cache-hit ratio 100%) - + The next logic step is to move the decision-making process out of the PHP code as PHP is to slow for the cache-hit path: - + a CML (Cache-Markup-Language) has been written which describes the whole decision process which has been written in PHP-code before: - - + + output.content-type text/html - + output.include _cache.html - + trigger.handler index.php - + trigger.if file.mtime("../lib/php/menu.csv") > file.mtime("_cache.html") trigger.if file.mtime("templates/jk.tmpl") > file.mtime("_cache.html") trigger.if file.mtime("content.html") > file.mtime("_cache.html") if one of the 'trigger.if' statements is true the 'trigger.handler' is called to generate the pages. - + if none of the them is trigger the files from 'output.include' are sent to the browser with content-type specified in the first line: - - The result was very 'promissing': - + + The result was very 'promissing': + 5900 req/s with keep-alive 3800 req/s without keep-alive (both for a cache-hit ratio of 100%) - + for keep-alive this is factor <b>59</b> against the plain un-cached version and still <b>39</b> againt the php-cache-version which is doing exactly the same. - + Time for party. :) - + 19.10.2003 - 18:55 - cache the handling of functions has been improved. they are now 'plugable'. just the dlopen() stuff is missing. - + a new datatype has been added: the string - + this makes it possible to evaluate something like: - + trigger.if unix.time.now() - file.mtime("head.html") > 30 trigger.if mysql.query("SELECT count(*) " + \ " FROM structure AS struc, session AS sess " + \ " WHERE struct.user = sess.user" + \ " AND sess.id = \"" + mysql.escape("ab\"c") + "\"") - - you see: + + you see: - string operations (concat) - handing of escape-sequences - functions @@ -2667,19 +2667,19 @@ trigger.if mysql.query("SELECT count(*) " + \ handler a lot easier. The CVS server was up all the time but not used. Importing required 5 minutes of work which included merge the freebsd and the linux tree. - + - compilers + platforms on a regular various compilers and platform are check to compile with with the current code base: - + platform | os | compiler | state ---------+---------------------+--------------+--------- ia32 | Linux 2.4.22 | gcc 2.95.3 | ok ia32 | FreeBSD 5.1-CURRENT | gcc 3.3.1 | ok mips64 | IRIX 6.5 | gcc 3.2.2 | ok misp64 | IRIX 6.5 | MIPSpro 7.41 | ok - + the mipspro compiler revealed some warning which resulted in a nice code-cleanup that made the code more readable. @@ -2687,23 +2687,23 @@ trigger.if mysql.query("SELECT count(*) " + \ - e-tags and friends in preparation for the php-conference at the begin of november in - frankfurt/main the server has the support some more caching/proxy tags - like: + frankfurt/main the server has the support some more caching/proxy tags + like: - E-Tag (14.19) [done] - If-Match (14.24) - If-None-Match (14.26) [done] - - If-Range (14.27) - + - If-Range (14.27) + Section (13.3.3) binds them together. [RFC 2616] - + using lxr.kde.org and lxr.mozilla.org revealed that - konqui only uses if-none-match - mozilla uses if-none-match and if-range - + it looks like it isn't that easy to trigger the if-range case. - - As ulf suggested the etag is a hash of file-size, inode-number and mtime. - + + As ulf suggested the etag is a hash of file-size, inode-number and mtime. + - fd-caching ulf just phoned me ask proposed the free the cache more agressivly in case @@ -2711,26 +2711,26 @@ trigger.if mysql.query("SELECT count(*) " + \ 17.10.2003 12:45 - chat - + finished the mysql-support for storing the sessions 12.10.2003 20:56 - valgrind used valgrind again to verify that the code a free of mem-leaks and found - a 'leak generator' in the chunk-api. - + a 'leak generator' in the chunk-api. + the last few leaks were just some missing free()'s at the end of the program run which would have been freed anyway. - + at the end valgrind couldn't find any missing free()'s. 11.10.2003 12:09 - FastCGI - reduced the number of system calls for FastCGI to WebServer to 2 calls per + reduced the number of system calls for FastCGI to WebServer to 2 calls per fd-event. (ioctl() + read()) - + this has no direct effect of the performance of the server, but improves the possible througput of the load-balancer. @@ -2739,8 +2739,8 @@ trigger.if mysql.query("SELECT count(*) " + \ a brown paper bug has been fixed which caused to decreasing throughput if load-balancing was enabled. - - + + benchmarking the req/s with load-balancing shows really nice results: @@ -2748,20 +2748,20 @@ trigger.if mysql.query("SELECT count(*) " + \ ---------+-------------------------------------------------- ulf : 764.06 (php) lappi : 800.06 (php) - + ulf+lappi: 1526.95 (2 * php) - - grisu : 1265.66 (php + ab + lighttpd) - - + + grisu : 1265.66 (php + ab + lighttpd) + + all : 1647.72 (3 * php + ab + lighttpd) - all(nice): 1904.40 (same as all, but the local php on grisu + all(nice): 1904.40 (same as all, but the local php on grisu has been 'nice -20'd) - - + + if a php is run on the load-balancer it has to get a lower priority than the load-balancer itself as to handle the work of (here) 3 php-servers. - + 10.10.2003 15:11 - java ? @@ -2773,108 +2773,108 @@ trigger.if mysql.query("SELECT count(*) " + \ Last week 3 RTL8169S gigE cards arrived and were installed in the test-framework. - + They are very cheap (20 Euros) and are a good start for a low-level - benchmark network. - + benchmark network. + First result show us: - + 48 Mb/s with ab. - + The webserver and the test-server are equipped with a 2000+ AMD CPU. The system load 95%, user load is 3%, the rest is idle on both plattforms. After some calculations at gets clear that there are various bottlenecks: - - 1. The PCI-Bus (32bit/33Mhz) can only transfer 133Mb/s + + 1. The PCI-Bus (32bit/33Mhz) can only transfer 133Mb/s - 48 Mb/s TCP-Traffic results in 55Mb/s Ethernet-Traffic (verified with slurm) [outgoing] - there is about 10Mb/s incomming traffic at the PCI bus which the requests - - the rest of the devices at the PCI bus are eating the last few mb/s + - the rest of the devices at the PCI bus are eating the last few mb/s 2. IRQ-Handling - There are reasons why the RTL8169S cards are so cheap - they can't send jumbo-frames - - only 8k/64k buffers which results in a interrupt every 3 packets + - only 8k/64k buffers which results in a interrupt every 3 packets - they are at least handling checksum offloading for ip, udp and tcp - + In the end there is a need for new hardware to limit the throughput by the Ethernet again. - PCI-X, 64bit-PCI, ... - 'real' gigE-Network cards - ... - - + + BTW: 2.4.22 + the r8139 driver are very flacky and resulted in 3 lock-ups - for today. - + for today. + In another test the dual-PPro-FreeBSD 5.1-CURRENT machine has been used as server with a gigE interface (re0) at has shown that the CPU is the limit for this combination. The maximum thoughput was 7Mb/s. - - Another small benchmark: + + Another small benchmark: $ ab -n 1000 -c 10 http://192.168.2.41:<port>/lighttpd-20030925.tar - - port | server | CPU Idle + + port | server | CPU Idle ------+----------------+----------- 1025 | lighttpd | 75% 1026 | thttpd 2.23b1 | 75% 1027 | boa-0.94.14rc17 | 69% * 1028 | apache 1.3.x | 77% - - + + In all 4 cases the thoughput was 8600 kbytes/s. - + * boa had 9 failed transfers. - -- FreeBSD - + +- FreeBSD + The problems with FreeBSD 5.0-RELEASE vanished after updating to 5.1-CURRENT. 26.09.2003 18:22 - FreeBSD - + A SMP-machine has been added to the test-farm. It is running FreeBSD 5.1-RELEASE and will help to the improve the scalability. fixed sendfile() handling. - + - FreeBSD problems FreeBSD-5.1-RELEASE-SMP 2 * Pentium Pro 200 MHz 192.168.2.38 (doubleheart) (webserver [lighttpd at port 1025, thttpd at port 1027]) - + Linux 2.4.20 1 * AMD 2000+ 192.168.2.10 (grisu) (ab) - + Problem: Connections are reset by the kernel without any application intervention. - + Calling 'ab' (apachebench) at grisu with the following paramters: - + /usr/sbin/ab -n 10000 -c 10 http://192.168.2.38:1025/index.html - + results in the following output: - + ... Time taken for tests: 40.610 seconds Complete requests: 10000 Failed requests: 5980 (Connect: 0, Length: 5980, Exceptions: 0) ... - - - This is reproducable and the number of failed requests is always + + + This is reproducable and the number of failed requests is always 5980 +/- 50 requests. In other words: after 4000 requests tcpdump shows the following output: tcpdump shows: - + 00:53:48.923029 192.168.2.10.39774 > 192.168.2.38.1025: S [tcp sum ok] 1013737315:1013737315(0) win 5840 <mss 1460,sackOK,timestamp 5208461 0,nop,wscale0> (DF) (ttl 64, id 7918, len 60) @@ -2892,7 +2892,7 @@ trigger.if mysql.query("SELECT count(*) " + \ 0x0030 0101 080a 0044 0d12 004f 798d .....D...Oy. 00:53:48.924009 192.168.2.10.39774 > 192.168.2.38.1025: . [tcp sum ok] ack 1 - win 5840 <nop,nop,timestamp 5208461 4459794> (DF) + win 5840 <nop,nop,timestamp 5208461 4459794> (DF) (ttl 64, id 7919, len 52) 0x0000 4500 0034 1eef 4000 4006 9654 c0a8 020a E..4..@.@..T.... 0x0010 c0a8 0226 9b5e 0401 3c6c 6764 6b84 bac1 ...&.^..<lgdk... @@ -2900,7 +2900,7 @@ trigger.if mysql.query("SELECT count(*) " + \ 0x0030 0044 0d12 00:53:48.924150 192.168.2.10.39774 > 192.168.2.38.1025: P [tcp sum ok] - 1:29(28) ack 1 win 5840 <nop,nop,timestamp 5208461 4459794> (DF) + 1:29(28) ack 1 win 5840 <nop,nop,timestamp 5208461 4459794> (DF) (ttl 64, id 7920, len 80) 0x0000 4500 0050 1ef0 4000 4006 9637 c0a8 020a E..P..@.@..7.... 0x0010 c0a8 0226 9b5e 0401 3c6c 6764 6b84 bac1 ...&.^..<lgdk... @@ -2918,9 +2918,9 @@ trigger.if mysql.query("SELECT count(*) " + \ strace shows that no connection attempt has been reported to the application which is poll()'ing the server socket. - + /* the common loop without any block attempts */ - + accept(3, {sa_family=AF_UNSPEC, sa_data="\0\0\0\0\0\0\0\0\0\0\0\0\0\0"}, [0]) = 5 fcntl(5, F_SETFL, O_RDWR|O_NONBLOCK) = 0 read(5, "GET /index.html HTTP/1.0\r\n\r\n", 4095) = 28 @@ -2930,13 +2930,13 @@ trigger.if mysql.query("SELECT count(*) " + \ write(2, "1064875136: (network.c.210) 235 "..., 33) = 33 syscall_393(0x6, 0x5, 0, 0, 0x10fc, 0, 0xbfbff2c0, 0) = 0 close(5) = 0 - + /* no futher waiting connections */ - + accept(3, 0xbfbff700, [1852702730]) = -1 EAGAIN (Resource temporarily unavailable) - + /* enter the main-loop */ - + gettimeofday({1769235301, 1663069807}, NULL) = 0 poll([{fd=3, events=POLLIN}], 1, 1000) = 0 gettimeofday({4294967295, 65537}, NULL) = 0 @@ -2944,9 +2944,9 @@ trigger.if mysql.query("SELECT count(*) " + \ gettimeofday({4294967295, 65537}, NULL) = 0 poll([{fd=3, events=POLLIN}], 1, 1000) = 0 ... - + (strace is broken for accept() and gettimeofday(), syscall_393() is sendfile()) - + after entering the main-loop the webserver doesn't receive any new POLLIN events at all for the next 10-15 seconds. Any connection-attempt within the period is, as you can see in the tcpdump output, accepted by the @@ -2954,23 +2954,23 @@ trigger.if mysql.query("SELECT count(*) " + \ After those 10-15 seconds the application gets a POLLIN event for the server socket and the normal data-transfer taken place for the next 4000 requests. - + This behaviour is reproducable with thttpd 2.20c and the current lighttpd. - + 26.09.2003 11:42 - localizer - ported the localizer-server application into a module for lighttpd. After - 30 minutes the code was ported and funtional. This modules provides access - to the localizer-db by a HTTP-Interface and generates the response as + ported the localizer-server application into a module for lighttpd. After + 30 minutes the code was ported and funtional. This modules provides access + to the localizer-db by a HTTP-Interface and generates the response as HTML, CSV and plain-text. - + So far, the module-interface looks good and flexible enough. - + 7000 req/s is good enough too. Generating the HTML and querying the DB needs some time. - + 22.09.2003 08:40 - modules @@ -2979,36 +2979,36 @@ trigger.if mysql.query("SELECT count(*) " + \ auth-sub-system and the cache out of the main-code. The module-interface will be extended to allow the cgi and the fastcgi sub-processes to be moved into a module. - + 15.09.2003 09:36 - error-handling fastcgi and cgi connections are now closed correctly if the corresponding client-connection has died. - + 14.09.2003 10:40 - cgi finally streaming works with CGI, too - + this enable support for cgiirc.sf.net and friends which use streaming as there transport mechanism. - + streaming has been verified with cgiirc-0.5.2. - + - fdevents there where some reports that sigio didn't work as expected. It just - reported no events at all. Looks like a known bug in the glibc on + reported no events at all. Looks like a known bug in the glibc on those platforms. - + Using poll() instead solve the problems. 27.08.2003 22:12 - rewrite a pcre based rewrite engine has been integrated - + - cgi the file-based cgi interface has been replace by two pipes. @@ -3016,13 +3016,13 @@ trigger.if mysql.query("SELECT count(*) " + \ 23.07.2003 13:29 - fdevents - the whole fd-event handling has been reworked and several smaller bugs + the whole fd-event handling has been reworked and several smaller bugs and design-errors have fixed. - + sigio, poll() and select() are working fine again. - + On IRIX 6.5 SIGIO could be used, but without further testing poll() is used. - + - cgi CGI-support is still broken. @@ -3031,16 +3031,16 @@ trigger.if mysql.query("SELECT count(*) " + \ using the F_NOTIFY feautre of the Linux 2.4.x kernel gives anothre nice performance boost as lighttpd can cache the stat()'s the right way, now. - + 23009.66 @ 5-4k-k which means +10% against 30.06.2003 14:03 - + for 1000-4k-nok the performace nearly doubles: 3730.23 goes up to 6144.39 17.07.2003 13:21 - FreeBSD a small patch (#include <>) to compile lighttpd on FreeBSD again. - + 08.07.2003 10:48 - fileinfo-cache @@ -3052,35 +3052,35 @@ trigger.if mysql.query("SELECT count(*) " + \ After some problems with other benchmarking tools for webservers the first version of lighttpd-bench has been written. - + It a revealed a nasty strange behaviour which was fixed by increasing the listen-backlog from 5 to 1024. - + 30.06.2003 14:03 - fileinfo-cache the fileinfo-cache has been relaxed a little bit and there are always 2 fstat()'s per file-request now. This isn't that dramatic: - + 21800.74 req/s is still a very good result (7-4k-k). - + 29.06.2003 03:29 - fileinfo-cache a fileinfo cache has been added to reduce the number of system-calls to - stat and open a file. - + stat and open a file. + in the releases before the same file was stat'ed at least 2 times plus a stat on the docroot for each request. Now the stat()'s and the corresponding open() + close() calls are cached and the number of system calls has been reduced to the minimum: - + $ strace -eopen,stat64,read,write,sendfile,accept,shutdown,close \ -p `pidof lighttpd` /* first connection */ -accept(3, {sin_family=AF_INET6, sin6_port=htons(56211), - inet_pton(AF_INET6, "::ffff:192.168.2.10", &sin6_addr), sin6_flowinfo=0, +accept(3, {sin_family=AF_INET6, sin6_port=htons(56211), + inet_pton(AF_INET6, "::ffff:192.168.2.10", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, [28]) = 5 accept(3, 0xbffff470, [28]) = -1 EAGAIN read(5, "GET /index.html HTTP/1.0\r\nUser-A"..., 4095) = 91 @@ -3108,20 +3108,20 @@ close(5) = 0 In the end we have a new speed record: - + (ab -c 8 -n 100000 http://192.168.2.10:1025/index.html with poll()) Requests per second: 23435.67 [#/sec] (mean) - + This is a speed increasement of 20-30% against the last internal benchmark. 28.06.2003 02:30 -- caching framework +- caching framework the trigger.if directive is working fine. the basic algebra is done ( +, -, *, / and comperations =, <=, >=, >, < and the boolean logic && and || including braces) - + two basic function are available: - unix.time.now - file.mtime(...) @@ -3130,37 +3130,37 @@ close(5) = 0 - caching framework added output.include, output.content-type for a cache-hit and - trigger.handler for a cache-miss. - + trigger.handler for a cache-miss. + the actual decision is made be trigger.if which will be added tomorrow. 15.06.2003 15:33 -- sig-io +- sig-io After several other smaller optimisations lighttpd performs better with sig-io under high load: - + sigio+poll poll c1000-4k-nok : 2635.95 1643.39 c1000-4k-k : 7335.68 6788.87 c1000-100k-nok: 2353.49 1217.73 c1000-100k-k : 3097.89 2080.73 - - + + The user-space part has been optimized a lot. Now it is time to optimized the number of context-switches between user and kernel-mode. - + user 0m0.180s sys 0m1.160s - + a fileinfo-cache is the way to go. - + struct { buffer *name; struct stat st; int handler; ... - + int fd; void *mmap_p; } @@ -3169,42 +3169,42 @@ close(5) = 0 - sig-io is back again and it works fine. - + sigio (Realtime-Signals under Linux 2.4.x) sends one signal per event and buffers the rest of the events in a kernel queue. If the is full a SIGIO is sent and poll() gets all events at once for further processing. - - + + Currently the behaviour is a little bit strange: - sig-io + poll() is good for non-keep-alive connections - poll() for keep-alive connections - + c1000-4k-nok: (1000 concurrent request, 4k filesize, no keepalive) poll : 1521.38 sigio+poll: 2124.00 - + c1000-4k-k: (1000 concurrent request, 4k filesize, keepalive) poll : 5882.35 sigio+poll: 1239.46 - - Very strange for now. - + + Very strange for now. + 09.06.2003 23:59 - code-cleanup - + the event-handling code has been rewritten to handle single events better as they are expected from sig-io. - + the fallback-mode of sig-io is broken now, but the normal poll() mode got - a 10% increasement in speed. This means the we are back the speed level of - 20030308-0155 are as fast as zeus again. - + a 10% increasement in speed. This means the we are back the speed level of + 20030308-0155 are as fast as zeus again. + Especially under higher load the current lighttpd performes better. - + 09.06.2003 11:51 - sig-io benchmark - 20030609-1151 20030608-2110 20030308-0155 + 20030609-1151 20030608-2110 20030308-0155 -c 10 sigio select() poll() poll() 4k : 7870.92 7937.77 8035.36 9443.76 4k (keep-alive) : 14098.41 14590.02 14275.52 17985.61 @@ -3217,15 +3217,15 @@ close(5) = 0 100k (keep-alive) : 4267.67 4283.94 4094.17 4314.06 -For -c 100 4k and 100k sig-io gives a small increasment. +For -c 100 4k and 100k sig-io gives a small increasment. -09.06.2003 01:00 +09.06.2003 01:00 - sig-io writing large files works now as expected. After removing the limit for the chunks of sendfile the write-buffer-is-empty-again signal is generated. that was missing. - + 321 of 10000 connections still have the wrong length. After that is fixed it is time to start some benchmarks again. @@ -3233,11 +3233,11 @@ For -c 100 4k and 100k sig-io gives a small increasment. - sig-io first attempts in getting SIGIO support running which were not very - successfull yet. - + successfull yet. + - poll()/select() benchmark - 20030608-2110 20030525-1623 20030308-0155 + 20030608-2110 20030525-1623 20030308-0155 -c 10 select() poll() poll() poll() 4k : 7937.77 8035.36 8166.60 9443.76 4k (keep-alive) : 14590.02 14275.52 14781.97 17985.61 @@ -3252,7 +3252,7 @@ For -c 100 4k and 100k sig-io gives a small increasment. as the overall processing cycle has been rearranged the overall figures changed in minor ranges. c100-4k-k increased, *-100k-k decreased. - + At least it still works. 08.06.2003 12:45 @@ -3260,7 +3260,7 @@ For -c 100 4k and 100k sig-io gives a small increasment. implementate an abstration layer for fd-events (like eevry other webserver). currently we support poll() and select(). - + This should bring us support for Mac OS X and propably Windows. 04.06.2003 18:35 @@ -3275,10 +3275,10 @@ For -c 100 4k and 100k sig-io gives a small increasment. 04.06.2003 14:34 - pipelining - + adding support for pipeling introduces a problem if the request-header was broken. this has been fixed now. - + - unneccesary slashes when building pathes from different portions of a string (e.g. docroot + @@ -3291,24 +3291,24 @@ For -c 100 4k and 100k sig-io gives a small increasment. the error-log contains the start and end-times of the lighttpd process, now. - + - configfile the config-file parser has been relaxed to accepts tabs instead of spaces. - + - better error-handling - fixed a <a + fixed a <a href="http://bugs.php.net/?id=24009">bug in the FastCGI-SAPI of PHP</a> - + if the fastcgi process dies or closes the connection unexpectedly we return 500 now instead of closing the connection to the client. - + - Location the CGI/1.1-rev-03 specification requires us to send Status 302 if a Location-header is sent by the client and a Status-header is missing. - + - PATH_TRANSLATED if PHP is compiled without --discard-path PATH_TRANSLATED has to be @@ -3318,7 +3318,7 @@ For -c 100 4k and 100k sig-io gives a small increasment. - directory listings if a directory is requested and the directory doesn't contain a index-file - a directory-listing can be displayed. You have to enable directory-listings + a directory-listing can be displayed. You have to enable directory-listings in the config-file (directory-listings on) - url-decoding @@ -3330,35 +3330,35 @@ For -c 100 4k and 100k sig-io gives a small increasment. - pipelining as Sascha required pipelining for his benchmarking tool it has been - implemented. - + implemented. + pipelining allows sending a bunch of requests at once without waiting for the actual responses. This reduces the network-overhead and the round-trip-time. - + - non-free()d memory - + dmalloc helped to close some non-free()d memory. For the normal operation this isn't important as only memory chunks which had to be free()d at the end of the live-time of the lighttpd-process were not de-allocated. - + - partly-initialized variables lighttpd wasn't initializing the main-structure which resulted in strange behaviour in rare circumstances. - + 25.05.2003 16:23 - benchmarks after removing some useless internal copies we are more or less at the old speed levels. - + after adding virtual-hosts 10% of the performance were lost. Using less memcpy() operations might add several other boosts. - + I've just checked how lighttpd compares to Zeus. - + lighttpd (current) (old) -c 10 20030525-1623 20030308-0155 Zeus 4_2 4k : 8166.60 9443.76 7278.55 @@ -3373,61 +3373,61 @@ For -c 100 4k and 100k sig-io gives a small increasment. 23.05.2003 14:38 - cgi-variables - + HTTP_HOST was missing for the cgi-module while the fcgi-module passed it through to the handler. Fixed that. - + - fcgi-errors - + the connection to the fcgi was dropped and poll() reported an error, the - error wasn't reported to the client the right way. - + error wasn't reported to the client the right way. + 22.05.2003 23:02 - authorization the first password-storage has been added: - + [auth] backend plan plain-userfile <filename> - + require /download/ user=jan|user=anom http-auth /download/ "download archiv" digest - + groups are prepared but not implemented. basic and digest are working fine. 20.05.2003 17:53 - authentification - - The auth-methods from RFC 2617 have been added. + + The auth-methods from RFC 2617 have been added. - auth basic - auth digest - + The only source for accounts is currently only the config-file. - + auth-digest needs the plain-text passwort. Are there any source which provide a plain-text password ? 12.05.2003 14:33 - virtual hosts - + added very basic virtual-host support - + virtual-server-root /home/weigon/projects/lighttpd/servers/ virtual-server-default-host grisu.home.kneschke.de:1025 virtual-server-docroot /pages/ - - docroot is - + + docroot is + - if http-host exists <virtual-server-root> + <http-host> + <virtual-server-docroot> - + - otherwise - <virtual-server-root> + <virtual-server-default-host> + + <virtual-server-root> + <virtual-server-default-host> + <virtual-server-docroot> - + - if even virtual-server-default-host does not exist, 500 is sent - + 12.05.2003 13:02 - code cleanup @@ -3435,33 +3435,33 @@ For -c 100 4k and 100k sig-io gives a small increasment. After two month of development it was time clean-up the internal structures. It looks like every went fine as lighttpd works es expected like before. - + - deflate - the on-the-fly compression has been verified to work fine with opera, + the on-the-fly compression has been verified to work fine with opera, konqui, mozilla and the IE. 12.05.2003 02:10 -- on-the-fly compression: deflate - +- on-the-fly compression: deflate + Why the hell are the defining a "deflate" encoding in the form of - - _deflate_ The "zlib" format defined in RFC 1950 [31] in combination - with the "deflate" compression mechanism described in RFC 1951 [29]. + + _deflate_ The "zlib" format defined in RFC 1950 [31] in combination + with the "deflate" compression mechanism described in RFC 1951 [29]. (RFC 2616) - + and noone implements it that way ? Konqui and Mozilla expect a plain - deflate() package without the zlib-header. - + deflate() package without the zlib-header. + Konqui is using "inflate2(..., -MAX_WBITS); " which is noted in the zlib - source as - + source as + /* handle undocumented nowrap option (no zlib header or check) */ - + Funny. Very, very funny. - - + + Anyway. We have mimetype-depended compression support now. - + 11.05.2003 21:56 - logging re-arranged the logfile structure to write CLF + useragent + referrer. @@ -3469,30 +3469,30 @@ For -c 100 4k and 100k sig-io gives a small increasment. 11.05.2003 10:23 - POST file-upload added the missing functionality to send more than a single packet to the - FCGI-Server (or Client ? ... the PHP). - + FCGI-Server (or Client ? ... the PHP). + This gives us the file-upload thing for eg. PHP and large user-forms (>16kb). 05.05.2003 15:21 - PATH_INFO - + added support for PATH_INFO. PHP is a little strange and doesn't trust the passed PATH_INFO setting. Works fine now. - + 30.04.2003 15:25 - bug-fixing day While testing the FastCGI interface with the MSIE Björn Schotte discovered - that sometimes the output repeats itself from the start in an endless loop. + that sometimes the output repeats itself from the start in an endless loop. This bug has been fixed. - + The read-write-fallback for ancient systems seeked the wrong FDs. - + The FastCGI handler is now separting the HTTP-Header from the response-body what results in a cleaner interface. The "header too long for caching" message is gone now. - + 28.04.2003 18:18 - chunked transfer-encoding @@ -3502,8 +3502,8 @@ For -c 100 4k and 100k sig-io gives a small increasment. 27.04.2003 23:10 - chunked transfer-encoding added "Transfer-Encoding: chunked" which is currently used in the web-chat - for the endless stream. Perhaps it helps some browsers. - + for the endless stream. Perhaps it helps some browsers. + The FastCGI interface will get a the chunked-support too, as it will enable keep-alive even if no content-length is returned from the FastCGI process. We know the size of the chunks and will report it to the browser. @@ -3512,14 +3512,14 @@ For -c 100 4k and 100k sig-io gives a small increasment. - gigE deatchmatch sascha compared the current lighttpd to his premium thttpd in his - gigabit-Ethernet-Network. + gigabit-Ethernet-Network. <a href="http://schumann.cx/gbit_deathmatch.txt">http://schumann.cx/gbit_deathmatch.txt</a> small comment: lighttpd provides the same performance (req/s and thoughput), but uses more - CPU-Time. + CPU-Time. 10.04.2003 17:22 - works on IRIX @@ -3527,7 +3527,7 @@ href="http://schumann.cx/gbit_deathmatch.txt">http://schumann.cx/gbit_deathmatch Jörg Behrens provided me login to his SGI Origin and after fixing two small typos it worked fine on IRIX. (#if define HAVE... was missing a 'd' and getopt returns a 'int' and not a 'char') - + IPv6 support is currently disabled for IRIX a gethostbyname2() isn't available. @@ -3535,11 +3535,11 @@ href="http://schumann.cx/gbit_deathmatch.txt">http://schumann.cx/gbit_deathmatch - another bug-fixing day The upper limit of open connections was enforced and a caused a seg-fault. The current limit is set to 4096 parallel connections. - + As sascha benchmarked lighttpd and his premium thttpd I tried to reproduce his reported results and had to fix 2 flaws in the async-io handling of httpd_load which was used for the testing. - + If sascha starts another benchmark session I'll put a link to it here. 09.04.2003 00:08 @@ -3547,9 +3547,9 @@ href="http://schumann.cx/gbit_deathmatch.txt">http://schumann.cx/gbit_deathmatch Date: and Last-Modified: where sending a timezone != GMT what was invalid. The timestamp itself was correct, just the timezone use the wrong characters. - + the fcgi-code had an buffer-overflow for larger POST-Requests. - + The fcgi-code still has problems with POST-Request larger than 16kb as the the write buffer is full. Currently we don't handle this case except from reporting it in the error-log. @@ -3560,29 +3560,29 @@ href="http://schumann.cx/gbit_deathmatch.txt">http://schumann.cx/gbit_deathmatch The CGI Interface wasn't tested for a longer time. It don't really survived the introduction of the config-file handling and the internal changes that were part of it. - + A small test with - + #! /usr/bin/perl print "Content-Type: text/html\r\n\r\n"; print time()."\n"; 0; - produced 219 req/s. - + produced 219 req/s. + Calling PHP via the CGI interface results in 100 req/s. Same script, same parameters for 'ab' and same PHP result in 1400 req/s if we use the - FastCGI interface. - + FastCGI interface. + <b>Don't forget</b>: these benchmarks only represent figures for scenarios which are not very realistic. They are just usefull for comparisions of the internals. We don't want to benchmark applications. 01.04.2003 23:04 - new benchmarks - + This time we wanted to see if we can get the fastcgi-Interface a little bit - faster. We use this small script for the testing the interface. + faster. We use this small script for the testing the interface. <?php @@ -3603,8 +3603,8 @@ ob_end_flush(); 01.04.2003 19:28 (no april fools joke) - added SSL support - I took -lssl and -lcrypto and added SSLv2/SSLv3/TLS support to lighttpd. - + I took -lssl and -lcrypto and added SSLv2/SSLv3/TLS support to lighttpd. + After some reading I realisized that libcrypto contained some of my code. They have a similar buffer-struct with similar functions and they use the same MD5-code from the RFC. :) @@ -3612,8 +3612,8 @@ ob_end_flush(); Adding basic SSL-support was quite esay: replacing all write/read-calls by SSL_write/read, initializing the ssl-context the right way and telling openssl where to get the data from (SSL_set_fd). It fits really well into - lighttpd. - + lighttpd. + - sidenote sooner or later the con->filename handler will vanish in favour of the direct interface to the chunk-API which will simplifiy the design a little @@ -3621,12 +3621,12 @@ ob_end_flush(); 31.03.2003 20:50 - added a web-chat module - 1400 lines of C-code are neccesary to add a web-chat to lighttpd. - + 1400 lines of C-code are neccesary to add a web-chat to lighttpd. + Features: - bb-code for text-layouting - auto-highlight for URLs and Email-adresses - - unlimited number of channels + - unlimited number of channels - max. 32.000 users per channel - fast as it is directly integrated into the web-server - easy to install (as easy as lighttpd) @@ -3635,14 +3635,14 @@ ob_end_flush(); - uses as little JavaScript as possible to stay compatible with all browsers - flood-protection (2 Levels: ignore and kick) - uses CSS for customized look-and-feel - + 25.03.2003 00:36 - finished the config-file support - now we have config-sections - + now we have config-sections + [fastcgi] fastcgi .php 192.168.2.76 1025 - + The only this missing is -HUP handling to re-read the config. But that will follow when I'm up again. @@ -3653,52 +3653,52 @@ ob_end_flush(); 19.03.2003 03:05 - more on sendfile support - added support for freebsd's version of sendfile(). - + added support for freebsd's version of sendfile(). + Linux: ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); - + FreeBSD: int sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, off_t *sbytes, int flags); - + the first 2 params are swap, the next 2 are the same and the last 3 are set to NULL or 0. - + Solaris 9 is providing a direct interface to the chunk-API with the sendfilev() system call: - - ssize_t sendfilev(int fildes, + + ssize_t sendfilev(int fildes, const struct sendfilevec *vec, int sfvcnt, size_t *xferred); - + recovering from a failure is a little bit more complex, but it should be fast. I just need a system to test it. Anyone ? 18.03.2003 17:32 - in the news - what a surprise: lighttpd is announced in entwickler.com. - + what a surprise: lighttpd is announced in entwickler.com. + <a href="http://www.entwickler.com/itr/news/psecom,id,9483,nodeid,82.html">http://www.entwickler.com/itr/news/psecom,id,9483,nodeid,82.html</a> - + this was not planned. - - + + - implemented the chunked-API rather writing the content of multi-range'd requests to a temp-file we - just register the parts in a chunk-queue. - + just register the parts in a chunk-queue. + chunk 1 [mem] - part-header chunk 2 [file] - source-file (offset, len) chunk 3 [mem] - part-header chunk 4 [file] - source-file (offset, len) chunk 5 [mem] - part-footer - + If everything is prepared, the content-length is calculated and the http-header is generated and prepended to the chunk-queue. - + the handle_write() function which handles the write-process just sends the chunks to the network without only further modifications. - + the chunk-api even simplifies the 'my-fastcgi-process-needs-some-time-to-create-the-response- and-sends-the-data-in-chunks' case. Just add the chunk to the queue if it @@ -3706,11 +3706,11 @@ ob_end_flush(); 13.03.2003 10:49 - another set of real-life benchmarks - + the chairman was benchmarked a little bit. Chairman is full-flegded WCMS. As every CMS it needs some time to generate pages. To speed the page generating the static-parts of the page can be cached internally. - + without caching with caching apache + mod_php : 2.50 10.64 req/s lighttpd + fcgi-php: 2.50 22.74 req/s @@ -3725,11 +3725,11 @@ lighttpd + fcgi-php: 2.50 22.74 req/s - another large application works with lighttpd <a -href="http://www.thinkphp.de/content/content2.php?CatID=44&NewsID=95">Chairman</a> from <a href="http://www.thinkphp.de/">thinkphp</a> has been verified to work with lighttpd. - +href="http://www.thinkphp.de/content/content2.php?CatID=44&NewsID=95">Chairman</a> from <a href="http://www.thinkphp.de/">thinkphp</a> has been verified to work with lighttpd. + Three things are worth to note: - - 1. ALWAYS use log_error in the php.ini if you use FastCGI + + 1. ALWAYS use log_error in the php.ini if you use FastCGI otherwise it will put the errormessages directly into fastcgi-socket without any FastCGI Header. This will result in strange errors. (its a PHP bug) @@ -3744,7 +3744,7 @@ href="http://www.thinkphp.de/content/content2.php?CatID=44&NewsID=95">Chairm 11.03.2003 00:13 - another target - after adding some headers lighttpd compiles without any warnings + after adding some headers lighttpd compiles without any warnings under cygwin on Windows. A native windows port will take some time as I have to figure out the @@ -3752,21 +3752,21 @@ href="http://www.thinkphp.de/content/content2.php?CatID=44&NewsID=95">Chairm 10.03.2003 11:52 - added Solaris 8 and 9 - lighttpd has been confirmed to compile and work on - - - linux + lighttpd has been confirmed to compile and work on + + - linux - FreeBSD, NetBSD - Solaris 8, 9 - + Perhaps I can get lcc to compile it on windows. 10.03.2003 01:30 - another platform was confirmed lighttpd works on NetBSD - + - another webserver benchmark mathopd (http://www.mathopd.org/) - + Mathopd/1.4 -c 10 4k : 6329.11 [#/sec] @@ -3776,7 +3776,7 @@ href="http://www.thinkphp.de/content/content2.php?CatID=44&NewsID=95">Chairm -c 100 4k : ---- (connections dropped) 4k (keep-alive) : ---- -100k : ---- +100k : ---- 100k (keep-alive) : ---- Very good values for small files, but the rest ? @@ -3786,11 +3786,11 @@ Very good values for small files, but the rest ? 1. sendfile (linux only) 2. mmap + write 3. read + write - + This means that lighttpd runs on some more systems. It has been verified to compile and work on linux 2.4.x and FreeBSD. - - + + -c 100 sendfile mmap read 4k 6476.68 5698.01 5363.08 [#/sec] @@ -3798,11 +3798,11 @@ Very good values for small files, but the rest ? The mmap() numbers could be better with a fd+mmap-cache. The zero-copy thing is good for our performance. - + - tested another small httpd - BOA just to get a better view about the performance of lighttpd i've tested another httpd: Boa/0.94.14rc16 (http://www.boa.org/) - + Boa/0.94.14rc16 -c 10 4k : 5659.63 [#/sec] @@ -3824,7 +3824,7 @@ Very good values for small files, but the rest ? 09.03.2003 13:26 - load-balancing works great - I used the framework from http://framework.netuse.de/ as a + I used the framework from http://framework.netuse.de/ as a real-life example again to test the load-balancer. setup: @@ -3832,57 +3832,57 @@ Very good values for small files, but the rest ? - AMD athlon XP 2000+ - runs lighttpd + ab + a 'nice -15'ed FastCGI-PHP - generates 153 req/s alone - + - laptop - Intel PIII 850 - runs a FastCGI-PHP - generates 88 req/s - - using the internal load-balancer of lighttpd which balances the + + using the internal load-balancer of lighttpd which balances the php-requests over grisu and laptop generate: 221 req/s - + An apache with mod_php running on grisu gives 117.04 req/s only. 09.03.2003 12:46 - building the connect connection to the fcgi-php is not non-blocking socket() -> connect() -> fcntl(non-blocking) resulted in some problems as - the connect() call blocked sometimes for 1 seconds. - + the connect() call blocked sometimes for 1 seconds. + socket() -> fcntl(non-blocking) -> connect() solves this problem, but - addes more overhead. The first connect-attempt seems always to + addes more overhead. The first connect-attempt seems always to return EINPROGRESS. - + 08.03.2003 15:06 -- the first 'real-life' PHP test showed 2 bugs in the POST handling. +- the first 'real-life' PHP test showed 2 bugs in the POST handling. 1. the Content-Type header was not forwarded via fastcgi 2. the internal content_length handler wasn't reset after the request - + now lighttpd + php work with - + http://framework.netuse.de/ - - the basic application gives us 145 req/s + + the basic application gives us 145 req/s 08.03.2003 11:06 - use diet to 'test' your code diet gives some use full warnings which should be followed. I took the chance and removed the last few fprintf() and sprintf() from the code. now, we don't need stdio.h anymore. - - a staticly linked, stripped lighttpd is 42884 bytes large. + + a staticly linked, stripped lighttpd is 42884 bytes large. 08.03.2003 01:55 - buffer_strcat() uses strlen() to get the length of the 'to-be-catted-string' if the string is constant or has a known length you can pass that function which gives use buffer_strcat_len() which passes the string length as a parameter. - + - using a ramdisk as the base for the tempfiles generated mkstemp() is a - very cood idea + very cood idea it reduces the io-load on the system and gives as more cpu-time for load-balancing the php-requests. - + - cache the output of strftime(), gmtime() and localtime we generate more then 10.000 req/s which results in using the same timestamp over and over again. It is sufficient to generate the timestamp @@ -3893,21 +3893,21 @@ Very good values for small files, but the rest ? - don't try to overoptimize for code for the sake of clean code the range support require some hack in the first versions like setting the - write_offset to the start of the range and keeping the rest of the - "code 200" send code as usual. Only a few lines added this first range - feature. fast, but a hack. It made things more complicated then neccesary + write_offset to the start of the range and keeping the rest of the + "code 200" send code as usual. Only a few lines added this first range + feature. fast, but a hack. It made things more complicated then neccesary to add multi-range support in this scenario. - + removing the hack doing small clean preprocessing helps to clean up the whole 'write a chunk on the wire' code. At the end we use less code and - have a cleaner design. - - Sascha proposed a chunked layer which just takes the chunks (http-header, + have a cleaner design. + + Sascha proposed a chunked layer which just takes the chunks (http-header, part-header, part-message, ... and the last boundary) and passes them to the write-to-the-wire-code. This is far more elegant and will perhaps same us from other problems, too. Currently I think that it is not necessary. First we have to fix some protability issues. - + Ok, today benches: today last @@ -3925,22 +3925,22 @@ Ok, today benches: Top Transfer Rate: 86365.77 [Kbytes/sec] received - + Too much for a GigE-link ? - + so far: - use state-engines - a non-forking webserver like described in - + a non-forking webserver like described in + http://www.kegel.com/c10k.html -- don't use fprintf() for logging. +- don't use fprintf() for logging. writing one line to log file takes more time that sending responsing the a HTTP-request - + - take care of your memory typedef struct { @@ -3948,7 +3948,7 @@ so far: size_t used; size_t size; } buffer; - + buffer* buffer_init(); void buffer_free(buffer *b); int buffer_prepare_copy(buffer *b, size_t size); @@ -3957,20 +3957,20 @@ so far: int buffer_strcpy_len(buffer *b, const char *s, int s_len); int buffer_strcat(buffer *b, const char *s); int buffer_strcat_len(buffer *b, const char *s, int s_len); - + buffer_init() is only called once per buffer. If you don't need the - buffer, set 'used' to zero and reused it afterward. + buffer, set 'used' to zero and reused it afterward. buffer_strcpy() + buffer_strcat() check if the 'used' + the new strlen() fit in to the 'size' of the buffer. If not the realloc() the buffer. buffer_strcat() uses memcpy(ptr + used - 1, s, s_len + 1); which should be faster than the original strcat(). - + Using those buffers keep the memory usage at 2Mb. malloc() and free() are only called at the beginnig of the programm and at the end. - + - don't used sprintf() to convert a integer into a string as like sprintf(buf, "%d", l); - + write your own ltostr function. sprintf() is to general for the case and is slow. @@ -3980,14 +3980,14 @@ Speed: Let's assume that <a href="http://www.acme.com/software/thttpd/">thttpd</a> is (one of) the -fastest webservers out there. +fastest webservers out there. all httpds were started with: $ ./thttpd -p 1026 -D \ -d /home/weigon/projects/localizer/src/lighttpd/docroot/ \ -l thttpd.access.log - + (lighttpd uses the same parameters). We used ApacheBench for testing the RPS (requests per second). @@ -4007,7 +4007,7 @@ $ /usr/sbin/ab -dS -c 10 -n 100000 http://192.168.2.10:80/dummy.out 100k (keep-a.) : 4035.35 893.51[3] 970.21 955.05 [#/sec] thttpd/2.21b+php has been patched with the keep-alive + php patches from PHP4 -sapi/thttpd/thttpd_patch. +sapi/thttpd/thttpd_patch. [1] ab reported: Failed requests: 1 @@ -10,7 +10,7 @@ Installation Installation ------------ -Get the source from +Get the source from http://www.lighttpd.net/download/ diff --git a/Makefile.am b/Makefile.am index dcd2605..3ed6331 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,3 +1,3 @@ SUBDIRS=src doc tests cygwin openwrt -EXTRA_DIST=lighttpd.spec +EXTRA_DIST=lighttpd.spec diff --git a/Makefile.in b/Makefile.in index 8eea902..365738f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -126,7 +126,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -159,6 +158,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ @@ -212,7 +212,7 @@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ SUBDIRS = src doc tests cygwin openwrt -EXTRA_DIST = lighttpd.spec +EXTRA_DIST = lighttpd.spec all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -3,6 +3,28 @@ NEWS ==== +- 1.4.13 - 2006-10-09 + + * added initgroups in spawn-fcgi (#871) + * added apr1 support htpasswd in mod-auth (#870) + * added lighty.stat() to mod_magnet + * fixed segfault in splitted CRLF CRLF sequences + (introduced in 1.4.12) (#876) + * fixed compilation of LOCK support in mod-webdav + * fixed fragments in request-URLs (#869) + * fixed pkg-config check for lua5.1 on debian + * fixed Content-Length = 0 on HEAD requests without + a known Content-Length (#119) + * fixed mkdir() forcing 0700 (#884) + * fixed writev() on FreeBSD 4.x and older (#875) + * removed warning about a 404-error-handler + returned 404 + * backported and fixed the buildsystem changes for + webdav locks + * fixed plugin loading so we can finally load lua + extensions in mod_magnet scripts + * fixed large uploads if xattr is enabled + - 1.4.12 - 2006-09-23 * added experimental LOCK support for webdav @@ -22,40 +44,40 @@ NEWS * fixed required trailing newline in configfiles (#142) * fixed quoting the autoconf files (#466) * fixed empty Host: + $HTTP["host"] handling (#458) - * fixed handling of If-Modified-Since if ETag is not set + * fixed handling of If-Modified-Since if ETag is not set * fixed default-shell if SHELL is not set (#441) * fixed appending and assigning of env.* vars * fixed empty FCGI_STDERR packets - * fixed conditional server.allow-http-11 + * fixed conditional server.allow-http-11 * fixed handling of follow-symlink + lstat() * fixed SIGHUP handling if max-workers is used * fixed "Software caused connection abort" messages on FreeBSD - 1.4.11 - 2006-03-09 - * added ability to specify which ip address spawn-fci listens on + * added ability to specify which ip address spawn-fci listens on (agkr@pobox.com) * added mod_flv_streaming to streaming Flash Movies efficiently - * fixed handling of error codes returned by mod_dav_svn behing a + * fixed handling of error codes returned by mod_dav_svn behing a mod_proxy * fixed error-messages in mod_auth and mod_fastcgi * fixed re-enabling overloaded local fastcgi backends * fixed handling of deleted files in linux-sendfile * fixed compilation on BSD and MacOSX * fixed $SERVER["socket"] on a already bound socket - * fixed local source retrieval on windows + * fixed local source retrieval on windows (secunia) - * fixed hanging cgi if remote side is dieing while reading + * fixed hanging cgi if remote side is dieing while reading from the pipe (sandy@meebo.com) - 1.4.10 - 2006-02-08 * added docs for mod_dirlisting * added fastcgi.map-extensions to mod_fastcgi - * fixed load balancing for mod_fastcgi + * fixed load balancing for mod_fastcgi * fixed extra newline for syslog() in mod_accesslog * fixed user-track cookie for IE in mod_usertrack - * fixed crash in digest handling in mod_auth + * fixed crash in digest handling in mod_auth * fixed handling of 301 response-bodies from a mod_proxy backend * fixed loading of base modules if server.modules is not set * fixed broken cgi if mod_scgi is loaded @@ -87,15 +109,15 @@ NEWS * added auto-reconnect to ldap-server in mod_auth (joerg@netbsd.org) - * changed auth.ldap-cafile to be optional + * changed auth.ldap-cafile to be optional (joerg@netbsd.org) * added strip_request_uri in mod_fastcgi * added more X-* headers to mod_proxy (Ben Grimm <bengrimm@gmail.com>) - * added 'debug' to simple-vhost to suppress the + * added 'debug' to simple-vhost to suppress the (mod_simple_vhost.c.157) No such file or directory /servers/ww.lighttpd.net/pages/ messages by default - * added support to let the server listen on UNIX-socket + * added support to let the server listen on UNIX-socket * changed default stat-cache-engine to 'simple' * removed debian/ dir from source package on request by packager * fixed max-age timestamps in mod_expire @@ -103,12 +125,12 @@ NEWS * fixed range request handling in network_writev * fixed retry on connect error in mod_fastcgi (Robert G. Jakabosky <bobby@alphatrade.com>) - * fixed possible crash in mod_webdav if sqlite3 support + * fixed possible crash in mod_webdav if sqlite3 support is available but not use * fixed fdvent-handler init if server.max-worker was used (Siddharth Vijayakrishnan <mail@bluefireworks.net>) * fixed missing cleanup in mysql_vhost - * fixed assert() in "connections.c:962: + * fixed assert() in "connections.c:962: connection_handle_read_state: Assertion 'c->mem->used' failed." * fixed 64bit issue in md5 * fixed crash in mod_status @@ -127,13 +149,13 @@ NEWS * added madvise() to instruct the kernel the do proper read-ahead in network_writev * added support for %I in mod_accesslog * added better compat to Apache for ?auto in mod_status - * added support for userdirs without a entry in /etc/passwd in mod_userdir + * added support for userdirs without a entry in /etc/passwd in mod_userdir (rob@inversepath.com) * added startup-time selectable network-backend * added location of upload-files to config as array * added webdav.log-xml for logging xml-content in mod_webdav * added Cache-Control: max-age to mod_expire - * workaround missing client-bug by assuming we received a close-notify on + * workaround missing client-bug by assuming we received a close-notify on non-keep-alive requests in SSL request * disabled kerberos5 support by default to fix compilation on RHEL * fixed order of library checks to fix compilation on Solaris 9 @@ -184,10 +206,10 @@ NEWS - 1.4.3 - 2005-09-01 * added gracefull shutdown - * added server.max-connections + * added server.max-connections * fixed compilation on all BSD platforms * fixed init of kqueue and /dev/poll after daemonize - * fixed segfault if select() is event-handler and more than FD_SETSIZE + * fixed segfault if select() is event-handler and more than FD_SETSIZE fds are opened * fixed compilation of mod_cml * fixed bin-copy-env in mod_fastcgi @@ -207,13 +229,13 @@ NEWS * added a complete Class 1 complient mod_webdav * fixed ssl support (especially on OpenBSD) * fixed response header in body problem in mod_cgi - * fixed numbers before body problem + * fixed numbers before body problem * fixed compilation on Solaris and FreeBSD * fixed conditional options in mod_dirlisting * fixed segfault in mod_dirlisting for NFS directories * fixed check for docroot in change-root environments -- 1.4.0 - 2005-08-17 +- 1.4.0 - 2005-08-17 * added nested conditionals * added remote-ip to $HTTP @@ -229,7 +251,7 @@ NEWS * added support for accesslog to syslog * added support for PATH_INFO guessing if check-local is disabled in mod_fastcgi - * added switch to disable range-requests + * added switch to disable range-requests * added valid-user option for mod_auth (tigger at gentoo.org) * added JavaScript based sorting to mod_status (erik) * added selective TCP_CORK (Christian von Roques) @@ -242,7 +264,7 @@ NEWS - 1.3.15 - 2005-07-15 - * added mod_cml + * added mod_cml * added mod_trigger_b4_dl * added encoding to mod_dirlisting * added ?auto to mod_status @@ -285,7 +307,7 @@ NEWS * added REMOTE_PORT and SERVER_ADDR to CGI-env * relaxed handling of newlines before keep-alive requests * relaxed uri-parser again - * fixed PHP_SELF for php + * fixed PHP_SELF for php * fixed compilation on MacOS X * fixed handling of EPIPE and ECONNRESET * fixed crash in mod_auth if config-options are missing @@ -299,7 +321,7 @@ NEWS * added support for full commandline in spawn-fcgi * fixed missing check for IP-address in mod_fastcgi * fixed compile error with openssl in mod_fastcgi - * removed a debug-message from network-functions + * removed a debug-message from network-functions - 1.3.9 - 2005-02-06 @@ -311,9 +333,9 @@ NEWS * fixed min-procs and max-procs in FastCGI on PowerPC * fixed crash in setenv.add-response-header * fixed handling of nph-scripts in CGI - * fixed accidently sending out physical file in CGI on error + * fixed accidently sending out physical file in CGI on error * fixed cygwin support - * fixed handling of missing files + * fixed handling of missing files * fixed HEAD requests for dynamic requests - 1.3.8 - 2005-01-30 @@ -328,22 +350,22 @@ NEWS * fixed build problems on netbsd 1.4.x and 1.5.x * fixed status.url configuration * fixed handling of != and !~ in configutation - * fixed special cases in keep-alive handling + * fixed special cases in keep-alive handling * fixed timeout handling in handling POST requests - * fixed mode AUTHORIZER in FastCGI + * fixed mode AUTHORIZER in FastCGI * fixed handling if internal redirects if no Host: is supplied - * fixed mod_alias + pathinfo + * fixed mod_alias + pathinfo * fixed directory indexes and permissions * enabled sending errorlog to syslog again - 1.3.7 - 2004-12-11 - * added retries for a fastcgi connect if a php-childs + * added retries for a fastcgi connect if a php-childs dies at startup * update the debian directory * added setgroups() to drop all group-privs * added native port to windows via mingw32 - * added server.tag = '...' + * added server.tag = '...' * added support for ${...} in mod_ssi * ported all plugins to conditional support * fixed multipart handling in cgi @@ -357,10 +379,10 @@ NEWS - 1.3.6 - 2004-11-03 * added spawn-fcgi to the distribution - * added support in fastcgi module to spawn fastcgi + * added support in fastcgi module to spawn fastcgi processes itself * fixed logfile cycling if external logging is used - * fixed connection handling in fastcgi if no chunk + * fixed connection handling in fastcgi if no chunk encoding is used * fixed internal redirects on directories if a query string is supplied @@ -369,7 +391,7 @@ NEWS - 1.3.5 - 2004-10-31 - * added mod_alias + * added mod_alias * added mod_userdir * added the exec command to the SSI handler * added a switch to disable follow-symlinks @@ -385,12 +407,12 @@ NEWS * added build target for OpenWRT * added plain backend support for auth-digest * fixed handling the external accesslog processes - * fixed SERVER_NAME in CGI and FastCGI + * fixed SERVER_NAME in CGI and FastCGI - 1.3.3 - 2004-10-16 * added support for NL terminators in CGI-scripts - * added support for conditionals in mod_auth, + * added support for conditionals in mod_auth, mod_simple_vhost and mod_evhost * added a error-handler for 404 codes * fixed request counter in the rrdtool module @@ -494,7 +516,7 @@ NEWS - 1.2.0 - 2004-05-17 * added conforming Expect: handling - * added a module for secure and fast downloading + * added a module for secure and fast downloading * rewrote the event handling interface * fixed array handling which might lead to 'missing header' * fixed pipelining support @@ -12,7 +12,7 @@ a light httpd :Revision: $Revision: 1.8 $ :abstract: - lighttpd a secure, fast, compliant and very flexible web-server + lighttpd a secure, fast, compliant and very flexible web-server which has been optimized for high-performance environments. It has a very low memory footprint compared to other webservers and takes care of cpu-load. Its advanced feature-set (FastCGI, CGI, Auth, Output-Compression, @@ -22,7 +22,7 @@ a light httpd the naming ---------- -lighttpd is a __httpd__ which is +lighttpd is a __httpd__ which is - fast as __light__ning and - __light__ when it comes to memory consumption and system requirements @@ -50,7 +50,7 @@ Advanced Features - load-balanced FastCGI (one webserver distributes requests to multiple PHP-servers via FastCGI) - custom error pages (for Response-Code 400-599) -- virtual hosts +- virtual hosts - directory listings - streaming CGI and FastCGI - URL-Rewriting @@ -71,18 +71,18 @@ PHP-Support - includes a utility to spawn FastCGI processes (necessary for PHP 4.3.x) Security features -````````````````` +````````````````` - chroot(), set UID, set GID - protecting docroot HTTP/1.1 features -````````````````` +````````````````` - Ranges (start-end, start-, -end, multiple ranges) - HTTP/1.0 Keep-Alive + HTTP/1.1 persistent Connections - methods: GET, HEAD, POST -- Last-Modified + If-Modified handling +- Last-Modified + If-Modified handling - sends Content-Length if possible - sends Transfer-Encoding: chunk, if Content-Length is not possible - sends Content-Type @@ -91,7 +91,7 @@ HTTP/1.1 features (http://www.ietf.org/rfc/rfc2617.txt) HTTP/1.1 compliance -``````````````````` +``````````````````` - Sends 206 for Range Requests - Sends 304 for If-Modified Requests @@ -101,7 +101,7 @@ HTTP/1.1 compliance - Sends 416 for "out-of-range" on Range: Header - Sends 501 for request-method != (GET|POST|HEAD) - Sends 505 for protocol != HTTP/1.0 or HTTP/1.1 -- Sends Date: on every requests +- Sends Date: on every requests Intended Audience ----------------- @@ -118,14 +118,14 @@ It has been tested to work with - IE 6.0 - Mozilla 1.x -- Konqueror 3.1 +- Konqueror 3.1 (for Keep-Alive/Persistent Connections, Accept-Encoding for PHP + gzip) -- wget +- wget (for Resuming) - acrobat plugin (for multiple ranges) - - + + Works on -------- diff --git a/config.h.in b/config.h.in index 068a8b1..36f3ab7 100644 --- a/config.h.in +++ b/config.h.in @@ -33,6 +33,9 @@ /* fam.h */ #undef HAVE_FAM_H +/* Define to 1 if you have the <fastcgi/fastcgi.h> header file. */ +#undef HAVE_FASTCGI_FASTCGI_H + /* Define to 1 if you have the <fastcgi.h> header file. */ #undef HAVE_FASTCGI_H @@ -331,6 +334,15 @@ /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H +/* libuuid */ +#undef HAVE_UUID + +/* uuid/uuid.h is available */ +#undef HAVE_UUID_H + +/* Define to 1 if you have the <uuid/uuid.h> header file. */ +#undef HAVE_UUID_UUID_H + /* Define to 1 if you have the <valgrind/valgrind.h> header file. */ #undef HAVE_VALGRIND_VALGRIND_H @@ -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.12. +# Generated by GNU Autoconf 2.59 for lighttpd 1.4.13. # # 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.12' -PACKAGE_STRING='lighttpd 1.4.12' +PACKAGE_VERSION='1.4.13' +PACKAGE_STRING='lighttpd 1.4.13' PACKAGE_BUGREPORT='jan@kneschke.de' ac_unique_file="src/server.c" @@ -465,7 +465,7 @@ ac_includes_default="\ # include <unistd.h> #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP CPP LN_S NO_RDYNAMIC_TRUE NO_RDYNAMIC_FALSE U ANSI2KNR ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBOBJS MYSQL_CONFIG MYSQL_LIBS MYSQL_INCLUDE LDAP_LIB LBER_LIB ATTR_LIB DL_LIB SSL_LIB PCRECONFIG PCRE_LIB Z_LIB BZ_LIB PKG_CONFIG ac_pt_PKG_CONFIG FAM_CFLAGS FAM_LIBS XML_CFLAGS XML_LIBS SQLITE_CFLAGS SQLITE_LIBS GDBM_LIB MEMCACHE_LIB LUACONFIG LUA_CFLAGS LUA_LIBS CRYPT_LIB SENDFILE_LIB CROSS_COMPILING_TRUE CROSS_COMPILING_FALSE CHECK_WITH_FASTCGI_TRUE CHECK_WITH_FASTCGI_FALSE LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar MAINTAINER_MODE_TRUE MAINTAINER_MODE_FALSE MAINT CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE EGREP CPP LN_S NO_RDYNAMIC_TRUE NO_RDYNAMIC_FALSE U ANSI2KNR ECHO AR ac_ct_AR RANLIB ac_ct_RANLIB CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE CXXCPP F77 FFLAGS ac_ct_F77 LIBTOOL LIBOBJS MYSQL_CONFIG MYSQL_LIBS MYSQL_INCLUDE LDAP_LIB LBER_LIB ATTR_LIB DL_LIB SSL_LIB PCRECONFIG PCRE_LIB Z_LIB BZ_LIB PKG_CONFIG ac_pt_PKG_CONFIG FAM_CFLAGS FAM_LIBS XML_CFLAGS XML_LIBS SQLITE_CFLAGS SQLITE_LIBS UUID_LIBS GDBM_LIB MEMCACHE_LIB LUA_CFLAGS LUA_LIBS CRYPT_LIB SENDFILE_LIB CROSS_COMPILING_TRUE CROSS_COMPILING_FALSE CHECK_WITH_FASTCGI_TRUE CHECK_WITH_FASTCGI_FALSE LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -990,7 +990,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.12 to adapt to many kinds of systems. +\`configure' configures lighttpd 1.4.13 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1057,7 +1057,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of lighttpd 1.4.12:";; + short | recursive ) echo "Configuration of lighttpd 1.4.13:";; esac cat <<\_ACEOF @@ -1102,6 +1102,7 @@ Optional Packages: --with-bzip2 Enable bzip2 support for mod_compress --with-fam fam/gamin for reducing number of stat() calls --with-webdav-props properties in mod_webdav + --with-webdav-locks locks in mod_webdav --with-gdbm gdbm storage for mod_trigger_b4_dl --with-memcache memcached storage for mod_trigger_b4_dl --with-lua lua engine for mod_cml @@ -1229,7 +1230,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -lighttpd configure 1.4.12 +lighttpd configure 1.4.13 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. @@ -1243,7 +1244,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.12, which was +It was created by lighttpd $as_me 1.4.13, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ @@ -1971,7 +1972,7 @@ fi # Define the identity of the package. PACKAGE='lighttpd' - VERSION='1.4.12' + VERSION='1.4.13' cat >>confdefs.h <<_ACEOF @@ -4927,7 +4928,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 4930 "configure"' > conftest.$ac_ext + echo '#line 4931 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -6033,7 +6034,7 @@ fi # Provide some information about the compiler. -echo "$as_me:6036:" \ +echo "$as_me:6037:" \ "checking for Fortran 77 compiler version" >&5 ac_compiler=`set X $ac_compile; echo $2` { (eval echo "$as_me:$LINENO: \"$ac_compiler --version </dev/null >&5\"") >&5 @@ -7131,11 +7132,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7134: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7135: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7138: \$? = $ac_status" >&5 + echo "$as_me:7139: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7393,11 +7394,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7396: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7397: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:7400: \$? = $ac_status" >&5 + echo "$as_me:7401: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -7455,11 +7456,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:7458: $lt_compile\"" >&5) + (eval echo "\"\$as_me:7459: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:7462: \$? = $ac_status" >&5 + echo "$as_me:7463: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -8840,7 +8841,7 @@ linux*) libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) - echo '#line 8843 "configure"' > conftest.$ac_ext + echo '#line 8844 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -9711,7 +9712,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 9714 "configure" +#line 9715 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -9809,7 +9810,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 9812 "configure" +#line 9813 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12057,11 +12058,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:12060: $lt_compile\"" >&5) + (eval echo "\"\$as_me:12061: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:12064: \$? = $ac_status" >&5 + echo "$as_me:12065: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -12119,11 +12120,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:12122: $lt_compile\"" >&5) + (eval echo "\"\$as_me:12123: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:12126: \$? = $ac_status" >&5 + echo "$as_me:12127: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -12634,7 +12635,7 @@ linux*) libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) - echo '#line 12637 "configure"' > conftest.$ac_ext + echo '#line 12638 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -13505,7 +13506,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 13508 "configure" +#line 13509 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -13603,7 +13604,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 13606 "configure" +#line 13607 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -14488,11 +14489,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14491: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14492: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14495: \$? = $ac_status" >&5 + echo "$as_me:14496: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14550,11 +14551,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14553: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14554: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14557: \$? = $ac_status" >&5 + echo "$as_me:14558: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -15915,7 +15916,7 @@ linux*) libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) - echo '#line 15918 "configure"' > conftest.$ac_ext + echo '#line 15919 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -16688,11 +16689,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:16691: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16692: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16695: \$? = $ac_status" >&5 + echo "$as_me:16696: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -16950,11 +16951,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:16953: $lt_compile\"" >&5) + (eval echo "\"\$as_me:16954: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:16957: \$? = $ac_status" >&5 + echo "$as_me:16958: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -17012,11 +17013,11 @@ else -e 's:.*FLAGS}? :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:17015: $lt_compile\"" >&5) + (eval echo "\"\$as_me:17016: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:17019: \$? = $ac_status" >&5 + echo "$as_me:17020: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -18397,7 +18398,7 @@ linux*) libsuff= case "$host_cpu" in x86_64*|s390x*|powerpc64*) - echo '#line 18400 "configure"' > conftest.$ac_ext + echo '#line 18401 "configure"' > conftest.$ac_ext if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -19268,7 +19269,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 19271 "configure" +#line 19272 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -19366,7 +19367,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<EOF -#line 19369 "configure" +#line 19370 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -20683,11 +20684,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/prctl.h +sys/resource.h sys/un.h syslog.h sys/prctl.h uuid/uuid.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -26227,29 +26229,28 @@ _ACEOF fi -fi -echo "$as_me:$LINENO: checking for gdbm" >&5 -echo $ECHO_N "checking for gdbm... $ECHO_C" >&6 + echo "$as_me:$LINENO: checking for locks in mod_webdav" >&5 +echo $ECHO_N "checking for locks in mod_webdav... $ECHO_C" >&6 -# Check whether --with-gdbm or --without-gdbm was given. -if test "${with_gdbm+set}" = set; then - withval="$with_gdbm" - WITH_GDBM=$withval +# Check whether --with-webdav-locks or --without-webdav-locks was given. +if test "${with_webdav_locks+set}" = set; then + withval="$with_webdav_locks" + WITH_WEBDAV_LOCKS=$withval else - WITH_GDBM=no + WITH_WEBDAV_LOCKS=no fi; -echo "$as_me:$LINENO: result: $WITH_GDBM" >&5 -echo "${ECHO_T}$WITH_GDBM" >&6 + echo "$as_me:$LINENO: result: $WITH_WEBDAV_LOCKS" >&5 +echo "${ECHO_T}$WITH_WEBDAV_LOCKS" >&6 -if test "$WITH_GDBM" != "no"; then - echo "$as_me:$LINENO: checking for gdbm_open in -lgdbm" >&5 -echo $ECHO_N "checking for gdbm_open in -lgdbm... $ECHO_C" >&6 -if test "${ac_cv_lib_gdbm_gdbm_open+set}" = set; then + if test "$WITH_WEBDAV_LOCKS" != "no"; then + echo "$as_me:$LINENO: checking for uuid_unparse in -luuid" >&5 +echo $ECHO_N "checking for uuid_unparse in -luuid... $ECHO_C" >&6 +if test "${ac_cv_lib_uuid_uuid_unparse+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lgdbm $LIBS" +LIBS="-luuid $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -26263,11 +26264,11 @@ extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ -char gdbm_open (); +char uuid_unparse (); int main () { -gdbm_open (); +uuid_unparse (); ; return 0; } @@ -26294,23 +26295,23 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_lib_gdbm_gdbm_open=yes + ac_cv_lib_uuid_uuid_unparse=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_lib_gdbm_gdbm_open=no +ac_cv_lib_uuid_uuid_unparse=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_gdbm_gdbm_open" >&5 -echo "${ECHO_T}$ac_cv_lib_gdbm_gdbm_open" >&6 -if test $ac_cv_lib_gdbm_gdbm_open = yes; then +echo "$as_me:$LINENO: result: $ac_cv_lib_uuid_uuid_unparse" >&5 +echo "${ECHO_T}$ac_cv_lib_uuid_uuid_unparse" >&6 +if test $ac_cv_lib_uuid_uuid_unparse = yes; then -for ac_header in gdbm.h +for ac_header in uuid/uuid.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -26455,14 +26456,15 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF - GDBM_LIB=-lgdbm + UUID_LIBS=-luuid cat >>confdefs.h <<\_ACEOF -#define HAVE_GDBM 1 +#define HAVE_UUID 1 _ACEOF - cat >>confdefs.h <<\_ACEOF -#define HAVE_GDBM_H 1 + +cat >>confdefs.h <<\_ACEOF +#define HAVE_UUID_H 1 _ACEOF @@ -26474,28 +26476,31 @@ done fi + fi fi -echo "$as_me:$LINENO: checking for memcache" >&5 -echo $ECHO_N "checking for memcache... $ECHO_C" >&6 -# Check whether --with-memcache or --without-memcache was given. -if test "${with_memcache+set}" = set; then - withval="$with_memcache" - WITH_MEMCACHE=$withval +echo "$as_me:$LINENO: checking for gdbm" >&5 +echo $ECHO_N "checking for gdbm... $ECHO_C" >&6 + +# Check whether --with-gdbm or --without-gdbm was given. +if test "${with_gdbm+set}" = set; then + withval="$with_gdbm" + WITH_GDBM=$withval else - WITH_MEMCACHE=no + WITH_GDBM=no fi; -echo "$as_me:$LINENO: result: $WITH_MEMCACHE" >&5 -echo "${ECHO_T}$WITH_MEMCACHE" >&6 -if test "$WITH_MEMCACHE" != "no"; then - echo "$as_me:$LINENO: checking for mc_new in -lmemcache" >&5 -echo $ECHO_N "checking for mc_new in -lmemcache... $ECHO_C" >&6 -if test "${ac_cv_lib_memcache_mc_new+set}" = set; then +echo "$as_me:$LINENO: result: $WITH_GDBM" >&5 +echo "${ECHO_T}$WITH_GDBM" >&6 + +if test "$WITH_GDBM" != "no"; then + echo "$as_me:$LINENO: checking for gdbm_open in -lgdbm" >&5 +echo $ECHO_N "checking for gdbm_open in -lgdbm... $ECHO_C" >&6 +if test "${ac_cv_lib_gdbm_gdbm_open+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-lmemcache $LIBS" +LIBS="-lgdbm $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -26509,11 +26514,11 @@ extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ -char mc_new (); +char gdbm_open (); int main () { -mc_new (); +gdbm_open (); ; return 0; } @@ -26540,23 +26545,23 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_lib_memcache_mc_new=yes + ac_cv_lib_gdbm_gdbm_open=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_lib_memcache_mc_new=no +ac_cv_lib_gdbm_gdbm_open=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_memcache_mc_new" >&5 -echo "${ECHO_T}$ac_cv_lib_memcache_mc_new" >&6 -if test $ac_cv_lib_memcache_mc_new = yes; then +echo "$as_me:$LINENO: result: $ac_cv_lib_gdbm_gdbm_open" >&5 +echo "${ECHO_T}$ac_cv_lib_gdbm_gdbm_open" >&6 +if test $ac_cv_lib_gdbm_gdbm_open = yes; then -for ac_header in memcache.h +for ac_header in gdbm.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -26701,15 +26706,14 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF - MEMCACHE_LIB=-lmemcache + GDBM_LIB=-lgdbm cat >>confdefs.h <<\_ACEOF -#define HAVE_MEMCACHE 1 +#define HAVE_GDBM 1 _ACEOF - -cat >>confdefs.h <<\_ACEOF -#define HAVE_MEMCACHE_H 1 + cat >>confdefs.h <<\_ACEOF +#define HAVE_GDBM_H 1 _ACEOF @@ -26723,81 +26727,26 @@ fi fi -echo "$as_me:$LINENO: checking if lua-support is requested" >&5 -echo $ECHO_N "checking if lua-support is requested... $ECHO_C" >&6 +echo "$as_me:$LINENO: checking for memcache" >&5 +echo $ECHO_N "checking for memcache... $ECHO_C" >&6 -# Check whether --with-lua or --without-lua was given. -if test "${with_lua+set}" = set; then - withval="$with_lua" - WITH_LUA=$withval +# Check whether --with-memcache or --without-memcache was given. +if test "${with_memcache+set}" = set; then + withval="$with_memcache" + WITH_MEMCACHE=$withval else - WITH_LUA=no + WITH_MEMCACHE=no fi; - -echo "$as_me:$LINENO: result: $WITH_LUA" >&5 -echo "${ECHO_T}$WITH_LUA" >&6 -if test "$WITH_LUA" != "no"; then - # Extract the first word of "lua-config", so it can be a program name with args. -set dummy lua-config; ac_word=$2 -echo "$as_me:$LINENO: checking for $ac_word" >&5 -echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 -if test "${ac_cv_path_LUACONFIG+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - case $LUACONFIG in - [\\/]* | ?:[\\/]*) - ac_cv_path_LUACONFIG="$LUACONFIG" # Let the user override the test with a path. - ;; - *) - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - ac_cv_path_LUACONFIG="$as_dir/$ac_word$ac_exec_ext" - echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done -done - - ;; -esac -fi -LUACONFIG=$ac_cv_path_LUACONFIG - -if test -n "$LUACONFIG"; then - echo "$as_me:$LINENO: result: $LUACONFIG" >&5 -echo "${ECHO_T}$LUACONFIG" >&6 -else - echo "$as_me:$LINENO: result: no" >&5 -echo "${ECHO_T}no" >&6 -fi - - - if test x"$LUACONFIG" != x; then - LUA_CFLAGS=`$LUACONFIG --include` - LUA_LIBS=`$LUACONFIG --libs --extralibs` - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LUA 1 -_ACEOF - - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LUA_H 1 -_ACEOF - - else - echo "$as_me:$LINENO: checking for lua_open in -llua" >&5 -echo $ECHO_N "checking for lua_open in -llua... $ECHO_C" >&6 -if test "${ac_cv_lib_lua_lua_open+set}" = set; then +echo "$as_me:$LINENO: result: $WITH_MEMCACHE" >&5 +echo "${ECHO_T}$WITH_MEMCACHE" >&6 +if test "$WITH_MEMCACHE" != "no"; then + echo "$as_me:$LINENO: checking for mc_new in -lmemcache" >&5 +echo $ECHO_N "checking for mc_new in -lmemcache... $ECHO_C" >&6 +if test "${ac_cv_lib_memcache_mc_new+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else ac_check_lib_save_LIBS=$LIBS -LIBS="-llua $LIBS" +LIBS="-lmemcache $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF @@ -26811,11 +26760,11 @@ extern "C" #endif /* We use char because int might match the return type of a gcc2 builtin and then its argument prototype would still apply. */ -char lua_open (); +char mc_new (); int main () { -lua_open (); +mc_new (); ; return 0; } @@ -26842,23 +26791,23 @@ if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ac_cv_lib_lua_lua_open=yes + ac_cv_lib_memcache_mc_new=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -ac_cv_lib_lua_lua_open=no +ac_cv_lib_memcache_mc_new=no fi rm -f conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi -echo "$as_me:$LINENO: result: $ac_cv_lib_lua_lua_open" >&5 -echo "${ECHO_T}$ac_cv_lib_lua_lua_open" >&6 -if test $ac_cv_lib_lua_lua_open = yes; then +echo "$as_me:$LINENO: result: $ac_cv_lib_memcache_mc_new" >&5 +echo "${ECHO_T}$ac_cv_lib_memcache_mc_new" >&6 +if test $ac_cv_lib_memcache_mc_new = yes; then -for ac_header in lua.h +for ac_header in memcache.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -27003,15 +26952,15 @@ if test `eval echo '${'$as_ac_Header'}'` = yes; then #define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF - LUA_LIBS="-llua -llualib" + MEMCACHE_LIB=-lmemcache cat >>confdefs.h <<\_ACEOF -#define HAVE_LUA 1 +#define HAVE_MEMCACHE 1 _ACEOF cat >>confdefs.h <<\_ACEOF -#define HAVE_LUA_H 1 +#define HAVE_MEMCACHE_H 1 _ACEOF @@ -27022,10 +26971,26 @@ done fi - fi - if test x"$LUA_LIBS" = x; then - # try pkgconfig +fi + +echo "$as_me:$LINENO: checking if lua-support is requested" >&5 +echo $ECHO_N "checking if lua-support is requested... $ECHO_C" >&6 + +# Check whether --with-lua or --without-lua was given. +if test "${with_lua+set}" = set; then + withval="$with_lua" + WITH_LUA=$withval +else + WITH_LUA=no +fi; + +echo "$as_me:$LINENO: result: $WITH_LUA" >&5 +echo "${ECHO_T}$WITH_LUA" >&6 +if test "$WITH_LUA" != "no"; then + if test "$WITH_LUA" == "yes"; then + WITH_LUA=lua + fi pkg_failed=no echo "$as_me:$LINENO: checking for LUA" >&5 @@ -27036,12 +27001,12 @@ if test -n "$PKG_CONFIG"; then pkg_cv_LUA_CFLAGS="$LUA_CFLAGS" else if test -n "$PKG_CONFIG" && \ - { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua >= 5.0\"") >&5 - ($PKG_CONFIG --exists --print-errors "lua >= 5.0") 2>&5 + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"\$WITH_LUA >= 5.1\"") >&5 + ($PKG_CONFIG --exists --print-errors "$WITH_LUA >= 5.1") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then - pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "lua >= 5.0" 2>/dev/null` + pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "$WITH_LUA >= 5.1" 2>/dev/null` else pkg_failed=yes fi @@ -27054,12 +27019,12 @@ if test -n "$PKG_CONFIG"; then pkg_cv_LUA_LIBS="$LUA_LIBS" else if test -n "$PKG_CONFIG" && \ - { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"lua >= 5.0\"") >&5 - ($PKG_CONFIG --exists --print-errors "lua >= 5.0") 2>&5 + { (echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"\$WITH_LUA >= 5.1\"") >&5 + ($PKG_CONFIG --exists --print-errors "$WITH_LUA >= 5.1") 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then - pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "lua >= 5.0" 2>/dev/null` + pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "$WITH_LUA >= 5.1" 2>/dev/null` else pkg_failed=yes fi @@ -27078,14 +27043,14 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "lua >= 5.0"` + LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$WITH_LUA >= 5.1"` else - LUA_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "lua >= 5.0"` + LUA_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$WITH_LUA >= 5.1"` fi # Put the nasty error message in config.log where it belongs echo "$LUA_PKG_ERRORS" >&5 - { { echo "$as_me:$LINENO: error: Package requirements (lua >= 5.0) were not met: + { { echo "$as_me:$LINENO: error: Package requirements ($WITH_LUA >= 5.1) were not met: $LUA_PKG_ERRORS @@ -27096,7 +27061,7 @@ Alternatively, you may set the environment variables LUA_CFLAGS and LUA_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 -echo "$as_me: error: Package requirements (lua >= 5.0) were not met: +echo "$as_me: error: Package requirements ($WITH_LUA >= 5.1) were not met: $LUA_PKG_ERRORS @@ -27148,7 +27113,6 @@ _ACEOF fi - fi @@ -28814,7 +28778,8 @@ echo "${ECHO_T}$ac_cv_lib_fcgi_FCGI_Accept" >&6 if test $ac_cv_lib_fcgi_FCGI_Accept = yes; then -for ac_header in fastcgi.h + +for ac_header in fastcgi.h fastcgi/fastcgi.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -28982,7 +28947,7 @@ fi if test "${GCC}" = "yes"; then - CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic" + CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99" fi LIGHTTPD_VERSION_ID=`echo $PACKAGE_VERSION | $AWK -F '.' '{print "(" $1 " << 16 | " $2 " << 8 | " $3 ")"}'` @@ -29405,7 +29370,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by lighttpd $as_me 1.4.12, which was +This file was extended by lighttpd $as_me 1.4.13, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -29468,7 +29433,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -lighttpd config.status 1.4.12 +lighttpd config.status 1.4.13 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" @@ -29779,9 +29744,9 @@ s,@XML_CFLAGS@,$XML_CFLAGS,;t t s,@XML_LIBS@,$XML_LIBS,;t t s,@SQLITE_CFLAGS@,$SQLITE_CFLAGS,;t t s,@SQLITE_LIBS@,$SQLITE_LIBS,;t t +s,@UUID_LIBS@,$UUID_LIBS,;t t s,@GDBM_LIB@,$GDBM_LIB,;t t s,@MEMCACHE_LIB@,$MEMCACHE_LIB,;t t -s,@LUACONFIG@,$LUACONFIG,;t t s,@LUA_CFLAGS@,$LUA_CFLAGS,;t t s,@LUA_LIBS@,$LUA_LIBS,;t t s,@CRYPT_LIB@,$CRYPT_LIB,;t t @@ -30612,6 +30577,14 @@ else disable_feature="$disable_feature $features" fi +features="webdav-locks" +if test "x$UUID_LIBS" \!= x; then + enable_feature="$enable_feature $features" +else + disable_feature="$disable_feature $features" +fi + + ## output $ECHO diff --git a/configure.in b/configure.in index 74bca03..f0c789f 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.12, jan@kneschke.de) +AC_INIT(lighttpd, 1.4.13, jan@kneschke.de) AC_CONFIG_SRCDIR([src/server.c]) AC_CANONICAL_TARGET @@ -40,13 +40,13 @@ dnl more automake stuff AM_C_PROTOTYPES dnl libtool -AC_DISABLE_STATIC +AC_DISABLE_STATIC AC_ENABLE_SHARED AC_LIBTOOL_DLOPEN AC_PROG_LIBTOOL -dnl for solaris +dnl for solaris CPPFLAGS="${CPPFLAGS} -D_REENTRANT -D__EXTENSIONS__" # Checks for header files. @@ -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/prctl.h]) +sys/resource.h sys/un.h syslog.h sys/prctl.h uuid/uuid.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_CONST @@ -90,7 +90,7 @@ AC_ARG_WITH(mysql, [WITH_MYSQL=$withval],[WITH_MYSQL=no]) if test "$WITH_MYSQL" != "no"; then - AC_MSG_RESULT(yes) + AC_MSG_RESULT(yes) if test "$WITH_MYSQL" = "yes"; then AC_PATH_PROG(MYSQL_CONFIG, mysql_config) else @@ -237,8 +237,8 @@ if test "x$use_openssl" = "xyes"; then AC_CHECK_HEADERS([openssl/ssl.h]) OLDLIBS="$LIBS" - AC_CHECK_LIB(crypto, BIO_f_base64, [ - AC_CHECK_LIB(ssl, SSL_new, [ SSL_LIB="-lssl -lcrypto" + AC_CHECK_LIB(crypto, BIO_f_base64, [ + AC_CHECK_LIB(ssl, SSL_new, [ SSL_LIB="-lssl -lcrypto" AC_DEFINE(HAVE_LIBSSL, [], [Have libssl]) ], [], [ -lcrypto "$DL_LIB" ]) ], [], []) LIBS="$OLDLIBS" @@ -253,7 +253,7 @@ AC_MSG_RESULT([$WITH_PCRE]) if test "x$cross_compiling" = xno -a "$WITH_PCRE" != "no"; then AC_PATH_PROG(PCRECONFIG, pcre-config) - if test x"$PCRECONFIG" != x; then + if test x"$PCRECONFIG" != x; then PCRE_LIB=`$PCRECONFIG --libs` CPPFLAGS="$CPPFLAGS `$PCRECONFIG --cflags`" OLDLIBS="$LIBS" @@ -339,7 +339,24 @@ if test "$WITH_WEBDAV_PROPS" != "no"; then AC_DEFINE([HAVE_SQLITE3], [1], [libsqlite3]) AC_DEFINE([HAVE_SQLITE3_H], [1], [sqlite3.h]) ]) + + AC_MSG_CHECKING(for locks in mod_webdav) + AC_ARG_WITH(webdav-locks, AC_HELP_STRING([--with-webdav-locks],[locks in mod_webdav]), + [WITH_WEBDAV_LOCKS=$withval],[WITH_WEBDAV_LOCKS=no]) + AC_MSG_RESULT([$WITH_WEBDAV_LOCKS]) + + if test "$WITH_WEBDAV_LOCKS" != "no"; then + AC_CHECK_LIB(uuid, uuid_unparse, [ + AC_CHECK_HEADERS([uuid/uuid.h],[ + UUID_LIBS=-luuid + AC_DEFINE([HAVE_UUID], [1], [libuuid]) + AC_DEFINE([HAVE_UUID_H], [1], [uuid/uuid.h is available]) + ]) + ]) + + fi fi +AC_SUBST(UUID_LIBS) dnl Check for gdbm AC_MSG_CHECKING(for gdbm) @@ -373,7 +390,7 @@ if test "$WITH_MEMCACHE" != "no"; then ]) AC_SUBST(MEMCACHE_LIB) fi - + dnl Check for lua AC_MSG_CHECKING(if lua-support is requested) AC_ARG_WITH(lua, AC_HELP_STRING([--with-lua],[lua engine for mod_cml]), @@ -381,30 +398,13 @@ AC_ARG_WITH(lua, AC_HELP_STRING([--with-lua],[lua engine for mod_cml]), AC_MSG_RESULT($WITH_LUA) if test "$WITH_LUA" != "no"; then - AC_PATH_PROG(LUACONFIG, lua-config) - - if test x"$LUACONFIG" != x; then - LUA_CFLAGS=`$LUACONFIG --include` - LUA_LIBS=`$LUACONFIG --libs --extralibs` + if test "$WITH_LUA" == "yes"; then + WITH_LUA=lua + fi + PKG_CHECK_MODULES(LUA, $WITH_LUA >= 5.1, [ AC_DEFINE([HAVE_LUA], [1], [liblua]) AC_DEFINE([HAVE_LUA_H], [1], [lua.h]) - else - AC_CHECK_LIB(lua, lua_open, [ - AC_CHECK_HEADERS([lua.h],[ - LUA_LIBS="-llua -llualib" - AC_DEFINE([HAVE_LUA], [1], [liblua]) - AC_DEFINE([HAVE_LUA_H], [1], [lua.h]) - ]) - ]) - fi - - if test x"$LUA_LIBS" = x; then - # try pkgconfig - PKG_CHECK_MODULES(LUA, lua >= 5.0, [ - AC_DEFINE([HAVE_LUA], [1], [liblua]) - AC_DEFINE([HAVE_LUA_H], [1], [lua.h]) - ]) - fi + ]) AC_SUBST(LUA_CFLAGS) AC_SUBST(LUA_LIBS) @@ -472,13 +472,13 @@ if test "x$ac_cv_func_sendfile" = xyes; then int o = 0; if (-1 == sendfile(-1, 0, &o, 0) && errno == ENOSYS) return -1; return 0; - } ], - AC_MSG_RESULT(yes), - [ AC_MSG_RESULT(no) + } ], + AC_MSG_RESULT(yes), + [ AC_MSG_RESULT(no) AC_DEFINE([HAVE_SENDFILE_BROKEN], [1], [broken sendfile]) ] ) else - AC_MSG_RESULT(no, cross-compiling) - AC_DEFINE([HAVE_SENDFILE_BROKEN], [1], [broken sendfile]) + AC_MSG_RESULT(no, cross-compiling) + AC_DEFINE([HAVE_SENDFILE_BROKEN], [1], [broken sendfile]) fi fi @@ -498,7 +498,7 @@ if test x$ipv6 = xtrue; then #include <sys/socket.h> #include <netinet/in.h>], [struct sockaddr_in6 s; struct in6_addr t=in6addr_any; int i=AF_INET6; s; t.s6_addr[0] = 0; ], [ac_cv_ipv6_support=yes], [ac_cv_ipv6_support=no])]) - + if test "$ac_cv_ipv6_support" = yes; then AC_DEFINE(HAVE_IPV6,1,[Whether to enable IPv6 support]) fi @@ -510,7 +510,7 @@ AM_CONDITIONAL(CROSS_COMPILING, test "x$cross_compiling" = xyes) dnl check for fastcgi lib, for the tests only fastcgi_found=no AC_CHECK_LIB(fcgi, FCGI_Accept, [ - AC_CHECK_HEADERS([fastcgi.h],[ + AC_CHECK_HEADERS([fastcgi.h fastcgi/fastcgi.h],[ fastcgi_found=yes ]) ]) @@ -519,12 +519,12 @@ AM_CONDITIONAL(CHECK_WITH_FASTCGI, test "x$fastcgi_found" = xyes) if test "${GCC}" = "yes"; then - CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic" + CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99" fi dnl build version-id LIGHTTPD_VERSION_ID=`echo $PACKAGE_VERSION | $AWK -F '.' '{print "(" $1 " << 16 | " $2 " << 8 | " $3 ")"}'` -AC_DEFINE_UNQUOTED([LIGHTTPD_VERSION_ID], [$LIGHTTPD_VERSION_ID], [lighttpd-version-id]) +AC_DEFINE_UNQUOTED([LIGHTTPD_VERSION_ID], [$LIGHTTPD_VERSION_ID], [lighttpd-version-id]) AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile tests/Makefile \ tests/docroot/Makefile \ @@ -538,7 +538,7 @@ AC_CONFIG_FILES([Makefile src/Makefile doc/Makefile tests/Makefile \ AC_OUTPUT -do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming" +do_build="mod_cgi mod_fastcgi mod_proxy mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_scgi mod_flv_streaming" plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl" features="regex-conditionals" @@ -642,6 +642,14 @@ else disable_feature="$disable_feature $features" fi +features="webdav-locks" +if test "x$UUID_LIBS" \!= x; then + enable_feature="$enable_feature $features" +else + disable_feature="$disable_feature $features" +fi + + ## output $ECHO diff --git a/cygwin/Makefile.in b/cygwin/Makefile.in index 68007f9..ba0c88c 100644 --- a/cygwin/Makefile.in +++ b/cygwin/Makefile.in @@ -101,7 +101,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -134,6 +133,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ diff --git a/cygwin/lighttpd.README b/cygwin/lighttpd.README index 2454c27..9a06680 100644 --- a/cygwin/lighttpd.README +++ b/cygwin/lighttpd.README @@ -1,114 +1,114 @@ -lighttpd
-------------------------------------------
-A fast, secure and flexible webserver
-
-Runtime requirements:
- cygwin-1.5.10 or newer
- crypt-1.1 or newer
- libbz2_1-1.0.2 or newer
- libpcre0-4.5 or newer
- openssl-0.9.7d or newer
- zlib-1.2.1 or newer
-
-Build requirements:
- cygwin-1.5.10 or newer
- gcc-3.3.1-3 or newer
- binutils-20030901-1 or newer
- crypt
- openssl-devel
- openssl
- openldap
- openldap-devel
- zlib
- bzip2
-
-Canonical homepage:
- http://jan.kneschke.de/projects/lighttpd/
-
-Canonical download:
- http://jan.kneschke.de/projects/lighttpd/download
-
-------------------------------------
-
-Build instructions:
- unpack lighttpd-1.4.12-<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.12-<REL>.sh all
-
-This will create:
- /usr/src/lighttpd-1.4.12-<REL>.tar.bz2
- /usr/src/lighttpd-1.4.12-<REL>-src.tar.bz2
-
-Or use './lighttpd-1.4.12-<REL>.sh prep' to get a patched source directory
-
--------------------------------------------
-
-Files included in the binary distribution:
-
- /etc/lighttpd/lighttpd.conf.default
- /usr/lib/cyglightcomp.dll
- /usr/lib/lighttpd/mod_access.dll
- /usr/lib/lighttpd/mod_accesslog.dll
- /usr/lib/lighttpd/mod_auth.dll
- /usr/lib/lighttpd/mod_cgi.dll
- /usr/lib/lighttpd/mod_compress.dll
- /usr/lib/lighttpd/mod_evhost.dll
- /usr/lib/lighttpd/mod_expire.dll
- /usr/lib/lighttpd/mod_fastcgi.dll
- /usr/lib/lighttpd/mod_httptls.dll
- /usr/lib/lighttpd/mod_maps.dll
- /usr/lib/lighttpd/mod_proxy.dll
- /usr/lib/lighttpd/mod_redirect.dll
- /usr/lib/lighttpd/mod_rewrite.dll
- /usr/lib/lighttpd/mod_rrdtool.dll
- /usr/lib/lighttpd/mod_secdownload.dll
- /usr/lib/lighttpd/mod_simple_vhost.dll
- /usr/lib/lighttpd/mod_ssi.dll
- /usr/lib/lighttpd/mod_status.dll
- /usr/lib/lighttpd/mod_usertrack.dll
- /usr/sbin/lighttpd.exe
- /usr/share/doc/Cygwin/lighttpd-1.3.0.README
- /usr/share/doc/lighttpd-1.3.0/accesslog.txt
- /usr/share/doc/lighttpd-1.3.0/authentification.txt
- /usr/share/doc/lighttpd-1.3.0/AUTHORS
- /usr/share/doc/lighttpd-1.3.0/cgi.txt
- /usr/share/doc/lighttpd-1.3.0/ChangeLog
- /usr/share/doc/lighttpd-1.3.0/compress.txt
- /usr/share/doc/lighttpd-1.3.0/configuration.txt
- /usr/share/doc/lighttpd-1.3.0/COPYING
- /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
- /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
- /usr/share/doc/lighttpd-1.3.0/features.txt
- /usr/share/doc/lighttpd-1.3.0/INSTALL
- /usr/share/doc/lighttpd-1.3.0/NEWS
- /usr/share/doc/lighttpd-1.3.0/performance.txt
- /usr/share/doc/lighttpd-1.3.0/plugins.txt
- /usr/share/doc/lighttpd-1.3.0/proxy.txt
- /usr/share/doc/lighttpd-1.3.0/README
- /usr/share/doc/lighttpd-1.3.0/redirect.txt
- /usr/share/doc/lighttpd-1.3.0/rewrite.txt
- /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
- /usr/share/doc/lighttpd-1.3.0/secdownload.txt
- /usr/share/doc/lighttpd-1.3.0/security.txt
- /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
- /usr/share/doc/lighttpd-1.3.0/skeleton.txt
- /usr/share/doc/lighttpd-1.3.0/ssi.txt
- /usr/share/doc/lighttpd-1.3.0/state.txt
- /usr/share/man/man1/lighttpd.1.gz
-
-------------------
-
-Port Notes:
-
----------- lighttpd-1.3.1-1 -----------
-
-Updated to 1.3.1
-
----------- lighttpd-1.3.0-1 -----------
-Initial release
-
-Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
-Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
-
+lighttpd +------------------------------------------ +A fast, secure and flexible webserver + +Runtime requirements: + cygwin-1.5.10 or newer + crypt-1.1 or newer + libbz2_1-1.0.2 or newer + libpcre0-4.5 or newer + openssl-0.9.7d or newer + zlib-1.2.1 or newer + +Build requirements: + cygwin-1.5.10 or newer + gcc-3.3.1-3 or newer + binutils-20030901-1 or newer + crypt + openssl-devel + openssl + openldap + openldap-devel + zlib + bzip2 + +Canonical homepage: + http://jan.kneschke.de/projects/lighttpd/ + +Canonical download: + http://jan.kneschke.de/projects/lighttpd/download + +------------------------------------ + +Build instructions: + unpack lighttpd-1.4.13-<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.13-<REL>.sh all + +This will create: + /usr/src/lighttpd-1.4.13-<REL>.tar.bz2 + /usr/src/lighttpd-1.4.13-<REL>-src.tar.bz2 + +Or use './lighttpd-1.4.13-<REL>.sh prep' to get a patched source directory + +------------------------------------------- + +Files included in the binary distribution: + + /etc/lighttpd/lighttpd.conf.default + /usr/lib/cyglightcomp.dll + /usr/lib/lighttpd/mod_access.dll + /usr/lib/lighttpd/mod_accesslog.dll + /usr/lib/lighttpd/mod_auth.dll + /usr/lib/lighttpd/mod_cgi.dll + /usr/lib/lighttpd/mod_compress.dll + /usr/lib/lighttpd/mod_evhost.dll + /usr/lib/lighttpd/mod_expire.dll + /usr/lib/lighttpd/mod_fastcgi.dll + /usr/lib/lighttpd/mod_httptls.dll + /usr/lib/lighttpd/mod_maps.dll + /usr/lib/lighttpd/mod_proxy.dll + /usr/lib/lighttpd/mod_redirect.dll + /usr/lib/lighttpd/mod_rewrite.dll + /usr/lib/lighttpd/mod_rrdtool.dll + /usr/lib/lighttpd/mod_secdownload.dll + /usr/lib/lighttpd/mod_simple_vhost.dll + /usr/lib/lighttpd/mod_ssi.dll + /usr/lib/lighttpd/mod_status.dll + /usr/lib/lighttpd/mod_usertrack.dll + /usr/sbin/lighttpd.exe + /usr/share/doc/Cygwin/lighttpd-1.3.0.README + /usr/share/doc/lighttpd-1.3.0/accesslog.txt + /usr/share/doc/lighttpd-1.3.0/authentification.txt + /usr/share/doc/lighttpd-1.3.0/AUTHORS + /usr/share/doc/lighttpd-1.3.0/cgi.txt + /usr/share/doc/lighttpd-1.3.0/ChangeLog + /usr/share/doc/lighttpd-1.3.0/compress.txt + /usr/share/doc/lighttpd-1.3.0/configuration.txt + /usr/share/doc/lighttpd-1.3.0/COPYING + /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt + /usr/share/doc/lighttpd-1.3.0/fastcgi.txt + /usr/share/doc/lighttpd-1.3.0/features.txt + /usr/share/doc/lighttpd-1.3.0/INSTALL + /usr/share/doc/lighttpd-1.3.0/NEWS + /usr/share/doc/lighttpd-1.3.0/performance.txt + /usr/share/doc/lighttpd-1.3.0/plugins.txt + /usr/share/doc/lighttpd-1.3.0/proxy.txt + /usr/share/doc/lighttpd-1.3.0/README + /usr/share/doc/lighttpd-1.3.0/redirect.txt + /usr/share/doc/lighttpd-1.3.0/rewrite.txt + /usr/share/doc/lighttpd-1.3.0/rrdtool.txt + /usr/share/doc/lighttpd-1.3.0/secdownload.txt + /usr/share/doc/lighttpd-1.3.0/security.txt + /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt + /usr/share/doc/lighttpd-1.3.0/skeleton.txt + /usr/share/doc/lighttpd-1.3.0/ssi.txt + /usr/share/doc/lighttpd-1.3.0/state.txt + /usr/share/man/man1/lighttpd.1.gz + +------------------ + +Port Notes: + +---------- lighttpd-1.3.1-1 ----------- + +Updated to 1.3.1 + +---------- lighttpd-1.3.0-1 ----------- +Initial release + +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de> +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com> + diff --git a/cygwin/lighttpd.README.in b/cygwin/lighttpd.README.in index 2b45546..d4910e4 100644 --- a/cygwin/lighttpd.README.in +++ b/cygwin/lighttpd.README.in @@ -1,114 +1,114 @@ -lighttpd
-------------------------------------------
-A fast, secure and flexible webserver
-
-Runtime requirements:
- cygwin-1.5.10 or newer
- crypt-1.1 or newer
- libbz2_1-1.0.2 or newer
- libpcre0-4.5 or newer
- openssl-0.9.7d or newer
- zlib-1.2.1 or newer
-
-Build requirements:
- cygwin-1.5.10 or newer
- gcc-3.3.1-3 or newer
- binutils-20030901-1 or newer
- crypt
- openssl-devel
- openssl
- openldap
- openldap-devel
- zlib
- bzip2
-
-Canonical homepage:
- http://jan.kneschke.de/projects/lighttpd/
-
-Canonical download:
- http://jan.kneschke.de/projects/lighttpd/download
-
-------------------------------------
-
-Build instructions:
- unpack lighttpd-@VERSION@-<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-@VERSION@-<REL>.sh all
-
-This will create:
- /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
- /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
-
-Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
-
--------------------------------------------
-
-Files included in the binary distribution:
-
- /etc/lighttpd/lighttpd.conf.default
- /usr/lib/cyglightcomp.dll
- /usr/lib/lighttpd/mod_access.dll
- /usr/lib/lighttpd/mod_accesslog.dll
- /usr/lib/lighttpd/mod_auth.dll
- /usr/lib/lighttpd/mod_cgi.dll
- /usr/lib/lighttpd/mod_compress.dll
- /usr/lib/lighttpd/mod_evhost.dll
- /usr/lib/lighttpd/mod_expire.dll
- /usr/lib/lighttpd/mod_fastcgi.dll
- /usr/lib/lighttpd/mod_httptls.dll
- /usr/lib/lighttpd/mod_maps.dll
- /usr/lib/lighttpd/mod_proxy.dll
- /usr/lib/lighttpd/mod_redirect.dll
- /usr/lib/lighttpd/mod_rewrite.dll
- /usr/lib/lighttpd/mod_rrdtool.dll
- /usr/lib/lighttpd/mod_secdownload.dll
- /usr/lib/lighttpd/mod_simple_vhost.dll
- /usr/lib/lighttpd/mod_ssi.dll
- /usr/lib/lighttpd/mod_status.dll
- /usr/lib/lighttpd/mod_usertrack.dll
- /usr/sbin/lighttpd.exe
- /usr/share/doc/Cygwin/lighttpd-1.3.0.README
- /usr/share/doc/lighttpd-1.3.0/accesslog.txt
- /usr/share/doc/lighttpd-1.3.0/authentification.txt
- /usr/share/doc/lighttpd-1.3.0/AUTHORS
- /usr/share/doc/lighttpd-1.3.0/cgi.txt
- /usr/share/doc/lighttpd-1.3.0/ChangeLog
- /usr/share/doc/lighttpd-1.3.0/compress.txt
- /usr/share/doc/lighttpd-1.3.0/configuration.txt
- /usr/share/doc/lighttpd-1.3.0/COPYING
- /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
- /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
- /usr/share/doc/lighttpd-1.3.0/features.txt
- /usr/share/doc/lighttpd-1.3.0/INSTALL
- /usr/share/doc/lighttpd-1.3.0/NEWS
- /usr/share/doc/lighttpd-1.3.0/performance.txt
- /usr/share/doc/lighttpd-1.3.0/plugins.txt
- /usr/share/doc/lighttpd-1.3.0/proxy.txt
- /usr/share/doc/lighttpd-1.3.0/README
- /usr/share/doc/lighttpd-1.3.0/redirect.txt
- /usr/share/doc/lighttpd-1.3.0/rewrite.txt
- /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
- /usr/share/doc/lighttpd-1.3.0/secdownload.txt
- /usr/share/doc/lighttpd-1.3.0/security.txt
- /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
- /usr/share/doc/lighttpd-1.3.0/skeleton.txt
- /usr/share/doc/lighttpd-1.3.0/ssi.txt
- /usr/share/doc/lighttpd-1.3.0/state.txt
- /usr/share/man/man1/lighttpd.1.gz
-
-------------------
-
-Port Notes:
-
----------- lighttpd-1.3.1-1 -----------
-
-Updated to 1.3.1
-
----------- lighttpd-1.3.0-1 -----------
-Initial release
-
-Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
-Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
-
+lighttpd +------------------------------------------ +A fast, secure and flexible webserver + +Runtime requirements: + cygwin-1.5.10 or newer + crypt-1.1 or newer + libbz2_1-1.0.2 or newer + libpcre0-4.5 or newer + openssl-0.9.7d or newer + zlib-1.2.1 or newer + +Build requirements: + cygwin-1.5.10 or newer + gcc-3.3.1-3 or newer + binutils-20030901-1 or newer + crypt + openssl-devel + openssl + openldap + openldap-devel + zlib + bzip2 + +Canonical homepage: + http://jan.kneschke.de/projects/lighttpd/ + +Canonical download: + http://jan.kneschke.de/projects/lighttpd/download + +------------------------------------ + +Build instructions: + unpack lighttpd-@VERSION@-<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-@VERSION@-<REL>.sh all + +This will create: + /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2 + /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2 + +Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory + +------------------------------------------- + +Files included in the binary distribution: + + /etc/lighttpd/lighttpd.conf.default + /usr/lib/cyglightcomp.dll + /usr/lib/lighttpd/mod_access.dll + /usr/lib/lighttpd/mod_accesslog.dll + /usr/lib/lighttpd/mod_auth.dll + /usr/lib/lighttpd/mod_cgi.dll + /usr/lib/lighttpd/mod_compress.dll + /usr/lib/lighttpd/mod_evhost.dll + /usr/lib/lighttpd/mod_expire.dll + /usr/lib/lighttpd/mod_fastcgi.dll + /usr/lib/lighttpd/mod_httptls.dll + /usr/lib/lighttpd/mod_maps.dll + /usr/lib/lighttpd/mod_proxy.dll + /usr/lib/lighttpd/mod_redirect.dll + /usr/lib/lighttpd/mod_rewrite.dll + /usr/lib/lighttpd/mod_rrdtool.dll + /usr/lib/lighttpd/mod_secdownload.dll + /usr/lib/lighttpd/mod_simple_vhost.dll + /usr/lib/lighttpd/mod_ssi.dll + /usr/lib/lighttpd/mod_status.dll + /usr/lib/lighttpd/mod_usertrack.dll + /usr/sbin/lighttpd.exe + /usr/share/doc/Cygwin/lighttpd-1.3.0.README + /usr/share/doc/lighttpd-1.3.0/accesslog.txt + /usr/share/doc/lighttpd-1.3.0/authentification.txt + /usr/share/doc/lighttpd-1.3.0/AUTHORS + /usr/share/doc/lighttpd-1.3.0/cgi.txt + /usr/share/doc/lighttpd-1.3.0/ChangeLog + /usr/share/doc/lighttpd-1.3.0/compress.txt + /usr/share/doc/lighttpd-1.3.0/configuration.txt + /usr/share/doc/lighttpd-1.3.0/COPYING + /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt + /usr/share/doc/lighttpd-1.3.0/fastcgi.txt + /usr/share/doc/lighttpd-1.3.0/features.txt + /usr/share/doc/lighttpd-1.3.0/INSTALL + /usr/share/doc/lighttpd-1.3.0/NEWS + /usr/share/doc/lighttpd-1.3.0/performance.txt + /usr/share/doc/lighttpd-1.3.0/plugins.txt + /usr/share/doc/lighttpd-1.3.0/proxy.txt + /usr/share/doc/lighttpd-1.3.0/README + /usr/share/doc/lighttpd-1.3.0/redirect.txt + /usr/share/doc/lighttpd-1.3.0/rewrite.txt + /usr/share/doc/lighttpd-1.3.0/rrdtool.txt + /usr/share/doc/lighttpd-1.3.0/secdownload.txt + /usr/share/doc/lighttpd-1.3.0/security.txt + /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt + /usr/share/doc/lighttpd-1.3.0/skeleton.txt + /usr/share/doc/lighttpd-1.3.0/ssi.txt + /usr/share/doc/lighttpd-1.3.0/state.txt + /usr/share/man/man1/lighttpd.1.gz + +------------------ + +Port Notes: + +---------- lighttpd-1.3.1-1 ----------- + +Updated to 1.3.1 + +---------- lighttpd-1.3.0-1 ----------- +Initial release + +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de> +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com> + diff --git a/distribute.sh.in b/distribute.sh.in index e0b63a3..a85fcec 100644 --- a/distribute.sh.in +++ b/distribute.sh.in @@ -3,7 +3,7 @@ PACKAGE=@PACKAGE_TARNAME@ VERSION=@VERSION@ NAME=@PACKAGE_TARNAME@-@VERSION@ -DISTDIR="/home/jan/wwwroot/servers/www.lighttpd.net/pages/download/" +DISTDIR="/home/jan/wwwroot/servers/www.lighttpd.net/pages/download/" RPMS="/home/jan/rpmbuild/RPMS/i386/${NAME}-1.i386.rpm \ /home/jan/rpmbuild/SRPMS/${NAME}-1.src.rpm" FILES="${RPMS} ${NAME}.tar.gz \ @@ -21,7 +21,7 @@ esac echo ${nopack} if test x${pack} = x1; then - make distcheck && rpmbuild -ta --nodeps ${NAME}.tar.gz + make distcheck && rpmbuild -ta --nodeps ${NAME}.tar.gz gpg --detach-sign ${NAME}.tar.gz rpm --addsign ${RPMS} fi @@ -49,7 +49,7 @@ Download MD5: ${MD5SRPM} - ${NAME}.tar.gz ${DLNAME}.tar.gz - MD5: ${MD5TGZ} + MD5: ${MD5TGZ} Signature: ${DLNAME}.tar.gz.sig EOF @@ -67,7 +67,7 @@ Checksums - ${NAME}-1.src.rpm MD5: ${MD5SRPM} - ${NAME}.tar.gz - MD5: ${MD5TGZ} + MD5: ${MD5TGZ} EOF diff --git a/doc/Makefile.am b/doc/Makefile.am index 47ca576..792ff22 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -35,7 +35,8 @@ trigger_b4_dl.txt \ webdav.txt \ expire.txt \ dirlisting.txt \ -evhost.txt +evhost.txt \ +magnet.txt HTMLDOCS=accesslog.html \ authentication.html \ @@ -71,7 +72,8 @@ HTMLDOCS=accesslog.html \ webdav.html \ expire.html \ dirlisting.html \ - evhost.html + evhost.html \ + magnet.html EXTRA_DIST=lighttpd.conf lighttpd.user \ rc.lighttpd rc.lighttpd.redhat sysconfig.lighttpd \ @@ -81,7 +83,7 @@ EXTRA_DIST=lighttpd.conf lighttpd.user \ newstyle.css \ oldstyle.css \ $(DOCS) - + %.html: %.txt rst2html $^ > $@ @@ -90,11 +92,11 @@ html: $(HTMLDOCS) #%.ps.gz: %.ps # gzip $^ - + #%.ps: %.dot -# dot -Tps -o $@ $^ +# dot -Tps -o $@ $^ clean-local: rm -f *.html - + diff --git a/doc/Makefile.in b/doc/Makefile.in index b133b09..e177fed 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -105,7 +105,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -138,6 +137,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ @@ -225,7 +225,8 @@ trigger_b4_dl.txt \ webdav.txt \ expire.txt \ dirlisting.txt \ -evhost.txt +evhost.txt \ +magnet.txt HTMLDOCS = accesslog.html \ authentication.html \ @@ -261,7 +262,8 @@ HTMLDOCS = accesslog.html \ webdav.html \ expire.html \ dirlisting.html \ - evhost.html + evhost.html \ + magnet.html EXTRA_DIST = lighttpd.conf lighttpd.user \ rc.lighttpd rc.lighttpd.redhat sysconfig.lighttpd \ @@ -491,7 +493,7 @@ html: $(HTMLDOCS) # gzip $^ #%.ps: %.dot -# dot -Tps -o $@ $^ +# dot -Tps -o $@ $^ clean-local: rm -f *.html diff --git a/doc/access.txt b/doc/access.txt index acfdcb7..042da01 100644 --- a/doc/access.txt +++ b/doc/access.txt @@ -12,10 +12,10 @@ Module: mod_access :abstract: The access module is used to deny access to files with given trailing path names. - + .. meta:: :keywords: lighttpd, trailing path access control - + .. contents:: Table of Contents Description @@ -32,7 +32,7 @@ url.access-deny Default: empty Example: :: - + url.access-deny = ( "~", ".inc") will deny access to all files ended with a diacritical mark (~) or .inc diff --git a/doc/accesslog.txt b/doc/accesslog.txt index 36584cf..889a4da 100644 --- a/doc/accesslog.txt +++ b/doc/accesslog.txt @@ -11,11 +11,11 @@ Module: mod_accesslog :Revision: $Revision: 1.2 $ :abstract: - The accesslog module ... - + The accesslog module ... + .. meta:: :keywords: lighttpd, accesslog, CLF - + .. contents:: Table of Contents Description @@ -28,30 +28,30 @@ Options accesslog.use-syslog send the accesslog to syslog - + Default: disabled accesslog.filename name of the file where the accesslog should be written too if syslog is not used. - + if the name starts with a '|' the rest of the name is taken as the name of a process which will be spawn and will get the output - + e.g.: :: - + accesslog.filename = "/var/log/lighttpd.log" - + $HTTP["host"] == "mail.example.org" { accesslog.filename = "|/usr/bin/cronolog" } - + Default: disabled accesslog.format the format of the logfile - + ====== ================================ Option Description ====== ================================ @@ -60,8 +60,8 @@ accesslog.format %l ident name (not supported) %u authenticated user %t timestamp for the request-start - %r request-line - %s status code + %r request-line + %s status code %b bytes sent for the body %i HTTP-header field %a remote address @@ -86,16 +86,16 @@ accesslog.format %I bytes incomming %O bytes outgoing ====== ================================ - + If %s is written %>s or %<s the < and the > are ignored. They are support - for compat with apache. - + for compat with apache. + %i and %o expect the name of the field which should be written in curly brackets. - + e.g.: :: - + accesslog.format = "%h %l %u %t \"%r\" %b %>s \"%{User-Agent}i\" \"%{Referer}i\"" - + Default: CLF compatible output Response Header @@ -109,18 +109,18 @@ If you want to log it into the accesslog just specify the field-name within a %{...}o like :: accesslog.format = "%h %l %u %t \"%r\" %b %>s \"%{User-Agent}i\" \"%{Referer}i\" \"%{X-LIGHTTPD-SID}o\"" - + The prefix ``X-LIGHTTPD-`` is special as every response header starting with this prefix is assumed to be special for lighttpd and won't be sent out -to the client. +to the client. An example the use this functionality is provided below: :: <?php - + session_start(); - + header("X-LIGHTTPD-SID: ".session_id()); - + ?> diff --git a/doc/alias.txt b/doc/alias.txt index 15012e3..1315f93 100644 --- a/doc/alias.txt +++ b/doc/alias.txt @@ -11,11 +11,11 @@ Module: mod_alias :Revision: $Revision: 1.1 $ :abstract: - The alias module ... - + The alias module ... + .. meta:: :keywords: lighttpd, alias - + .. contents:: Table of Contents Description @@ -32,5 +32,5 @@ alias.url Default: empty Example: :: - + alias.url = ( "/cgi-bin/" => "/var/www/servers/www.example.org/cgi-bin/" ) diff --git a/doc/authentication.txt b/doc/authentication.txt index 2a11f64..c375ece 100644 --- a/doc/authentication.txt +++ b/doc/authentication.txt @@ -7,15 +7,15 @@ Module: mod_auth ---------------- :Author: Jan Kneschke -:Date: $Date: 2006-01-12 19:34:26 +0100 (Thu, 12 Jan 2006) $ -:Revision: $Revision: 940 $ +:Date: $Date: 2006-10-04 15:26:23 +0200 (Wed, 04 Oct 2006) $ +:Revision: $Revision: 1371 $ :abstract: The auth module provides ... - + .. meta:: :keywords: lighttpd, authentication - + .. contents:: Table of Contents Description @@ -24,85 +24,85 @@ Description Supported Methods ----------------- -lighttpd supportes both authentication method described by -RFC 2617: +lighttpd supportes both authentication method described by +RFC 2617: basic ````` -The Basic method transfers the username and the password in -cleartext over the network (base64 encoded) and might result -in security problems if not used in conjunction with a crypted +The Basic method transfers the username and the password in +cleartext over the network (base64 encoded) and might result +in security problems if not used in conjunction with a crypted channel between client and server. digest `````` -The Digest method only transfers a hashed value over the -network which performs a lot of work to harden the +The Digest method only transfers a hashed value over the +network which performs a lot of work to harden the authentication process in insecure networks. Backends -------- -Depending on the method lighttpd provides various way to store +Depending on the method lighttpd provides various way to store the credentials used for the authentication. for basic auth: - plain_ -- htpasswd_ +- htpasswd_ - htdigest_ - ldap_ - + for digest auth: - plain_ - htdigest_ - + plain ````` -A file which contains username and the cleartext password -seperated by a colon. Each entry is terminated by a single +A file which contains username and the cleartext password +seperated by a colon. Each entry is terminated by a single newline.:: e.g.: agent007:secret - + htpasswd ```````` -A file which contains username and the crypt()'ed password -seperated by a colon. Each entry is terminated by a single +A file which contains username and the crypt()'ed password +seperated by a colon. Each entry is terminated by a single newline. :: e.g.: agent007:XWY5JwrAVBXsQ -You can use htpasswd from the apache distribution to manage +You can use htpasswd from the apache distribution to manage those files. :: - + $ htpasswd lighttpd.user.htpasswd agent007 - - + + htdigest ```````` -A file which contains username, realm and the md5()'ed -password seperated by a colon. Each entry is terminated +A file which contains username, realm and the md5()'ed +password seperated by a colon. Each entry is terminated by a single newline. :: - + e.g.: agent007:download area:8364d0044ef57b3defcfa141e8f77b65 - -You can use htdigest from the apache distribution to manage + +You can use htdigest from the apache distribution to manage those files. :: $ htdigest lighttpd.user.htdigest 'download area' agent007 - + Using md5sum can also generate the password-hash: :: #!/bin/sh @@ -118,21 +118,21 @@ To use it: $ htdigest.sh 'agent007' 'download area' 'secret' agent007:download area:8364d0044ef57b3defcfa141e8f77b65 - - - + + + ldap ```` -the ldap backend is basically performing the following steps +the ldap backend is basically performing the following steps to authenticate a user - + 1. connect anonymously (at plugin init) 2. get DN for filter = username 3. auth against ldap server 4. disconnect - -if all 4 steps are performed without any error the user is + +if all 4 steps are performed without any error the user is authenticated Configuration @@ -143,28 +143,28 @@ Configuration ## debugging # 0 for off, 1 for 'auth-ok' messages, 2 for verbose debugging auth.debug = 0 - - ## type of backend + + ## type of backend # plain, htpasswd, ldap or htdigest auth.backend = "htpasswd" - # filename of the password storage for + # filename of the password storage for # plain auth.backend.plain.userfile = "lighttpd-plain.user" - + ## for htpasswd auth.backend.htpasswd.userfile = "lighttpd-htpasswd.user" - + ## for htdigest auth.backend.htdigest.userfile = "lighttpd-htdigest.user" ## for ldap - # the $ in auth.backend.ldap.filter is replaced by the + # the $ in auth.backend.ldap.filter is replaced by the # 'username' from the login dialog auth.backend.ldap.hostname = "localhost" auth.backend.ldap.base-dn = "dc=my-domain,dc=com" auth.backend.ldap.filter = "(uid=$)" - # if enabled, startTLS needs a valid (base64-encoded) CA + # if enabled, startTLS needs a valid (base64-encoded) CA # certificate auth.backend.ldap.starttls = "enable" auth.backend.ldap.ca-file = "/etc/CAcertificate.pem" @@ -178,20 +178,20 @@ Configuration # "require" => "user=<username>" ) # ) # - # <realm> is a string to display in the dialog - # presented to the user and is also used for the - # digest-algorithm and has to match the realm in the + # <realm> is a string to display in the dialog + # presented to the user and is also used for the + # digest-algorithm and has to match the realm in the # htdigest file (if used) # - auth.require = ( "/download/" => - ( + auth.require = ( "/download/" => + ( "method" => "digest", "realm" => "download archiv", "require" => "user=agent007|user=agent008" ), - "/server-info" => - ( + "/server-info" => + ( "method" => "digest", "realm" => "download archiv", "require" => "valid-user" @@ -201,7 +201,7 @@ Configuration Limitations ============ -- The implementation of digest method is currently not +- The implementation of digest method is currently not completely compliant with the standard as it still allows a replay attack. diff --git a/doc/cgi.txt b/doc/cgi.txt index 081d795..95d187c 100644 --- a/doc/cgi.txt +++ b/doc/cgi.txt @@ -12,10 +12,10 @@ Module: mod_cgi :abstract: The cgi module provides a CGI-conforming interface. - + .. meta:: :keywords: lighttpd, cgi - + .. contents:: Table of Contents Description @@ -32,7 +32,7 @@ cgi.assign file-extensions that are handled by a CGI program e.g.: :: - + cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl" ) @@ -43,7 +43,7 @@ To setup a executable which doesn't need the help of a external program you just don't specify a handler for the extension. :: cgi.assign = ( ".sh" => "" ) - + If the file has no extension keep in mind that lighttpd matches not the extension itself but the right part of the URL: :: diff --git a/doc/cml.txt b/doc/cml.txt index ae69067..10fac70 100644 --- a/doc/cml.txt +++ b/doc/cml.txt @@ -12,10 +12,10 @@ Module: mod_cml :abstract: CML is a Meta language to describe the dependencies of a page at one side and building a page from its fragments on the other side using LUA. - + .. meta:: :keywords: lighttpd, cml, lua - + .. contents:: Table of Contents Description @@ -31,7 +31,7 @@ CML (Cache Meta Language) wants to solves several problems: Cache Decision -------------- -A simple example should show how to a content caching the very simple way in PHP. +A simple example should show how to a content caching the very simple way in PHP. jan.kneschke.de has a very simple design: @@ -39,7 +39,7 @@ jan.kneschke.de has a very simple design: * the menu is generated from a menu.csv file * the content is coming from files on the local directory named content-1, content-2 and so on -The page content is static as long non of the those tree items changes. A change in the layout +The page content is static as long non of the those tree items changes. A change in the layout is affecting all pages, a change of menu.csv too, a change of content-x file only affects the cached page itself. @@ -58,7 +58,7 @@ If we model this in PHP we get: :: } foreach($content as $k => $v) { - if (isset($v["file"]) && + if (isset($v["file"]) && filemtime($v["file"]) > $cachemtime) { return 0; } @@ -71,7 +71,7 @@ If we model this in PHP we get: :: return 0; } } - + if (is_cachable(...), $cachefile) { readfile($cachefile); exit(); @@ -81,7 +81,7 @@ If we model this in PHP we get: :: ?> Quite simple. No magic involved. If the one of the files is new than the cached -content, the content is dirty and has to be regenerated. +content, the content is dirty and has to be regenerated. Now let take a look at the numbers: @@ -92,9 +92,9 @@ As you can see the increase is not as good as it could be. The main reason as th of the PHP interpreter to start up (a byte-code cache has been used here). Moving these decisions out of the PHP script into a server module will remove the need -to start PHP for a cache-hit. +to start PHP for a cache-hit. -To transform this example into a CML you need 'index.cml' in the list of indexfiles +To transform this example into a CML you need 'index.cml' in the list of indexfiles and the following index.cml file: :: output_contenttype = "text/html" @@ -110,7 +110,7 @@ and the following index.cml file: :: file_mtime(b .. "templates/jk.tmpl") > file_mtime(cwd .. "_cache.html") or file_mtime(b .. "content.html") > file_mtime(cwd .. "_cache.html") then return CACHE_MISS - else + else return CACHE_HIT end @@ -132,26 +132,26 @@ Sometimes the different fragment are already generated externally. You have to c readfile("spacer2.html"); readfile("news.html"); readfile("footer.html"); - ?> + ?> -We we can do the same several times faster directly in the webserver. +We we can do the same several times faster directly in the webserver. Don't forget: Webserver are built to send out static content, that is what they can do best. The index.cml for this looks like: :: output_contenttype = "text/html" - + cwd = request["CWD"] - - output_include = { cwd .. "head.html", + + output_include = { cwd .. "head.html", cwd .. "menu.html", cwd .. "spacer.html", cwd .. "db-content.html", cwd .. "spacer2.html", cwd .. "news.html", cwd .. "footer.html" } - + return CACHE_HIT Now we get about 10000 req/s instead of 600 req/s. @@ -161,7 +161,7 @@ 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. +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: @@ -183,7 +183,7 @@ and create /home/www/power-magnet.cml with: :: 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. +instead of handling the usual request. Another example, create thumbnail for requested image and serve it instead of sending the big image: :: @@ -196,7 +196,7 @@ of sending the big image: :: dr = request["DOCUMENT_ROOT"] sn = request["SCRIPT_NAME"] - ## to be continued :) ... + ## to be continued :) ... trigger_handler = '/gen_image.php' @@ -217,7 +217,7 @@ To use the plugin you have to load it: :: Options ======= -:cml.extension: +:cml.extension: the file extension that is bound to the cml-module :cml.memcache-hosts: hosts for the memcache.* functions @@ -229,7 +229,7 @@ Options Language ======== -The language used for CML is provided by `LUA <http://www.lua.org/>`_. +The language used for CML is provided by `LUA <http://www.lua.org/>`_. Additionally to the functions provided by lua mod_cml provides: :: @@ -252,10 +252,10 @@ Additionally to the functions provided by lua mod_cml provides: :: number file_mtime(string) string memcache_get_string(string) number memcache_get_long(string) - boolean memcache_exists(string) + boolean memcache_exists(string) -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 +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/compress.txt b/doc/compress.txt index 7b083e9..a739c42 100644 --- a/doc/compress.txt +++ b/doc/compress.txt @@ -12,17 +12,17 @@ Module: mod_compress :abstract: a nice, short abstrace about the module - + .. meta:: :keywords: lighttpd, compress - + .. contents:: Table of Contents Description =========== Output compression reduces the network load and can improve the overall -throughput of the webserver. +throughput of the webserver. Only static content is supported up to now. @@ -36,21 +36,21 @@ compress.cache-dir name of the directory where compressed content will be cached e.g.: :: - + compress.cache-dir = "/var/www/cache/" - + # even better with virt-hosting $HTTP["host"] == "docs.example.org" { compress.cache-dir = "/var/www/cache/docs.example.org/" } - + Default: not set, compress the file for every request compress.filetype mimetypes where might get compressed - + e.g.: :: - + compress.filetype = ("text/plain", "text/html") Default: not set @@ -62,5 +62,5 @@ Compressing Dynamic Content To compress dynamic content with PHP please enable :: zlib.output_compression = 1 - + in the php.ini as PHP provides compression support by itself. diff --git a/doc/configuration.txt b/doc/configuration.txt index 2b60e58..416329b 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -7,15 +7,15 @@ Module: core ------------ :Author: Jan Kneschke -:Date: $Date: 2006-03-09 01:10:40 +0100 (Thu, 09 Mar 2006) $ -:Revision: $Revision: 1034 $ +:Date: $Date: 2006-10-04 15:26:23 +0200 (Wed, 04 Oct 2006) $ +:Revision: $Revision: 1371 $ :abstract: the layout of the configuration file - + .. meta:: :keywords: lighttpd, configuration - + .. contents:: Table of Contents Description @@ -36,21 +36,21 @@ A BNF like notation: :: <array> : "(" [ <string> "=>" ] <value> [, [ <string> "=>" ] <value> ]* ")" INCLUDE : "include" VALUE INCLUDE_SHELL : "include_shell" STRING_VALUE - + Example ------- :: - + # default document-root server.document-root = "/var/www/example.org/pages/" - + # TCP port server.port = 80 - + # selecting modules server.modules = ( "mod_access", "mod_rewrite" ) - + # variables, computed when config is read. var.mymodule = "foo" server.modules += ( "mod_" + var.mymodule ) @@ -125,22 +125,22 @@ Example $HTTP["url"] =~ "^/download/" { dir-listing.activate = "disable" } - + # handish virtual hosting # 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/" } - + # multiple sockets $SERVER["socket"] == "127.0.0.1:81" { server.document-root = "..." } - + $SERVER["socket"] == "127.0.0.1:443" { ssl.pemfile = "/var/www/certs/localhost.pem" ssl.engine = "enable" - + server.document-root = "/var/www/htdocs/secure.example.org/pages/" } @@ -148,19 +148,19 @@ Example $HTTP["useragent"] =~ "Google" { url.access-deny = ( "" ) } - + # deny access for all image stealers $HTTP["referer"] !~ "^($|http://www\.example\.org)" { url.access-deny = ( ".jpg", ".jpeg", ".png" ) } - # deny the access to www.example.org to all user which + # deny the access to www.example.org to all user which # are not in the 10.0.0.0/8 network $HTTP["host"] == "www.example.org" { $HTTP["remoteip"] != "10.0.0.0/8" { url.access-deny = ( "" ) } - } + } Using variables =============== @@ -177,7 +177,7 @@ You can set your own variables in the configuration to simplify your config. in incl-base.conf: server.document-root = basedir + server.name + "/pages/" accesslog.filename = basedir + server.name + "/logs/access.log" - + You can also use environement variables or the default variables var.PID and var.CWD: :: @@ -248,11 +248,11 @@ server.document-root might have specified with one of the above conditionals. Default: no default, required - + server.bind IP address, hostname or absolute path to the unix-domain socket the server listen on. - + Default: bind to all interfaces Example: :: @@ -260,14 +260,14 @@ server.bind 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 - + .. note:: port belows 1024 require root-permissions - + Default: 80 (443 if ssl is enabled) - + server.use-ipv6 bind to the IPv6 socket @@ -275,42 +275,42 @@ server.tag set the string returned by the Server: response header Default: lighttpd <current-version> - + server.errorlog pathname of the error-log - + Default: either STDERR or ``server.errorlog-use-syslog`` - + server.errorlog-use-syslog send errorlog to syslog - + Default: disabled - + server.chroot root-directory of the server - + NOTE: requires root-permissions - + server.username username used to run the server - + NOTE: requires root-permissions server.groupname groupname used to run the server - + NOTE: requires root-permissions server.follow-symlink allow to follow-symlinks - + Default: enabled index-file.names list of files to search for if a directory is requested e.g.: :: - index-file.names = ( "index.php", "index.html", + index-file.names = ( "index.php", "index.html", "index.htm", "default.htm" ) if a name starts with slash this file will be used a index generator @@ -318,17 +318,17 @@ index-file.names server.modules modules to load - + .. note:: the order of the modules is important. The modules are executed in the order as they are specified. Loading mod_auth AFTER mod_fastcgi might disable authentication for fastcgi - backends (if check-local is disabled). + backends (if check-local is disabled). - As auth should be done first, move it before all executing modules (like + As auth should be done first, move it before all executing modules (like proxy, fastcgi, scgi and cgi). - rewrites, redirects and access should be first, followed by auth and + rewrites, redirects and access should be first, followed by auth and the docroot plugins. Afterwards the external handlers like fastcgi, cgi, scgi and proxy and @@ -336,12 +336,12 @@ server.modules e.g.: :: - server.modules = ( "mod_rewrite", - "mod_redirect", + server.modules = ( "mod_rewrite", + "mod_redirect", "mod_alias", - "mod_access", - "mod_auth", - "mod_status", + "mod_access", + "mod_auth", + "mod_status", "mod_simple_vhost", "mod_evhost", "mod_userdir", @@ -363,74 +363,74 @@ server.modules - mod_staticfile server.event-handler - set the event handler - + set the event handler + Default: "poll" server.pid-file - set the name of the .pid-file where the PID of the server should be placed. + 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 daemon mode - + Default: not set - + server.max-request-size maximum size in kbytes of the request (header + body). Only applies to POST requests. - + Default: 2097152 (2GB) server.max-worker 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 - + server.name name of the server/virtual server - + Default: hostname server.max-keep-alive-requests - maximum number of request within a keep-alive session before the server + maximum number of request within a keep-alive session before the server terminates the connection - + Default: 128 server.max-keep-alive-idle maximum number of seconds until a idling keep-alive connection is droped - + Default: 30 server.max-read-idle - maximum number of seconds until a waiting, non keep-alive read times out + maximum number of seconds until a waiting, non keep-alive read times out and closes the connection - + Default: 60 server.max-write-idle maximum number of seconds until a waiting write call times out and closes the connection - + Default: 360 server.error-handler-404 uri to call if the requested file results in a 404 Default: not set - + Example: :: - + server.error-handler-404 = "/error-404.php" server.protocol-http11 defines if HTTP/1.1 is allowed or not. - + Default: enabled server.range-requests defines if range requests are allowed or not. - + Default: enabled @@ -445,9 +445,9 @@ debugging debug.dump-unknown-headers enables listing of internally unhandled HTTP-headers - + e.g. :: - + debug.dump-unknown-headers = "enable" mimetypes @@ -456,20 +456,20 @@ mimetypes mimetype.assign list of known mimetype mappings NOTE: if no mapping is given "application/octet-stream" is used - + e.g.: :: - - mimetype.assign = ( ".png" => "image/png", + + mimetype.assign = ( ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".html" => "text/html", ".txt" => "text/plain" ) - The list is compared top down and the first match is taken. This is + The list is compared top down and the first match is taken. This is important if you have matches like: :: ".tar.gz" => "application/x-tgz", - ".gz" => "application/x-gzip", + ".gz" => "application/x-gzip", If you want to set another default mimetype use: :: @@ -483,17 +483,17 @@ mimetype.use-xattr retrieve the "Content-Type" attribute on each file, and use that as the mime type. If it's not defined or not available, fall back to the mimetype.assign assignment. - + e.g.: :: - + mimetype.use-xattr = "enable" - + on shell use: - + $ attr -s Content-Type -V image/svg svgfile.svg - + or - + $ attr -s Content-Type -V text/html indexfile @@ -501,13 +501,13 @@ debugging ````````` debug.log-request-header - default: disabled - + default: disabled + debug.log-response-header - default: disabled + default: disabled debug.log-file-not-found - default: disabled + default: disabled debug.log-request-handling - default: disabled + default: disabled diff --git a/doc/dirlisting.txt b/doc/dirlisting.txt index ea65ba6..3b33752 100644 --- a/doc/dirlisting.txt +++ b/doc/dirlisting.txt @@ -13,10 +13,10 @@ Module: mod_dirlisting :abstract: mod_dirlisting generates HTML based directory listings with full CSS control - + .. meta:: :keywords: lighttpd, directory listings, dirlisting - + .. contents:: Table of Contents Description @@ -53,7 +53,7 @@ Options dir-listing.activate enables virtual directory listings if a directory is requested no - index-file was found + index-file was found Default: disabled @@ -78,5 +78,5 @@ dir-listing.encoding encoding) Example: :: - + dir-listing.encoding = "utf-8" diff --git a/doc/evhost.txt b/doc/evhost.txt index 9e79b03..441029c 100644 --- a/doc/evhost.txt +++ b/doc/evhost.txt @@ -12,10 +12,10 @@ Module: mod_evhost :abstract: virtual hosting - + .. meta:: :keywords: lighttpd, virtual hosting - + .. contents:: Table of Contents Description @@ -23,10 +23,10 @@ Description mod_evhost builds the document-root based on a pattern which contains wildcards. Those wildcards can represent parts if the submitted hostname - + :: - + %% => % sign %0 => domain name + tld %1 => tld @@ -39,7 +39,7 @@ wildcards. Those wildcards can represent parts if the submitted hostname Options ======= -evhost.path-pattern +evhost.path-pattern pattern with wildcards to be replace to build a documentroot - + diff --git a/doc/expire.txt b/doc/expire.txt index 2aee938..ca59c42 100644 --- a/doc/expire.txt +++ b/doc/expire.txt @@ -12,17 +12,17 @@ Module: mod_expire :abstract: mod_expire controls the setting of the the Expire Response header - + .. meta:: :keywords: lighttpd, expire - + .. contents:: Table of Contents Description =========== mod_expire controls the Expire header in the Response Header of HTTP/1.0 -messages. It is usefull to set it for static files which should be cached +messages. It is usefull to set it for static files which should be cached aggressivly like images, stylesheets or similar. Options @@ -35,8 +35,8 @@ expire.url <access|modification> <number> <years|months|days|hours|minutes|seconds> following the syntax used by mod_expire in Apache 1.3.x and later. - + Example: :: - + expire.url = ( "/images/" => "access 1 hour" ) - + diff --git a/doc/fastcgi-state.txt b/doc/fastcgi-state.txt index 9e76a6f..a05d2c2 100644 --- a/doc/fastcgi-state.txt +++ b/doc/fastcgi-state.txt @@ -11,13 +11,13 @@ Module: fastcgi :Revision: $Revision: 1.1 $ :abstract: - This is a short summary of the state-engine which is driving the FastCGI + This is a short summary of the state-engine which is driving the FastCGI module. It describes the basic concepts and the way the different parts of the module are connected. - + .. meta:: :keywords: lighttpd, state-engine, fastcgi - + .. contents:: Table of Contents Description @@ -27,7 +27,7 @@ States ------ The state-engine is currently made of 6 states which are walk-through on -the way each connection. +the way each connection. :init: prepare fastcgi-connection @@ -41,7 +41,7 @@ the way each connection. read fastcgi-response from network and push it to the write-queue :close: terminate the connection - + .. image:: fastcgi-state.png Delays diff --git a/doc/fastcgi.txt b/doc/fastcgi.txt index a29cf48..fc46385 100644 --- a/doc/fastcgi.txt +++ b/doc/fastcgi.txt @@ -12,72 +12,72 @@ Module: mod_fastcgi :abstract: The FastCGI interface is the fastest and most secure way - to interface external process-handlers like Perl, PHP and - your self-written applications. - + to interface external process-handlers like Perl, PHP and + your self-written applications. + .. meta:: :keywords: lighttpd, FastCGI - + .. contents:: Table of Contents Description =========== -lighttpd provides an interface to a external programs that -support the FastCGI interface. The FastCGI Interface is -defined by http://www.fastcgi.com/ and is a +lighttpd provides an interface to a external programs that +support the FastCGI interface. The FastCGI Interface is +defined by http://www.fastcgi.com/ and is a platform-independent and server independent interface between a web-application and a webserver. -This means that FastCGI programs that run with the Apache +This means that FastCGI programs that run with the Apache Webserver will run seamlessly with lighttpd and vice versa. FastCGI ------- -FastCGI is removes a lot of the limitations of CGI programs. -CGI programs have the problem that they have to be restarted -by the webserver for every request which leads to really bad +FastCGI is removes a lot of the limitations of CGI programs. +CGI programs have the problem that they have to be restarted +by the webserver for every request which leads to really bad performance values. -FastCGI removes this limitation by keeping the process running -and handling the requests by this always running process. This -removes the time used for the fork() and the overall startup -and cleanup time which is necessary to create and destroy a +FastCGI removes this limitation by keeping the process running +and handling the requests by this always running process. This +removes the time used for the fork() and the overall startup +and cleanup time which is necessary to create and destroy a process. -While CGI programs communicate to the server over pipes, -FastCGI processes use Unix-Domain-Sockets or TCP/IP to talk -with the webserver. This gives you the second advantage over +While CGI programs communicate to the server over pipes, +FastCGI processes use Unix-Domain-Sockets or TCP/IP to talk +with the webserver. This gives you the second advantage over simple CGI programs: FastCGI don't have to run on the Webserver -itself but everywhere in the network. +itself but everywhere in the network. -lighttpd takes it a little bit further by providing a internal -FastCGI load-balancer which can be used to balance the load -over multiple FastCGI Servers. In contrast to other solutions -only the FastCGI process has to be on the cluster and not the +lighttpd takes it a little bit further by providing a internal +FastCGI load-balancer which can be used to balance the load +over multiple FastCGI Servers. In contrast to other solutions +only the FastCGI process has to be on the cluster and not the whole webserver. That gives the FastCGI process more resources than a e.g. load-balancer+apache+mod_php solution. -If you compare FastCGI against a apache+mod_php solution you -should note that FastCGI provides additional security as the -FastCGI process can be run under different permissions that -the webserver and can also live a chroot which might be -different than the one the webserver is running in. +If you compare FastCGI against a apache+mod_php solution you +should note that FastCGI provides additional security as the +FastCGI process can be run under different permissions that +the webserver and can also live a chroot which might be +different than the one the webserver is running in. Options ======= -lighttpd provides the FastCGI support via the fastcgi-module +lighttpd provides the FastCGI support via the fastcgi-module (mod_fastcgi) which provides 2 options in the config-file: fastcgi.debug - a value between 0 and 65535 to set the debug-level in the - FastCGI module. Currently only 0 and 1 are used. Use 1 to + a value between 0 and 65535 to set the debug-level in the + FastCGI module. Currently only 0 and 1 are used. Use 1 to enable some debug output, 0 to disable it. -fastcgi.map-extensions +fastcgi.map-extensions map multiple extensions to the same fastcgi server Example: :: @@ -85,23 +85,23 @@ fastcgi.map-extensions fastcgi.map-extensions = ( ".php3" => ".php" ) fastcgi.server - tell the module where to send FastCGI requests to. Every - file-extension can have it own handler. Load-Balancing is + tell the module where to send FastCGI requests to. Every + file-extension can have it own handler. Load-Balancing is done by specifying multiple handles for the same extension. - + structure of fastcgi.server section: :: - - ( <extension> => - ( + + ( <extension> => + ( ( "host" => <string> , "port" => <integer> , "socket" => <string>, # either socket # or host+port - "bin-path" => <string>, # OPTIONAL - "bin-environment" => <array>, # OPTIONAL - "bin-copy-environment" => <array>, # OPTIONAL + "bin-path" => <string>, # OPTIONAL + "bin-environment" => <array>, # OPTIONAL + "bin-copy-environment" => <array>, # OPTIONAL "mode" => <string>, # OPTIONAL - "docroot" => <string> , # OPTIONAL if "mode" + "docroot" => <string> , # OPTIONAL if "mode" # is not "authorizer" "check-local" => <string>, # OPTIONAL "min-procs" => <integer>, # OPTIONAL @@ -112,54 +112,54 @@ fastcgi.server "disable-time" => <integer>, # optional "allow-x-send-file" => <boolean> # optional ), - ( "host" => ... - ) + ( "host" => ... + ) ) ) - - :<extension>: is the file-extension or prefix + + :<extension>: is the file-extension or prefix (if started with "/") :"host": is hostname/ip of the FastCGI process :"port": is tcp-port on the "host" used by the FastCGI process - :"bin-path": path to the local FastCGI binary which should be + :"bin-path": path to the local FastCGI binary which should be started if no local FastCGI is running :"socket": path to the unix-domain socket - :"mode": is the FastCGI protocol mode. - Default is "responder", also "authorizer" + :"mode": is the FastCGI protocol mode. + Default is "responder", also "authorizer" mode is implemented. - :"docroot": is optional and is the docroot on the remote - host for default "responder" mode. For - "authorizer" mode it is MANDATORY and it points + :"docroot": is optional and is the docroot on the remote + host for default "responder" mode. For + "authorizer" mode it is MANDATORY and it points to docroot for authorized requests. For security reasons it is recommended to keep this docroot outside of server.document-root tree. - :"check-local": is optional and may be "enable" (default) or - "disable". If enabled the server first check - for a file in local server.document-root tree + :"check-local": is optional and may be "enable" (default) or + "disable". If enabled the server first check + for a file in local server.document-root tree and return 404 (Not Found) if no such file. - If disabled, the server forward request to + If disabled, the server forward request to FastCGI interface without this check. - :"broken-scriptfilename": breaks SCRIPT_FILENAME in a wat that + :"broken-scriptfilename": breaks SCRIPT_FILENAME in a wat that PHP can extract PATH_INFO from it (default: disabled) :"disable-time": time to wait before a disabled backend is checked again :"allow-x-send-file": controls if X-LIGHTTPD-send-file headers - are allowed + are allowed If bin-path is set: :"min-procs": sets the minium processes to start :"max-procs": the upper limit of the processess to start :"max-load-per-proc": maximum number of waiting processes on - average per process before a new process is + average per process before a new process is spawned :"idle-timeout": number of seconds before a unused process gets terminated - :"bin-environment": put an entry into the environment of + :"bin-environment": put an entry into the environment of the started process :"bin-copy-environement": clean up the environment and copy - only the specified entries into the fresh + only the specified entries into the fresh environment of the spawn process @@ -167,9 +167,9 @@ Examples -------- Multiple extensions for the same host :: - + fastcgi.server = ( ".php" => - (( "host" => "127.0.0.1", + (( "host" => "127.0.0.1", "port" => 1026, "bin-path" => "/usr/local/bin/php" )), @@ -180,30 +180,30 @@ Examples ) Example with prefix: :: - + fastcgi.server = ( "/remote_scripts/" => (( "host" => "192.168.0.3", "port" => 9000, "check-local" => "disable", - "docroot" => "/" # remote server may use + "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 is also the + variable. Remote server may prepend it with its own + 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 + In the case that the prefix is not terminated with a slash the prefix will be handled as file and /test.cgi would become a PATH_INFO instead of part of SCRIPT_NAME. Example for "authorizer" mode: :: - + fastcgi.server = ( "/remote_scripts/" => (( "host" => "10.0.0.2", "port" => 9000, @@ -212,23 +212,23 @@ Examples )) ) - Note that if "docroot" is specified then its value will be + Note that if "docroot" is specified then its value will be used in DOCUMENT_ROOT and SCRIPT_FILENAME variables passed to FastCGI server. Load-Balancing ============== -The FastCGI plugin provides automaticly a load-balancing between +The FastCGI plugin provides automaticly a load-balancing between multiple FastCGI servers. :: - fastcgi.server = ( ".php" => + fastcgi.server = ( ".php" => (( "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 +To understand how the load-balancing works you can enable the fastcgi.debug option and will get a similar output as here: :: proc: 127.0.0.1 1031 1 1 1 31454 @@ -244,89 +244,89 @@ fastcgi.debug option and will get a similar output as here: :: proc: 127.0.0.1 1031 1 1 2 31454 proc: 127.0.0.1 1029 1 1 2 31447 -Even if this for multiple FastCGI children on the local machine +Even if this for multiple FastCGI children on the local machine the following explaination is valid for remote connections too. -The output shows: +The output shows: - IP, port, unix-socket (is empty here) - is-local, state (0 - unset, 1 - running, ... ) - active connections (load) - PID -As you can see the list is always sorted by the load field. +As you can see the list is always sorted by the load field. -Whenever a new connection is requested, the first entry (the one -with the lowest load) is selected, the load is increased (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 dropped, 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 -as it keeps the fastcgi-servers equally loaded even if they have different -CPUs. +This behaviour is very light-weight in code and still very efficient +as it keeps the fastcgi-servers equally loaded even if they have different +CPUs. Adaptive Process Spawning ========================= -.. note:: This feature is disabled in 1.3.14 again. min-procs is +.. note:: This feature is disabled in 1.3.14 again. min-procs is ignored in that release -Starting with 1.3.8 lighttpd can spawn processes on demand if +Starting with 1.3.8 lighttpd can spawn processes on demand if a bin-path is specified and the FastCGI process runs locally. -If you want to have a least one FastCGI process running and -more of the number of requests increases you can use min-procs +If you want to have a least one FastCGI process running and +more of the number of requests increases you can use min-procs and max-procs. -A new process is spawned as soon as the average number of +A new process is spawned as soon as the average number of requests waiting to be handle by a single process increases the -max-load-per-proc setting. +max-load-per-proc setting. The idle-timeout specifies how long a fastcgi-process should wait -for a new request before it kills itself. +for a new request before it kills itself. Example ------- :: - fastcgi.server = ( ".php" => + 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 + "idle-timeout" => 20 )) ) Disabling Adaptive Spawning --------------------------- -Adaptive Spawning is a quite new feature and it might misbehave -for your setup. There are several ways to control how the spawing +Adaptive Spawning is a quite new feature and it might misbehave +for your setup. There are several ways to control how the spawing is done: 1. ``"max-load-per-proc" => 1`` if that works for you, great. - + 2. If not set ``min-procs == max-procs``. - + 3. For PHP you can also use: :: - + $ PHP_FCGI_CHILDREN=384 ./lighttpd -f ./lighttpd.conf - - fastcgi.server = ( ".php" => + + 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 + "idle-timeout" => 20 )) ) - + It will create one socket and let's PHP create the 384 processes itself. 4. If you don't want lighttpd to manage the fastcgi processes, remove the @@ -334,26 +334,26 @@ is done: FastCGI and Programming Languages -================================= +================================= Preparing PHP as a FastCGI program ---------------------------------- -One of the most important application that has a FastCGI -interface is php which can be downloaded from -http://www.php.net/ . You have to recompile the php from -source to enable the FastCGI interface as it is normally +One of the most important application that has a FastCGI +interface is php which can be downloaded from +http://www.php.net/ . You have to recompile the php from +source to enable the FastCGI interface as it is normally not enabled by default in the distributions. -If you already have a working installation of PHP on a +If you already have a working installation of PHP on a webserver execute a small script which just contains :: <?php phpinfo(); ?> -and search for the line in that contains the configure call. -You can use it as the base for the compilation. +and search for the line in that contains the configure call. +You can use it as the base for the compilation. -You have to remove all occurences of `--with-apxs`, `--with-apxs2` +You have to remove all occurences of `--with-apxs`, `--with-apxs2` and the like which would build PHP with Apache support. Add the next three switches to compile PHP with FastCGI support:: @@ -361,8 +361,8 @@ next three switches to compile PHP with FastCGI support:: --enable-fastcgi \ --enable-force-cgi-redirect \ ... - -After compilation and installation check that your PHP + +After compilation and installation check that your PHP binary contains FastCGI support by calling: :: $ php -v @@ -374,7 +374,7 @@ The important part is the (cgi-fcgi). Starting a FastCGI-PHP ---------------------- -Starting with version 1.3.6 lighttpd can spawn the FastCGI +Starting with version 1.3.6 lighttpd can spawn the FastCGI processes locally itself if necessary: :: fastcgi.server = ( ".php" => @@ -391,20 +391,20 @@ handles before it kills itself. :: fastcgi.server = ( ".php" => (( "socket" => "/tmp/php-fastcgi.socket", "bin-path" => "/usr/local/bin/php", - "bin-environment" => ( + "bin-environment" => ( "PHP_FCGI_CHILDREN" => "16", "PHP_FCGI_MAX_REQUESTS" => "10000" ) )) ) -To increase the security of the started process you should only pass +To increase the security of the started process you should only pass the necessary environment variables to the FastCGI process. :: fastcgi.server = ( ".php" => (( "socket" => "/tmp/php-fastcgi.socket", "bin-path" => "/usr/local/bin/php", - "bin-environment" => ( + "bin-environment" => ( "PHP_FCGI_CHILDREN" => "16", "PHP_FCGI_MAX_REQUESTS" => "10000" ), "bin-copy-environment" => ( @@ -425,7 +425,7 @@ and the option ``broken-scriptfilename`` in your fastcgi.server config: :: fastcgi.server = ( ".php" => (( "socket" => "/tmp/php-fastcgi.socket", "bin-path" => "/usr/local/bin/php", - "bin-environment" => ( + "bin-environment" => ( "PHP_FCGI_CHILDREN" => "16", "PHP_FCGI_MAX_REQUESTS" => "10000" ), "bin-copy-environment" => ( @@ -434,17 +434,17 @@ and the option ``broken-scriptfilename`` in your fastcgi.server config: :: )) ) -Why this ? the ``cgi.fix_pathinfo = 0`` would give you a working ``PATH_INFO`` +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 ``PATH_INFO`` `--enable-discard-path` needs a SCRIPT_FILENAME which is against the CGI spec, a broken-scriptfilename. With ``cgi.fix_pathinfo = 1`` in php.ini and -``broken-scriptfilename => "enable"`` you get both. +``broken-scriptfilename => "enable"`` you get both. External Spawning ----------------- -Spawning FastCGI processes directly in the webserver has some +Spawning FastCGI processes directly in the webserver has some disadvantages like - FastCGI process can only run locally @@ -456,54 +456,54 @@ take off some load from the webserver you have to control the FastCGI process by a external program like spawn-fcgi. spawn-fcgi is used to start a FastCGI process in its own -environment and set the user-id, group-id and change to +environment and set the user-id, group-id and change to another root-directory (chroot). -For convenience a wrapper script should be used which takes -care of all the necessary option. Such a script in included +For convenience a wrapper script should be used which takes +care of all the necessary option. Such a script in included in the lighttpd distribution and is call spawn-php.sh. -The script has a set of config variables you should take +The script has a set of config variables you should take a look at: :: ## ABSOLUTE path to the spawn-fcgi binary SPAWNFCGI="/usr/local/sbin/spawn-fcgi" - + ## ABSOLUTE path to the PHP binary FCGIPROGRAM="/usr/local/bin/php" - + ## bind to tcp-port on localhost FCGIPORT="1026" - + ## bind to unix domain socket # FCGISOCKET="/tmp/php.sock" - + ## number of PHP childs to spawn PHP_FCGI_CHILDREN=10 - + ## number of request server by a single php-process until ## is will be restarted PHP_FCGI_MAX_REQUESTS=1000 - + ## IP adresses where PHP should access server connections ## from FCGI_WEB_SERVER_ADDRS="127.0.0.1,192.168.0.1" - + # allowed environment variables sperated by spaces ALLOWED_ENV="ORACLE_HOME PATH USER" - + ## if this script is run as root switch to the following user USERID=wwwrun GROUPID=wwwrun -If you have set the variables to values that fit to your +If you have set the variables to values that fit to your setup you can start it by calling: :: $ spawn-php.sh spawn-fcgi.c.136: child spawned successfully: PID: 6925 -If you get "child spawned successfully: PID:" the php -processes could be started successfully. You should see them +If you get "child spawned successfully: PID:" the php +processes could be started successfully. You should see them in your processlist: :: $ ps ax | grep php @@ -511,22 +511,22 @@ in your processlist: :: 6928 ? S 0:00 /usr/local/bin/php ... -The number of processes should be PHP_FCGI_CHILDREN + 1. -Here the process 6925 is the master of the slaves which -handle the work in parallel. Number of parallel workers can -be set by PHP_FCGI_CHILDREN. A worker dies automaticly of -handling PHP_FCGI_MAX_REQUESTS requests as PHP might have +The number of processes should be PHP_FCGI_CHILDREN + 1. +Here the process 6925 is the master of the slaves which +handle the work in parallel. Number of parallel workers can +be set by PHP_FCGI_CHILDREN. A worker dies automaticly of +handling PHP_FCGI_MAX_REQUESTS requests as PHP might have memory leaks. -If you start the script as user root php processes will be -running as the user USERID and group GROUPID to drop the -root permissions. Otherwise the php processes will run as +If you start the script as user root php processes will be +running as the user USERID and group GROUPID to drop the +root permissions. Otherwise the php processes will run as the user you started script as. -As the script might be started from a unknown stage or even -directly from the command-line it cleans the environment -before starting the processes. ALLOWED_ENV contains all -the external environement variables that should be available +As the script might be started from a unknown stage or even +directly from the command-line it cleans the environment +before starting the processes. ALLOWED_ENV contains all +the external environement variables that should be available to the php-process. @@ -539,7 +539,7 @@ Skeleton for remote authorizer ============================== The basic functionality of authorizer is as follows (see -http://www.fastcgi.com/devkit/doc/fcgi-spec.html, 6.3 for +http://www.fastcgi.com/devkit/doc/fcgi-spec.html, 6.3 for details). :: #include <fcgi_stdio.h> @@ -547,25 +547,25 @@ details). :: #include <unistd.h> int main () { char* p; - - while (FCGI_Accept() >= 0) { + + while (FCGI_Accept() >= 0) { /* wait for fastcgi authorizer request */ - + printf("Content-type: text/html\r\n"); - + if ((p = getenv("QUERY_STRING")) == NULL) || <QUERY_STRING is unauthorized>) printf("Status: 403 Forbidden\r\n\r\n"); - else printf("\r\n"); + else printf("\r\n"); /* default Status is 200 - allow access */ } - + return 0; } -It is possible to use any other variables provided by -FastCGI interface for authorization check. Here is only an +It is possible to use any other variables provided by +FastCGI interface for authorization check. Here is only an example. @@ -578,22 +578,22 @@ If you get: :: (fcgi.c.274) connect delayed: 8 (fcgi.c.289) connect succeeded: 8 - (fcgi.c.745) unexpected end-of-file (perhaps the fastcgi + (fcgi.c.745) unexpected end-of-file (perhaps the fastcgi process died): 8 -the fastcgi process accepted the connection but closed it -right away. This happens if FCGI_WEB_SERVER_ADDRS doesn't +the fastcgi process accepted the connection but closed it +right away. This happens if FCGI_WEB_SERVER_ADDRS doesn't include the host where you are connection from. If you get :: (fcgi.c.274) connect delayed: 7 - (fcgi.c.1107) error: unexpected close of fastcgi connection + (fcgi.c.1107) error: unexpected close of fastcgi connection for /peterp/seite1.php (no fastcgi process on host/port ?) - (fcgi.c.1015) emergency exit: fastcgi: connection-fd: 5 + (fcgi.c.1015) emergency exit: fastcgi: connection-fd: 5 fcgi-fd: 7 -the fastcgi process is not running on the host/port you are +the fastcgi process is not running on the host/port you are connection to. Check your configuration. If you get :: @@ -601,6 +601,6 @@ If you get :: (fcgi.c.274) connect delayed: 7 (fcgi.c.289) connect succeeded: 7 -everything is fine. The connect() call just was delayed a +everything is fine. The connect() call just was delayed a little bit and is completly normal. diff --git a/doc/features.txt b/doc/features.txt index cfccbb1..f45fe08 100644 --- a/doc/features.txt +++ b/doc/features.txt @@ -7,12 +7,12 @@ progress report :Revision: $Revision: 1.2 $ :abstract: - This document tries to track the requested features and + This document tries to track the requested features and the release when they have been implemented. - + .. meta:: :keywords: lighttpd, features - + .. contents:: Table of Contents Description @@ -29,17 +29,17 @@ It is used to see what is still missing and what is already done. :: > considering installing and testing the latest version. From a > quick glance, it seems to support most/all of the features of > Premium thttpd and Zeus. - + If you think it compares to Zeus, then you've obviously never used Zeus. - + lighttpd is currently the only non-blocking open source web server to support FastCGI responders and that's worthwhile. - + The documentation is lacking. Comments in the configuration file do not make up for a complete manual. - + Constantly improving. :: - + The configuration syntax is overly complex, like Apache. There is no .htaccess support. @@ -50,34 +50,34 @@ Constantly improving. :: SSL. Works since 1.3.0. :: - + There is no SSI support. Zeus has full recursive SSI support. Output from a FastCGI program can get run through the SSI interpreter. SSI can also do virtual includes recursively. - + SSI works since 1.2.4. :: - + Request logging is not configurable. Zeus supports fully configurable access logging, plus a binary version of CLF that save space. - + 1.2.6 adds Apache-like logfile config. :: - + Access control only allows authentication via username and password. There is no way to allow or deny based in IP address. - + planed for 1.3.x :: - + The request rewriting appears to only allow regex substitutions. Zeus has a simple, yet powerful, request rewrite language. - - + + There is no support for FastCGI authorizers. These are very useful for high traffic sites that require complex authentication schemes or that store authorization information in a central database. - + since 1.1.9. :: - + There is no bandwidth throttling support. Zeus does bandwidth throttling correctly (i.e. unlike past versions of thttpd) and can throttle on a per-subserver (thttpd-style virtual hosts) basis. @@ -88,29 +88,29 @@ since 1.3.8. :: modification of web server behavior. While it isn't strictly necessary for an open source web server, it nice to have a documented, consistent API, rather than having to manually patch the server. - + If someone requests it it might be implemented. :: - + There is no web based interface. Zeus has a complete web based interface for everything, including a powerful feature of configuring multiple virtual servers at once. - + That is something that should be a special feature of Zeus. :) :: - + There is no support for mapping certain URLs to specific filesystem paths. - + since 1.2.6 :: - + There is no referring checking. This is incredibly important to prevent hotlinking of bandwidth intensive media types (images, movies, etc.). - + we have something better: mod_secdownload. And if someone wants referer checking we have a condition in the config for it since 1.2.9 :: - + Zeus has a lot of features that lighttpd doesn't have, but I only mentioned the ones I care about and use. - - -- + + -- David Phillips <david@acz.org> http://david.acz.org/ diff --git a/doc/magnet.txt b/doc/magnet.txt new file mode 100644 index 0000000..9d7697a --- /dev/null +++ b/doc/magnet.txt @@ -0,0 +1,429 @@ +{{{
+#!rst
+==============
+a power-magnet
+==============
+
+------------------
+Module: mod_magnet
+------------------
+
+
+
+.. contents:: Table of Contents
+
+Requirements
+============
+
+:Version: lighttpd 1.4.12 or higher
+:Packages: lua >= 5.1
+
+Overview
+========
+
+mod_magnet is a module to control the request handling in lighty.
+
+.. note::
+
+ Keep in mind that the magnet is executed in the core of lighty. EVERY long-running operation is blocking
+ ALL connections in the server. You are warned. For time-consuming or blocking scripts use mod_fastcgi and friends.
+
+For performance reasons mod_magnet caches the compiled script. For each script-run the script itself is checked for
+freshness and recompile if neccesary.
+
+
+Installation
+============
+
+mod_magnet needs a lighty which is compiled with the lua-support ( --with-lua). Lua 5.1 or higher are required by
+the module. Use "--with-lua=lua5.1" to install on Debian and friends. ::
+
+ server.modules = ( ..., "mod_magnet", ... )
+
+Options
+=======
+
+mod_magnet can attract a request in several stages in the request-handling.
+
+* either at the same level as mod_rewrite, before any parsing of the URL is done
+* or at a later stage, when the doc-root is known and the physical-path is already setup
+
+It depends on the purpose of the script which stage you want to intercept. Usually you want to use
+the 2nd stage where the physical-path which relates to your request is known. At this level you
+can run checks against lighty.env["physical.path"].
+
+::
+
+ magnet.attract-raw-url-to = ( ... )
+ magnet.attract-physical-path-to = ( ... )
+
+You can define multiple scripts when separated by a semicolon. The scripts are executed in the specified
+order. If one of them a returning a status-code, the following scripts will not be executed.
+
+Tables
+======
+
+Most of the interaction between between mod_magnet and lighty is done through tables. Tables in lua are hashes (Perl), dictionaries (Java), arrays (PHP), ...
+
+Request-Environment
+-------------------
+
+Lighttpd has its internal variables which are exported as read/write to the magnet.
+
+If "http://example.org/search.php?q=lighty" is requested this results in a request like ::
+
+ GET /search.php?q=lighty HTTP/1.1
+ Host: example.org
+
+When you are using ``attract-raw-url-to`` you can access the following variables:
+
+* parts of the request-line
+
+ * lighty.env["request.uri"] = "/search.php?q=lighty"
+
+* HTTP request-headers
+
+ * lighty.request["Host"] = "example.org"
+
+Later in the request-handling, the URL is splitted, cleaned up and turned into a physical path name:
+
+* parts of the URI
+
+ * lighty.env["uri.path"] = "/search.php"
+ * lighty.env["uri.path-raw"] = "/search.php"
+ * lighty.env["uri.scheme"] = "http"
+ * lighty.env["uri.authority"] = "example.org"
+ * lighty.env["uri.query"] = "q=lighty"
+
+* filenames, pathnames
+
+ * lighty.env["physical.path"] = "/my-docroot/search.php"
+ * lighty.env["physical.rel-path"] = "/search.php"
+ * lighty.env["physical.doc-root"] = "/my-docroot"
+
+All of them are readable, not all of the are writable (or don't have an effect if you write to them).
+
+As a start, you might want to use those variables for writing: ::
+
+ -- 1. simple rewriting is done via the request.uri
+ lighty.env["request.uri"] = ...
+ return lighty.RESTART_REQUEST
+
+ -- 2. changing the physical-path
+ lighty.env["physical.path"] = ...
+
+ -- 3. changing the query-string
+ lighty.env["uri.query"] = ...
+
+Response Headers
+----------------
+
+If you want to set a response header for your request, you can add a field to the lighty.header[] table: ::
+
+ lighty.header["Content-Type"] = "text/html"
+
+Sending Content
+===============
+
+You can generate your own content and send it out to the clients. ::
+
+ lighty.content = { "<pre>", { filename = "/etc/passwd" }, "</pre>" }
+ lighty.header["Content-Type"] = "text/html"
+
+ return 200
+
+The lighty.content[] table is executed when the script is finished. The elements of the array are processed left to right and the elements can either be a string or a table. Strings are included AS IS into the output of the request.
+
+* Strings
+
+ * are included as is
+
+* Tables
+
+ * filename = "<absolute-path>" is required
+ * offset = <number> [default: 0]
+ * length = <number> [default: size of the file - offset]
+
+Internally lighty will use the sendfile() call to send out the static files at full speed.
+
+Status Codes
+============
+
+You might have seen it already in other examples: In case you are handling the request completly in the magnet you
+can return your own status-codes. Examples are: Redirected, Input Validation, ... ::
+
+ if (lighty.env["uri.scheme"] == "http") then
+ lighty.header["Location"] = "https://" .. lighty.env["uri.authority"] .. lighty.env["request.uri"]
+ return 302
+ end
+
+You every number above and equal to 100 is taken as final status code and finishes the request. No other modules are
+executed after this return.
+
+A special return-code is lighty.RESTART_REQUEST (currently equal to 99) which is usually used in combination with
+changing the request.uri in a rewrite. It restarts the splitting of the request-uri again.
+
+If you return nothing (or nil) the request-handling just continues.
+
+Debugging
+=========
+
+To easy debugging we overloaded the print()-function in lua and redirect the output of print() to the error-log. ::
+
+ print("Host: " .. lighty.request["Host"])
+ print("Request-URI: " .. lighty.env["request.uri"])
+
+
+Examples
+========
+
+Sending text-files as HTML
+--------------------------
+
+This is a bit simplistic, but it illustrates the idea: Take a text-file and cover it in a <pre> tag.
+
+Config-file ::
+
+ magnet.attract-physical-path-to = server.docroot + "/readme.lua"
+
+readme.lua ::
+
+ lighty.content = { "<pre>", { filename = "/README" }, "</pre>" }
+ lighty.header["Content-Type"] = "text/html"
+
+ return 200
+
+Maintainance pages
+------------------
+
+Your side might be on maintainance from time to time. Instead of shutting down the server confusing all
+users, you can just send a maintainance page.
+
+Config-file ::
+
+ magnet.attract-physical-path-to = server.docroot + "/maintainance.lua"
+
+maintainance.lua ::
+
+ require "lfs"
+
+ if (nil == lfs.attributes(lighty.env["physical.doc-root"] .. "/maintainance.html")) then
+ lighty.content = ( lighty.env["physical.doc-root"] .. "/maintainance.html" )
+
+ lighty.header["Content-Type"] = "text/html"
+
+ return 200
+ end
+
+mod_flv_streaming
+-----------------
+
+Config-file ::
+
+ magnet.attract-physical-path-to = server.docroot + "/flv-streaming.lua"
+
+flv-streaming.lua::
+
+ if (lighty.env["uri.query"]) then
+ -- split the query-string
+ get = {}
+ for k, v in string.gmatch(lighty.env["uri.query"], "(%w+)=(%w+)") do
+ get[k] = v
+ end
+
+ if (get["start"]) then
+ -- missing: check if start is numeric and positive
+
+ -- send te FLV header + a seek into the file
+ lighty.content = { "FLV\x1\x1\0\0\0\x9\0\0\0\x9",
+ { filename = lighty.env["physical.path"], offset = get["start"] } }
+ lighty.header["Content-Type"] = "video/x-flv"
+
+ return 200
+ end
+ end
+
+
+selecting a random file from a directory
+----------------------------------------
+
+Say, you want to send a random file (ad-content) from a directory.
+
+To simplify the code and to improve the performance we define:
+
+* all images have the same format (e.g. image/png)
+* all images use increasing numbers starting from 1
+* a special index-file names the highest number
+
+Config ::
+
+ server.modules += ( "mod_magnet" )
+ magnet.attract-physical-path-to = "random.lua"
+
+random.lua ::
+
+ dir = lighty.env["physical.path"]
+
+ f = assert(io.open(dir .. "/index", "r"))
+ maxndx = f:read("*all")
+ f:close()
+
+ ndx = math.random(maxndx)
+
+ lighty.content = { { filename = dir .. "/" .. ndx }}
+ lighty.header["Content-Type"] = "image/png"
+
+ return 200
+
+denying illegal character sequences in the URL
+----------------------------------------------
+
+Instead of implementing mod_security, you might just want to apply filters on the content
+and deny special sequences that look like SQL injection.
+
+A common injection is using UNION to extend a query with another SELECT query.
+
+::
+
+ if (string.find(lighty.env["request.uri"], "UNION%s")) then
+ return 400
+ end
+
+Traffic Quotas
+--------------
+
+If you only allow your virtual hosts a certain amount for traffic each month and want to
+disable them if the traffic is reached, perhaps this helps: ::
+
+ host_blacklist = { ["www.example.org"] = 0 }
+
+ if (host_blacklist[lighty.request["Host"]]) then
+ return 404
+ end
+
+Just add the hosts you want to blacklist into the blacklist table in the shown way.
+
+Complex rewrites
+----------------
+
+If you want to implement caching on your document-root and only want to regenerate
+content if the requested file doesn't exist, you can attract the physical.path: ::
+
+ magnet.attract-physical-path-to = ( server.document-root + "/rewrite.lua" )
+
+rewrite.lua ::
+
+ require "lfs"
+
+ attr = lfs.attributes(lighty.env["physical.path"])
+
+ if (not attr) then
+ -- we couldn't stat() the file for some reason
+ -- let the backend generate it
+
+ lighty.env["uri.path"] = "/dispatch.fcgi"
+ lighty.env["physical.rel-path"] = lighty.env["uri.path"]
+ lighty.env["physical.path"] = lighty.env["physical.doc-root"] .. lighty.env["physical.rel-path"]
+ fi
+
+luafilesystem
++++++++++++++
+
+We are requiring the lua-module 'lfs' (http://www.keplerproject.org/luafilesystem/).
+
+I had to compile lfs myself for lua-5.1 which required a minor patch as compat-5.1 is not needed::
+
+ $ wget http://luaforge.net/frs/download.php/1487/luafilesystem-1.2.tar.gz
+ $ wget http://www.lighttpd.net/download/luafilesystem-1.2-lua51.diff
+ $ gzip -cd luafilesystem-1.2.tar.gz | tar xf -
+ $ cd luafilesystem-1.2
+ $ patch -ls -p1 < ../luafilesystem-1.2-lua51.diff
+ $ make install
+
+It will install lfs.so into /usr/lib/lua/5.1/ which is where lua expects the extensions on my system.
+
+SuSE and Gentoo are known to have their own lfs packages and don't require a compile.
+
+Usertracking
+------------
+
+... or how to store data globally in the script-context:
+
+Each script has its own script-context. When the script is started it only contains the lua-functions
+and the special lighty.* name-space. If you want to save data between script runs, you can use the global-script
+context:
+
+::
+
+ if (nil == _G["usertrack"]) then
+ _G["usertrack"] = {}
+ end
+ if (nil == _G["usertrack"][lighty.request["Cookie"]]) then
+ _G["usertrack"][lighty.request["Cookie"]]
+ else
+ _G["usertrack"][lighty.request["Cookie"]] = _G["usertrack"][lighty.request["Cookie"]] + 1
+ end
+
+ print _G["usertrack"][lighty.request["Cookie"]]
+
+The global-context is per script. If you update the script without restarting the server, the context will still be maintained.
+
+Counters
+--------
+
+mod_status support a global statistics page and mod_magnet allows to add and update values in the status page:
+
+Config ::
+
+ status.statistics-url = "/server-counters"
+ magnet.attract-raw-url-to = server.docroot + "/counter.lua"
+
+counter.lua ::
+
+ lighty.status["core.connections"] = lighty.status["core.connections"] + 1
+
+Result::
+
+ core.connections: 7
+ fastcgi.backend.php-foo.0.connected: 0
+ fastcgi.backend.php-foo.0.died: 0
+ fastcgi.backend.php-foo.0.disabled: 0
+ fastcgi.backend.php-foo.0.load: 0
+ fastcgi.backend.php-foo.0.overloaded: 0
+ fastcgi.backend.php-foo.1.connected: 0
+ fastcgi.backend.php-foo.1.died: 0
+ fastcgi.backend.php-foo.1.disabled: 0
+ fastcgi.backend.php-foo.1.load: 0
+ fastcgi.backend.php-foo.1.overloaded: 0
+ fastcgi.backend.php-foo.load: 0
+
+Porting mod_cml scripts
+-----------------------
+
+mod_cml got replaced by mod_magnet.
+
+A CACHE_HIT in mod_cml::
+
+ output_include = { "file1", "file2" }
+
+ return CACHE_HIT
+
+becomes::
+
+ content = { { filename = "/path/to/file1" }, { filename = "/path/to/file2"} }
+
+ return 200
+
+while a CACHE_MISS like (CML) ::
+
+ trigger_handler = "/index.php"
+
+ return CACHE_MISS
+
+becomes (magnet) ::
+
+ lighty.env["request.uri"] = "/index.php"
+
+ return lighty.RESTART_REQUEST
+
+}}}
\ No newline at end of file diff --git a/doc/performance.txt b/doc/performance.txt index 56a7ca1..04d48a1 100644 --- a/doc/performance.txt +++ b/doc/performance.txt @@ -115,13 +115,13 @@ Solaris sendfilev FreeBSD sendfile ========== ========== -The best backend is selected at compile time. In case you want to use -another backend set: :: +The best backend is selected at compile time. In case you want to use +another backend set: :: server.network-backend = "writev" -You can find more information about network backend in: - +You can find more information about network backend in: + http://blog.lighttpd.net/articles/2005/11/11/optimizing-lighty-for-high-concurrent-large-file-downloads diff --git a/doc/plugins.txt b/doc/plugins.txt index 91c81fd..22dee40 100644 --- a/doc/plugins.txt +++ b/doc/plugins.txt @@ -13,23 +13,23 @@ Module: core :abstract: The plugin interface is an integral part of lighttpd which provides a flexible way to add specific functionality to lighttpd. - + .. meta:: :keywords: lighttpd, plugins - + .. contents:: Table of Contents Description =========== Plugins allow you to enhance the functionality of lighttpd without -changing the core of the webserver. They can be loaded at startup time +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 ------------------- -lighttpd has 16 hooks which are used in different states of the +lighttpd has 16 hooks which are used in different states of the execution of the request: Serverwide hooks @@ -49,7 +49,7 @@ Serverwide hooks Connectionwide hooks ```````````````````` -Most of these hooks are called in ``http_response_prepare()`` after some +Most of these hooks are called in ``http_response_prepare()`` after some fields in the connection structure are set. :handle_uri_raw_: @@ -57,13 +57,13 @@ fields in the connection structure are set. :handle_uri_clean_: 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 + called at the end of the logical path handle to get a docroot :handle_subrequest_start_: called if the physical path is set up and checked :handle_subrequest_: called at the end of ``http_response_prepare()`` :handle_physical_path_: - called after the physical path is created and no other handler is + called after the physical path is created and no other handler is found for this request :handle_request_done_: called when the request is done @@ -73,7 +73,7 @@ fields in the connection structure are set. called after the connection_state_engine is left again and plugin internal handles have to be called :connection_reset_: - called if the connection structure has to be cleaned up + called if the connection structure has to be cleaned up Plugin Interface @@ -82,14 +82,14 @@ Plugin Interface \*_plugin_init `````````````` -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 +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 +- all hooks -The field ``data`` and ``lib`` should not be touched in the init function. +The field ``data`` and ``lib`` should not be touched in the init function. ``lib`` is the library handler from dlopen and ``data`` will be the storage of the internal plugin data. @@ -99,9 +99,9 @@ of the internal plugin data. init ```` -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. +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. :returns: a pointer to the internal plugin data. @@ -109,7 +109,7 @@ to set up the internal plugin data. The internal plugin is assigned the cleanup ``````` -The cleanup hook is called just before the plugin is unloaded. It is meant +The cleanup hook is called just before the plugin is unloaded. It is meant to free all buffers allocated in ``init`` or somewhere else in the plugin which are still not freed and to close all handles which were opened and are not closed yet. @@ -120,16 +120,16 @@ are not closed yet. set_defaults ```````````` -set_defaults is your entry point into the configfile parsing. It should +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 +the plugin configuration is valid. If it is not valid yet, it should set useful defaults or return with HANDLER_ERROR and an error message. :returns: HANDLER_GO_ON if ok - + HANDLER_ERROR will terminate lighttpd - + connection_reset ```````````````` @@ -137,9 +137,9 @@ called at the end of each request :returns: HANDLER_GO_ON if ok - + HANDLER_ERROR on error - + handle_trigger `````````````` @@ -147,9 +147,9 @@ called once a second :returns: HANDLER_GO_ON if ok - + HANDLER_ERROR on error - + handle_sighup ````````````` @@ -157,9 +157,9 @@ called if a SIGHUP is received (cycling logfiles, ...) :returns: HANDLER_GO_ON if ok - + HANDLER_ERROR on error - + handle_uri_raw `````````````` @@ -168,9 +168,9 @@ called after uri_raw is set :returns: HANDLER_GO_ON if ok HANDLER_FINISHED if the final output is prepared - + HANDLER_ERROR on error - + handle_uri_clean ```````````````` @@ -179,9 +179,9 @@ called after uri.path is set :returns: HANDLER_GO_ON if ok HANDLER_FINISHED if the final output is prepared - + HANDLER_ERROR on error - + handle_docroot `````````````` @@ -190,9 +190,9 @@ called when a docroot is needed :returns: HANDLER_GO_ON if ok HANDLER_FINISHED if the final output is prepared - + HANDLER_ERROR on error - + handle_subrequest_start ``````````````````````` @@ -201,9 +201,9 @@ called after physical.path is set :returns: HANDLER_GO_ON if ok HANDLER_FINISHED if the final output is prepared - + HANDLER_ERROR on error - + handle_subrequest ````````````````` @@ -212,9 +212,9 @@ called if subrequest_start requested a COMEBACK or a WAIT_FOR_EVENT :returns: HANDLER_GO_ON if ok HANDLER_FINISHED if the final output is prepared - + HANDLER_ERROR on error - + handle_physical_path ```````````````````` @@ -223,9 +223,9 @@ called after physical.path is set :returns: HANDLER_GO_ON if ok HANDLER_FINISHED if the final output is prepared - + HANDLER_ERROR on error - + handle_request_done ``````````````````` @@ -234,9 +234,9 @@ called at the end of the request (logging, statistics, ...) :returns: HANDLER_GO_ON if ok - + HANDLER_ERROR on error - + handle_connection_close ``````````````````````` @@ -244,9 +244,9 @@ called if the connection is terminated :returns: HANDLER_GO_ON if ok - + HANDLER_ERROR on error - + handle_joblist `````````````` @@ -254,7 +254,7 @@ called if the state of the connection has changed :returns: HANDLER_GO_ON if ok - + HANDLER_ERROR on error - + diff --git a/doc/proxy.txt b/doc/proxy.txt index 8ff5c3e..b8a3997 100644 --- a/doc/proxy.txt +++ b/doc/proxy.txt @@ -11,12 +11,12 @@ Module: mod_proxy :Revision: $Revision: 1.1 $ :abstract: - The proxy module a simplest way to connect lighttpd to + The proxy module a simplest way to connect lighttpd to java servers which have a HTTP-interface. - + .. meta:: :keywords: lighttpd, Proxy - + .. contents:: Table of Contents Description @@ -27,17 +27,17 @@ Description Options ======= -lighttpd provides the Proxy support via the proxy-module +lighttpd provides the Proxy support via the proxy-module (mod_proxy) which provides 2 options in the config-file: :proxy.debug: - a value between 0 and 65535 to set the debug-level in the - Proxy module. Currently only 0 and 1 are used. Use 1 to + a value between 0 and 65535 to set the debug-level in the + Proxy module. Currently only 0 and 1 are used. Use 1 to enable some debug output, 0 to disable it. :proxy.balance: might be one of 'hash', 'round-robin' or 'fair' (default). - + 'round-robin' choses another host for each request, 'hash' is generating a hash over the request-uri and makes sure that the same request URI is sent to always the same host. @@ -46,22 +46,22 @@ lighttpd provides the Proxy support via the proxy-module load-based, passive balancing. :proxy.server: - tell the module where to send Proxy requests to. Every - file-extension can have its own handler. Load-Balancing is + tell the module where to send Proxy requests to. Every + file-extension can have its own handler. Load-Balancing is done by specifying multiple handles for the same extension. - + structure of proxy.server section: :: - - ( <extension> => - ( + + ( <extension> => + ( ( "host" => <string> , "port" => <integer> ), ( "host" => <string> , "port" => <integer> ) ), - <extension> => ... + <extension> => ... ) - + :<extension>: is the file-extension or prefix (if started with "/") might empty to match all requests :"host": is ip of the proxy server @@ -69,9 +69,9 @@ lighttpd provides the Proxy support via the proxy-module server (default: 80) e.g.: :: - + proxy.server = ( ".jsp" => - ( ( + ( ( "host" => "10.0.0.242", "port" => 81 ) ) @@ -80,8 +80,8 @@ lighttpd provides the Proxy support via the proxy-module Example: ======== -Using lighttpd + mod_proxy in front of 8 Squids which handle the -caching of dynamic content for you. All requests for the host +Using lighttpd + mod_proxy in front of 8 Squids which handle the +caching of dynamic content for you. All requests for the host www.example.org should be forwarded to the proxy. All proxies listen on port 80 for requests. :: @@ -97,7 +97,7 @@ listen on port 80 for requests. :: ( "host" => "10.0.0.17" ) ) ) } -If one of the hosts goes down the all requests for this one server are +If one of the hosts goes down the all requests for this one server are moved equally to the other servers. If you want to know more about the algorithm used here google for 'Microsoft CARP'. diff --git a/doc/rc.lighttpd b/doc/rc.lighttpd index 4dd2a1e..da0d244 100755 --- a/doc/rc.lighttpd +++ b/doc/rc.lighttpd @@ -11,7 +11,7 @@ # /(usr/)sbin/rcFOO # # LSB compliant service control script; see http://www.linuxbase.org/spec/ -# +# # System startup script for some example service or daemon FOO (template) # ### BEGIN INIT INFO @@ -23,7 +23,7 @@ # Description: Start FOO to allow XY and provide YZ # continued on second line by '#<TAB>' ### END INIT INFO -# +# # Note on Required-Start: It does specify the init script ordering, # not real dependencies. Depencies have to be handled by admin # resp. the configuration tools (s)he uses. @@ -64,7 +64,7 @@ rc_reset # 5 - program is not installed # 6 - program is not configured # 7 - program is not running -# +# # Note that starting an already running service, stopping # or restarting a not-running service as well as the restart # with force-reload (in case signalling is not supported) are @@ -76,7 +76,7 @@ case "$1" in ## Start daemon with startproc(8). If this fails ## the echo return value is set appropriate. - # NOTE: startproc returns 0, even if service is + # NOTE: startproc returns 0, even if service is # already running to match LSB spec. startproc $LIGHTTPD_BIN -f $LIGHTTPD_CONF_PATH @@ -94,7 +94,7 @@ case "$1" in rc_status -v ;; try-restart) - ## Stop the service and if this succeeds (i.e. the + ## Stop the service and if this succeeds (i.e. the ## service was running before), start it again. ## Note: try-restart is not (yet) part of LSB (as of 0.7.5) $0 status >/dev/null && $0 restart @@ -121,7 +121,7 @@ case "$1" in $0 start touch /var/run/lighttpd.pid rc_status -v - + ## Otherwise if it does not support reload: #rc_failed 3 #rc_status -v diff --git a/doc/redirect.txt b/doc/redirect.txt index 118ea8e..cf7cd75 100644 --- a/doc/redirect.txt +++ b/doc/redirect.txt @@ -12,10 +12,10 @@ Module: mod_redirect :abstract: url redirection - + .. meta:: :keywords: lighttpd, redirect - + .. contents:: Table of Contents Description @@ -28,9 +28,9 @@ Options url.redirect redirects a set of URLs externally - + e.g. :: - + url.redirect = ( "^/show/([0-9]+)/([0-9]+)$" => "http://www.example.org/show.php?isdn=$1&page$2", "^/get/([0-9]+)/([0-9]+)$" => "http://www.example.org/get.php?isdn=$1&page$2" ) diff --git a/doc/rewrite.txt b/doc/rewrite.txt index 09d4b66..e467022 100644 --- a/doc/rewrite.txt +++ b/doc/rewrite.txt @@ -12,10 +12,10 @@ Module: mod_rewrite :abstract: url rewrite - + .. meta:: :keywords: lighttpd, rewrite - + .. contents:: Table of Contents Description @@ -28,25 +28,25 @@ Options url.rewrite-once rewrites a set of URLs interally in the webserver BEFORE they are handled. - + e.g. :: - + url.rewrite-once = ( "<regex>" => "<relative-uri>" ) - + url.rewrite-repeat rewrites a set of URLs interally in the webserver BEFORE they are handled - + e.g. :: - + url.rewrite-repeat = ( "<regex>" => "<relative-uri>" ) -The options ``url.rewrite`` and ``url.rewrite-final`` were mapped to ``url.rewrite-once`` +The options ``url.rewrite`` and ``url.rewrite-final`` were mapped to ``url.rewrite-once`` in 1.3.16. Examples ======== -The regex is matching the full REQUEST_URI which is supplied by the user including +The regex is matching the full REQUEST_URI which is supplied by the user including query-string.:: url.rewrite-once = ( "^/id/([0-9]+)$" => "/index.php?id=$1", @@ -58,7 +58,7 @@ query-string.:: # * you can never change document-root by mod_rewrite # use mod_*host instead to make real mass-vhost - # request: http://any.domain.com/url/ + # request: http://any.domain.com/url/ # before rewrite: REQUEST_URI="/www/htdocs/url/" # and DOCUMENT_ROOT="/www/htdocs/" %0="www.domain.com" $1="url/" # after rewrite: REQUEST_URI="/www/htdocs/domain.com/url/" diff --git a/doc/rrdtool.txt b/doc/rrdtool.txt index 0e05cd3..1ad5543 100644 --- a/doc/rrdtool.txt +++ b/doc/rrdtool.txt @@ -50,7 +50,7 @@ Generating Graphs :: #!/bin/sh - + RRDTOOL=/usr/bin/rrdtool OUTDIR=/var/www/servers/www.example.org/pages/rrd/ INFILE=/var/www/lighttpd.rrd diff --git a/doc/scgi.txt b/doc/scgi.txt index eeb694c..dbb6371 100644 --- a/doc/scgi.txt +++ b/doc/scgi.txt @@ -13,10 +13,10 @@ Module: mod_scgi :abstract: SCGI is a fast and simplified CGI interface. It is mostly used by Python + WSGI. - + .. meta:: :keywords: lighttpd, FastCGI - + .. contents:: Table of Contents Description @@ -24,7 +24,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 +and client has been replaced. Please check the documentation of the FastCGI module for more information. History diff --git a/doc/secdownload.txt b/doc/secdownload.txt index 570b911..bf0a481 100644 --- a/doc/secdownload.txt +++ b/doc/secdownload.txt @@ -114,19 +114,19 @@ Your application has to generate the correct URLs. The following sample code for PHP should be easily adaptable to any other language: :: <?php - + $secret = "verysecret"; $uri_prefix = "/dl/"; - + # filename $f = "/secret-file.txt"; - + # current timestamp $t = time(); - + $t_hex = sprintf("%08x", $t); $m = md5($secret.$f.$t_hex); - + # generate link printf('<a href="%s%s/%s%s">%s</a>', $uri_prefix, $m, $t_hex, $f, $f); @@ -139,7 +139,7 @@ The server has to be configured in the same way. The URI prefix and secret have to match: :: server.modules = ( ..., "mod_secdownload", ... ) - + secdownload.secret = "verysecret" secdownload.document-root = "/home/www/servers/download-area/" secdownload.uri-prefix = "/dl/" diff --git a/doc/security.txt b/doc/security.txt index ebbbf68..766fd34 100644 --- a/doc/security.txt +++ b/doc/security.txt @@ -12,10 +12,10 @@ Module: core :abstract: lighttpd was developed with security in mind ... - + .. meta:: :keywords: lighttpd, security - + .. contents:: Table of Contents Description diff --git a/doc/setenv.txt b/doc/setenv.txt index 0238c10..c03474f 100644 --- a/doc/setenv.txt +++ b/doc/setenv.txt @@ -12,10 +12,10 @@ Module: mod_setenv :abstract: mod_setenv is used to add request - + .. meta:: :keywords: lighttpd, skeleton - + .. contents:: Table of Contents Description diff --git a/doc/simple-vhost.txt b/doc/simple-vhost.txt index d4b4db2..4f8338f 100644 --- a/doc/simple-vhost.txt +++ b/doc/simple-vhost.txt @@ -12,10 +12,10 @@ Module: mod_simple_vhost :abstract: virtual hosting - + .. meta:: :keywords: lighttpd, virtual hosting - + .. contents:: Table of Contents Description @@ -36,11 +36,11 @@ The document root for each vhost is built from three values: The complete document root is constructed either by :: server-root + hostname + document-root - + or if this path does not exist by :: server-root + default-host + document-root - + A small example should make this idea clear: :: /var/www/ @@ -52,7 +52,7 @@ A small example should make this idea clear: :: /var/www/servers/mail.example.org/ /var/www/servers/mail.example.org/lib/ /var/www/servers/mail.example.org/pages/ - + simple-vhost.server-root = "/var/www/servers/" simple-vhost.default-host = "www.example.org" simple-vhost.document-root = "pages" @@ -71,7 +71,7 @@ with one another. :: $HTTP["host"] == "news.example.org" { server.document-root = "/var/www/servers/news2.example.org/pages/" - } + } When ``news.example.org`` is requested, the ``server.document-root`` will be set to ``/var/www/servers/news2.example.org/pages/``, but @@ -91,7 +91,7 @@ To use conditionals together with simple-vhost, you should do this: :: $HTTP["host"] == "news.example.org" { server.document-root = "/var/www/servers/news2.example.org/pages/" - } + } It will enable simple vhosting for all hosts other than ``news.example.org``. @@ -100,10 +100,10 @@ Options simple-vhost.server-root root of the virtual host - + simple-vhost.default-host use this hostname if the requested hostname does not have its own directory - + simple-vhost.document-root path below the vhost directory diff --git a/doc/skeleton.txt b/doc/skeleton.txt index 13c6881..b1b01e6 100644 --- a/doc/skeleton.txt +++ b/doc/skeleton.txt @@ -12,10 +12,10 @@ Module: mod_skeleton :abstract: a nice, short abstrace about the module - + .. meta:: :keywords: lighttpd, skeleton - + .. contents:: Table of Contents Description diff --git a/doc/spawn-php.sh b/doc/spawn-php.sh index 83b7b16..181eae2 100755 --- a/doc/spawn-php.sh +++ b/doc/spawn-php.sh @@ -49,6 +49,6 @@ E= for i in $ALLOWED_ENV; do E="$E $i=${!i}" done - + # clean the environment and set up a new one env - $E $EX diff --git a/doc/ssi.txt b/doc/ssi.txt index 8761416..c65e7e1 100644 --- a/doc/ssi.txt +++ b/doc/ssi.txt @@ -13,10 +13,10 @@ Module: mod_ssi :abstract: The module for server-side includes provides a compatability layer for NSCA/Apache SSI. - + .. meta:: :keywords: lighttpd, ssi, Server-Side Includes - + .. contents:: Table of Contents Description @@ -73,4 +73,4 @@ which are not supported by this module for various reasons: - nested virtual - config.errmsg - echo.encoding - + diff --git a/doc/state.txt b/doc/state.txt index d0768bc..5e8277b 100644 --- a/doc/state.txt +++ b/doc/state.txt @@ -14,10 +14,10 @@ Module: core This is a short summary of the state-engine which is driving the lighttpd webserver. It describes the basic concepts and the way the different parts of the server are connected. - + .. meta:: :keywords: lighttpd, state-engine - + .. contents:: Table of Contents Description @@ -52,72 +52,72 @@ and some may never be hit at all. reset connection (incl. close()) :close: close connection (handle lingering close) - + .. image:: state.png - + A simple GET request (green path) --------------------------------- - + The connection is idling in the 'connect' state waiting for a connection. As soon as the connection is set up we init the read-timer in 'reqstart' and start to read data from the network. As soon as we get the HTTP-request terminator (CRLFCRLF) we forward the header to the parser. - + The parsed request is handled by 'handlereq' and as soon as a decision out the request is made it is sent to 'respstart' to prepare the HTTP-response header. In the 'write' state the prepare content is sent out to the network. When everything is sent 'respend' is entered to log the -request and cleanup the environment. After the close() call the connection +request and cleanup the environment. After the close() call the connection is set back to the 'connect' state again. - + Keep-Alive (blue path) ---------------------- - + The Keep-Alive handling is implemented by going from the 'respend' directly to 'reqstart' without the close() and the accept() calls. - + POST requests (grey path) ------------------------- - + As requests might contain a request-body the state 'readpost' entered as soon as the header is parsed and we know how much data we expect. - + Pipelining ---------- - + HTTP/1.1 supportes pipelining (sending multiple requests without waiting for the response of the first request). This is handled transparently by the 'read' state. - + Unexpected errors (red path) ---------------------------- - + For really hard errors we use the 'error' state which resets the connection and can be call from every state. It is only use if there is no other way to handle the issue (e.g. client-side close of the connection). If possible we should use http-status 500 ('internal server error') and log the issue in the errorlog. - + If we have to take care of some data which is coming in after we ran into the error condition the 'close' state is used the init a half-close and read all the delay packet from the network. - + Sub-Requests (lightblue) ------------------------ - + The FastCGI, CGI, ... intergration is done by introducing a loop in 'handlereq' to handle all aspect which are neccesary to find out what has to be sent back to the client. - + Functions ========= Important functions used by the state-engine - + :state-engine: - ``connection_state_machine()`` - + :connect: - (nothing) diff --git a/doc/status.txt b/doc/status.txt index fe3ee87..5312176 100644 --- a/doc/status.txt +++ b/doc/status.txt @@ -12,10 +12,10 @@ Module: mod_status :abstract: mod_status displays the server's status and configuration - + .. meta:: :keywords: lighttpd, server status - + .. contents:: Table of Contents Description @@ -47,8 +47,8 @@ cover it in a conditional. :: } Or require authorization: :: - - auth.require = ( "/server-status" => + + auth.require = ( "/server-status" => ( "realm" ... ) ) @@ -68,7 +68,7 @@ status-url you can get a text version which is simpler to parse. :: Uptime: 1234 BusyServers: 123 -Total Accesses is the number of handled requests, kBytes the overall outgoing +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. @@ -88,7 +88,7 @@ status.status-url Example: status.status-url = "/server-status" status.enable-sort - + add JavaScript which allows client-side sorting for the connection overview Default: enable diff --git a/doc/userdir.txt b/doc/userdir.txt index 10ba065..27a896a 100644 --- a/doc/userdir.txt +++ b/doc/userdir.txt @@ -11,11 +11,11 @@ Module: mod_userdir :Revision: $Revision: 1.1 $ :abstract: - The userdir module ... - + The userdir module ... + .. meta:: :keywords: lighttpd, userdir - + .. contents:: Table of Contents Description @@ -29,7 +29,7 @@ building the classic mapping of: :: userdir.path = "public_html" - URL: http://www.example.org/~jan/index.html + 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 list of usernames to include or exclude. @@ -48,7 +48,7 @@ Options userdir.path usually it should be set to "public_html" to take ~/public_html/ as the document root - + Default: empty (document root is the home directory) Example: :: diff --git a/doc/webdav.txt b/doc/webdav.txt index b10012f..7b5259e 100644 --- a/doc/webdav.txt +++ b/doc/webdav.txt @@ -12,17 +12,17 @@ Module: mod_webdav :abstract: WebDAV module for lighttpd - + .. meta:: :keywords: lighttpd, webdav - + .. contents:: Table of Contents Description =========== The WebDAV module is a very minimalistic implementation of RFC 2518. -Minimalistic means that not all operations are implemented yet. +Minimalistic means that not all operations are implemented yet. So far we have @@ -32,7 +32,7 @@ So far we have * DELETE * PUT -and the usual GET, POST, HEAD from HTTP/1.1. +and the usual GET, POST, HEAD from HTTP/1.1. So far, mounting a WebDAV resource into Windows XP works and the basic litmus tests are passed. @@ -41,9 +41,9 @@ Options ======= webdav.activate - If you load the webdav module, the WebDAV functionality has to be + 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 webdav.is-readonly diff --git a/lighttpd.spec b/lighttpd.spec index 30e77b9..193170b 100644 --- a/lighttpd.spec +++ b/lighttpd.spec @@ -1,13 +1,13 @@ Summary: A fast webserver with minimal memory-footprint (lighttpd) Name: lighttpd -Version: 1.4.12 +Version: 1.4.13 Release: 1 Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz Packager: Jan Kneschke <jan@kneschke.de> License: BSD Group: Networking/Daemons URL: http://jan.kneschke.de/projects/lighttpd/ -Requires: pcre >= 3.1 zlib +Requires: pcre >= 3.1 zlib BuildPrereq: libtool zlib-devel BuildRoot: %{_tmppath}/%{name}-root @@ -63,7 +63,7 @@ fi %files %defattr(-,root,root) -%doc doc/lighttpd.conf doc/lighttpd.user README INSTALL ChangeLog COPYING AUTHORS +%doc doc/lighttpd.conf doc/lighttpd.user README INSTALL ChangeLog COPYING AUTHORS %doc doc/*.txt %config(noreplace) %attr(0755,root,root) %{_sysconfdir}/init.d/lighttpd %config(noreplace) %attr(0644,root,root) %{_sysconfdir}/sysconfig/lighttpd diff --git a/lighttpd.spec.in b/lighttpd.spec.in index 182297d..9436a83 100644 --- a/lighttpd.spec.in +++ b/lighttpd.spec.in @@ -7,7 +7,7 @@ Packager: Jan Kneschke <jan@kneschke.de> License: BSD Group: Networking/Daemons URL: http://jan.kneschke.de/projects/lighttpd/ -Requires: pcre >= 3.1 zlib +Requires: pcre >= 3.1 zlib BuildPrereq: libtool zlib-devel BuildRoot: %{_tmppath}/%{name}-root @@ -63,7 +63,7 @@ fi %files %defattr(-,root,root) -%doc doc/lighttpd.conf doc/lighttpd.user README INSTALL ChangeLog COPYING AUTHORS +%doc doc/lighttpd.conf doc/lighttpd.user README INSTALL ChangeLog COPYING AUTHORS %doc doc/*.txt %config(noreplace) %attr(0755,root,root) %{_sysconfdir}/init.d/lighttpd %config(noreplace) %attr(0644,root,root) %{_sysconfdir}/sysconfig/lighttpd diff --git a/openwrt/Makefile.in b/openwrt/Makefile.in index 8cd22be..2fba912 100644 --- a/openwrt/Makefile.in +++ b/openwrt/Makefile.in @@ -101,7 +101,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -134,6 +133,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ diff --git a/openwrt/control b/openwrt/control index ec80f98..d83440a 100644 --- a/openwrt/control +++ b/openwrt/control @@ -1,8 +1,8 @@ Package: lighttpd -Version: 1.4.12 +Version: 1.4.13 Architecture: mipsel Maintainer: Jan Kneschke <jan@kneschke.de> -Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.12.tar.gz +Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.13.tar.gz Section: net Priority: optional Depends: diff --git a/openwrt/lighttpd.conf b/openwrt/lighttpd.conf index 42d2f76..b17519d 100644 --- a/openwrt/lighttpd.conf +++ b/openwrt/lighttpd.conf @@ -1,5 +1,5 @@ # lighttpd configuration file -# +# # use a it as base for lighttpd 1.0.0 and above # # $Id: lighttpd.conf,v 1.6 2004/08/29 09:44:53 weigon Exp $ @@ -11,12 +11,12 @@ # all other module should only be loaded if really neccesary # - saves some time # - saves memory -server.modules = ( -# "mod_rewrite", -# "mod_redirect", - "mod_access", -# "mod_auth", -# "mod_status", +server.modules = ( +# "mod_rewrite", +# "mod_redirect", + "mod_access", +# "mod_auth", +# "mod_status", # "mod_fastcgi", # "mod_simple_vhost", # "mod_evhost", @@ -25,10 +25,10 @@ server.modules = ( # "mod_ssi", # "mod_usertrack", # "mod_rrdtool", -# "mod_accesslog" +# "mod_accesslog" ) -## a static document-root, for virtual-hosting take look at the +## a static document-root, for virtual-hosting take look at the ## server.virtual-* options server.document-root = "/www/" @@ -36,11 +36,11 @@ server.document-root = "/www/" # server.errorlog = "" # files to check for if .../ is requested -server.indexfiles = ( "index.php", "index.html", +server.indexfiles = ( "index.php", "index.html", "index.htm", "default.htm" ) # mimetype mapping -mimetype.assign = ( +mimetype.assign = ( ".pdf" => "application/pdf", ".sig" => "application/pgp-signature", ".spl" => "application/futuresplash", @@ -131,7 +131,7 @@ url.access-deny = ( "~", ".inc" ) #simple-vhost.document-root = "/pages/" -## +## ## Format: <errorfile-prefix><status>.html ## -> ..../status-404.html for 'File not found' #server.errorfile-prefix = "/home/weigon/projects/lighttpd/doc/status-" @@ -160,8 +160,8 @@ url.access-deny = ( "~", ".inc" ) #### fastcgi module ## read fastcgi.txt for more info #fastcgi.server = ( ".php" => -# ( "grisu" => -# ( +# ( "grisu" => +# ( # "host" => "192.168.2.10", # "port" => 1026 # ) @@ -191,14 +191,14 @@ url.access-deny = ( "~", ".inc" ) # auth.backend.ldap.base-dn = "dc=my-domain,dc=com" # auth.backend.ldap.filter = "(uid=$)" -# auth.require = ( "/server-status" => -# ( +# auth.require = ( "/server-status" => +# ( # "method" => "digest", # "realm" => "download archiv", # "require" => "group=www|user=jan|host=192.168.2.10" # ), -# "/server-info" => -# ( +# "/server-info" => +# ( # "method" => "digest", # "realm" => "download archiv", # "require" => "group=www|user=jan|host=192.168.2.10" diff --git a/openwrt/lighttpd.mk b/openwrt/lighttpd.mk index e198e3f..c4bf1de 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.12 +LIGHTTPD=lighttpd-1.4.13 LIGHTTPD_TARGET=.built LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD) LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk @@ -28,7 +28,7 @@ $(DL_DIR)/$(LIGHTTPD_SOURCE) : $(LIGHTTPD_DIR)/.unpacked: $(DL_DIR)/$(LIGHTTPD_SOURCE) gzip -cd $(DL_DIR)/$(LIGHTTPD_SOURCE) | tar -C $(BUILD_DIR) -xvf - touch $(LIGHTTPD_DIR)/.unpacked - + # if we have the sources unpacked, we need to configure them $(LIGHTTPD_DIR)/.configured: $(LIGHTTPD_DIR)/.unpacked (cd $(LIGHTTPD_DIR); rm -rf config.cache; \ @@ -48,14 +48,14 @@ $(LIGHTTPD_DIR)/.configured: $(LIGHTTPD_DIR)/.unpacked --program-transform-name="s,y,y," \ ); touch $(LIGHTTPD_DIR)/.configured - - + + # now that we have it all in place, just build it $(LIGHTTPD_DIR)/$(LIGHTTPD_TARGET): $(LIGHTTPD_DIR)/.configured - cd $(LIGHTTPD_DIR) && $(MAKE) CC=$(TARGET_CC) DESTDIR="$(LIGHTTPD_IPK_DIR)" install + cd $(LIGHTTPD_DIR) && $(MAKE) CC=$(TARGET_CC) DESTDIR="$(LIGHTTPD_IPK_DIR)" install $(STAGING_DIR)/bin/sstrip $(LIGHTTPD_IPK_DIR)/usr/sbin/lighttpd touch $(LIGHTTPD_DIR)/$(LIGHTTPD_TARGET) - + $(LIGHTTPD_IPK): uclibc $(LIGHTTPD_DIR)/$(LIGHTTPD_TARGET) mkdir -p $(LIGHTTPD_IPK_DIR)/CONTROL mkdir -p $(LIGHTTPD_IPK_DIR)/etc/init.d diff --git a/openwrt/lighttpd.mk.in b/openwrt/lighttpd.mk.in index 9ee6170..85cd2f2 100644 --- a/openwrt/lighttpd.mk.in +++ b/openwrt/lighttpd.mk.in @@ -28,7 +28,7 @@ $(DL_DIR)/$(LIGHTTPD_SOURCE) : $(LIGHTTPD_DIR)/.unpacked: $(DL_DIR)/$(LIGHTTPD_SOURCE) gzip -cd $(DL_DIR)/$(LIGHTTPD_SOURCE) | tar -C $(BUILD_DIR) -xvf - touch $(LIGHTTPD_DIR)/.unpacked - + # if we have the sources unpacked, we need to configure them $(LIGHTTPD_DIR)/.configured: $(LIGHTTPD_DIR)/.unpacked (cd $(LIGHTTPD_DIR); rm -rf config.cache; \ @@ -48,14 +48,14 @@ $(LIGHTTPD_DIR)/.configured: $(LIGHTTPD_DIR)/.unpacked --program-transform-name="s,y,y," \ ); touch $(LIGHTTPD_DIR)/.configured - - + + # now that we have it all in place, just build it $(LIGHTTPD_DIR)/$(LIGHTTPD_TARGET): $(LIGHTTPD_DIR)/.configured - cd $(LIGHTTPD_DIR) && $(MAKE) CC=$(TARGET_CC) DESTDIR="$(LIGHTTPD_IPK_DIR)" install + cd $(LIGHTTPD_DIR) && $(MAKE) CC=$(TARGET_CC) DESTDIR="$(LIGHTTPD_IPK_DIR)" install $(STAGING_DIR)/bin/sstrip $(LIGHTTPD_IPK_DIR)/usr/sbin/lighttpd touch $(LIGHTTPD_DIR)/$(LIGHTTPD_TARGET) - + $(LIGHTTPD_IPK): uclibc $(LIGHTTPD_DIR)/$(LIGHTTPD_TARGET) mkdir -p $(LIGHTTPD_IPK_DIR)/CONTROL mkdir -p $(LIGHTTPD_IPK_DIR)/etc/init.d diff --git a/src/Makefile.am b/src/Makefile.am index 3381100..49b3bfd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ AM_CFLAGS = $(FAM_CFLAGS) noinst_PROGRAMS=proc_open lemon # simple-fcgi #graphic evalo bench ajp ssl error_test adserver gen-license -sbin_PROGRAMS=lighttpd +sbin_PROGRAMS=lighttpd bin_PROGRAMS=spawn-fcgi LEMON=$(top_builddir)/src/lemon @@ -11,8 +11,8 @@ lemon_SOURCES=lemon.c #simple_fcgi_LDADD=-lfcgi if CROSS_COMPILING -configparser.c configparser.h: -mod_ssi_exprparser.c mod_ssi_exprparser.h: +configparser.c configparser.h: +mod_ssi_exprparser.c mod_ssi_exprparser.h: else configparser.y: lemon mod_ssi_exprparser.y: lemon @@ -21,7 +21,7 @@ configparser.c configparser.h: configparser.y rm -f configparser.h $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c -mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y +mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y rm -f mod_ssi_exprparser.h $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c endif @@ -47,13 +47,13 @@ common_src=buffer.c log.c \ network_freebsd_sendfile.c network_writev.c \ network_solaris_sendfilev.c network_openssl.c \ splaytree.c status_counter.c - + src = server.c response.c connections.c network.c \ configfile.c configparser.c request.c proc_open.c spawn_fcgi_SOURCES=spawn-fcgi.c -lib_LTLIBRARIES = +lib_LTLIBRARIES = if NO_RDYNAMIC # if the linker doesn't allow referencing symbols of the binary @@ -67,11 +67,11 @@ liblightcomp_la_LIBADD = $(PCRE_LIB) $(SSL_LIB) $(FAM_LIBS) common_libadd = liblightcomp.la else src += $(common_src) -common_libadd = +common_libadd = endif lib_LTLIBRARIES += mod_flv_streaming.la -mod_flv_streaming_la_SOURCES = mod_flv_streaming.c +mod_flv_streaming_la_SOURCES = mod_flv_streaming.c mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_flv_streaming_la_LIBADD = $(common_libadd) @@ -82,9 +82,9 @@ mod_evasive_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_webdav.la mod_webdav_la_SOURCES = mod_webdav.c -mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIBS) lib_LTLIBRARIES += mod_magnet.la mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c @@ -110,42 +110,42 @@ mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd) mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE) lib_LTLIBRARIES += mod_cgi.la -mod_cgi_la_SOURCES = mod_cgi.c +mod_cgi_la_SOURCES = mod_cgi.c mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_cgi_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_scgi.la -mod_scgi_la_SOURCES = mod_scgi.c +mod_scgi_la_SOURCES = mod_scgi.c mod_scgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_scgi_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_staticfile.la -mod_staticfile_la_SOURCES = mod_staticfile.c +mod_staticfile_la_SOURCES = mod_staticfile.c mod_staticfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_staticfile_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_dirlisting.la -mod_dirlisting_la_SOURCES = mod_dirlisting.c +mod_dirlisting_la_SOURCES = mod_dirlisting.c mod_dirlisting_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_dirlisting_la_LIBADD = $(common_libadd) $(PCRE_LIB) lib_LTLIBRARIES += mod_indexfile.la -mod_indexfile_la_SOURCES = mod_indexfile.c +mod_indexfile_la_SOURCES = mod_indexfile.c mod_indexfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_indexfile_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_setenv.la -mod_setenv_la_SOURCES = mod_setenv.c +mod_setenv_la_SOURCES = mod_setenv.c mod_setenv_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_setenv_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_alias.la -mod_alias_la_SOURCES = mod_alias.c +mod_alias_la_SOURCES = mod_alias.c mod_alias_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_alias_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_userdir.la -mod_userdir_la_SOURCES = mod_userdir.c +mod_userdir_la_SOURCES = mod_userdir.c mod_userdir_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_userdir_la_LIBADD = $(common_libadd) @@ -165,7 +165,7 @@ mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_proxy_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_ssi.la -mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c +mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_ssi_la_LIBADD = $(common_libadd) $(PCRE_LIB) @@ -193,7 +193,7 @@ lib_LTLIBRARIES += mod_simple_vhost.la mod_simple_vhost_la_SOURCES = mod_simple_vhost.c mod_simple_vhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_simple_vhost_la_LIBADD = $(common_libadd) - + lib_LTLIBRARIES += mod_fastcgi.la mod_fastcgi_la_SOURCES = mod_fastcgi.c mod_fastcgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined @@ -205,7 +205,7 @@ mod_access_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_access_la_LIBADD = $(common_libadd) lib_LTLIBRARIES += mod_compress.la -mod_compress_la_SOURCES = mod_compress.c +mod_compress_la_SOURCES = mod_compress.c mod_compress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_compress_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd) diff --git a/src/Makefile.in b/src/Makefile.in index ff69c2a..e3ea4c1 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -221,7 +221,8 @@ mod_usertrack_la_DEPENDENCIES = $(am__DEPENDENCIES_2) am_mod_usertrack_la_OBJECTS = mod_usertrack.lo mod_usertrack_la_OBJECTS = $(am_mod_usertrack_la_OBJECTS) mod_webdav_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) am_mod_webdav_la_OBJECTS = mod_webdav_la-mod_webdav.lo mod_webdav_la_OBJECTS = $(am_mod_webdav_la_OBJECTS) binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) @@ -384,7 +385,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -417,6 +417,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ @@ -514,16 +515,16 @@ lib_LTLIBRARIES = $(am__append_1) mod_flv_streaming.la mod_evasive.la \ @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_flv_streaming_la_SOURCES = mod_flv_streaming.c +mod_flv_streaming_la_SOURCES = mod_flv_streaming.c mod_flv_streaming_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_flv_streaming_la_LIBADD = $(common_libadd) 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 = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS) mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIBS) mod_magnet_la_SOURCES = mod_magnet.c mod_magnet_cache.c mod_magnet_la_CFLAGS = $(AM_CFLAGS) $(LUA_CFLAGS) mod_magnet_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined @@ -539,28 +540,28 @@ mod_mysql_vhost_la_SOURCES = mod_mysql_vhost.c mod_mysql_vhost_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd) mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE) -mod_cgi_la_SOURCES = mod_cgi.c +mod_cgi_la_SOURCES = mod_cgi.c mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_cgi_la_LIBADD = $(common_libadd) -mod_scgi_la_SOURCES = mod_scgi.c +mod_scgi_la_SOURCES = mod_scgi.c mod_scgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_scgi_la_LIBADD = $(common_libadd) -mod_staticfile_la_SOURCES = mod_staticfile.c +mod_staticfile_la_SOURCES = mod_staticfile.c mod_staticfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_staticfile_la_LIBADD = $(common_libadd) -mod_dirlisting_la_SOURCES = mod_dirlisting.c +mod_dirlisting_la_SOURCES = mod_dirlisting.c mod_dirlisting_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_dirlisting_la_LIBADD = $(common_libadd) $(PCRE_LIB) -mod_indexfile_la_SOURCES = mod_indexfile.c +mod_indexfile_la_SOURCES = mod_indexfile.c mod_indexfile_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_indexfile_la_LIBADD = $(common_libadd) -mod_setenv_la_SOURCES = mod_setenv.c +mod_setenv_la_SOURCES = mod_setenv.c mod_setenv_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_setenv_la_LIBADD = $(common_libadd) -mod_alias_la_SOURCES = mod_alias.c +mod_alias_la_SOURCES = mod_alias.c mod_alias_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_alias_la_LIBADD = $(common_libadd) -mod_userdir_la_SOURCES = mod_userdir.c +mod_userdir_la_SOURCES = mod_userdir.c mod_userdir_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_userdir_la_LIBADD = $(common_libadd) mod_rrdtool_la_SOURCES = mod_rrdtool.c @@ -572,7 +573,7 @@ mod_usertrack_la_LIBADD = $(common_libadd) mod_proxy_la_SOURCES = mod_proxy.c mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_proxy_la_LIBADD = $(common_libadd) -mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c +mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_ssi_la_LIBADD = $(common_libadd) $(PCRE_LIB) mod_secdownload_la_SOURCES = mod_secure_download.c @@ -593,7 +594,7 @@ mod_fastcgi_la_LIBADD = $(common_libadd) mod_access_la_SOURCES = mod_access.c mod_access_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_access_la_LIBADD = $(common_libadd) -mod_compress_la_SOURCES = mod_compress.c +mod_compress_la_SOURCES = mod_compress.c mod_compress_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined mod_compress_la_LIBADD = $(Z_LIB) $(BZ_LIB) $(common_libadd) mod_auth_la_SOURCES = mod_auth.c http_auth_digest.c http_auth.c @@ -1544,8 +1545,8 @@ uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ #simple_fcgi_SOURCES=simple-fcgi.c #simple_fcgi_LDADD=-lfcgi -@CROSS_COMPILING_TRUE@configparser.c configparser.h: -@CROSS_COMPILING_TRUE@mod_ssi_exprparser.c mod_ssi_exprparser.h: +@CROSS_COMPILING_TRUE@configparser.c configparser.h: +@CROSS_COMPILING_TRUE@mod_ssi_exprparser.c mod_ssi_exprparser.h: @CROSS_COMPILING_FALSE@configparser.y: lemon @CROSS_COMPILING_FALSE@mod_ssi_exprparser.y: lemon @@ -1553,7 +1554,7 @@ uninstall-am: uninstall-binPROGRAMS uninstall-info-am \ @CROSS_COMPILING_FALSE@ rm -f configparser.h @CROSS_COMPILING_FALSE@ $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c -@CROSS_COMPILING_FALSE@mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y +@CROSS_COMPILING_FALSE@mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y @CROSS_COMPILING_FALSE@ rm -f mod_ssi_exprparser.h @CROSS_COMPILING_FALSE@ $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c diff --git a/src/array.c b/src/array.c index 3e1b32d..e35455b 100644 --- a/src/array.c +++ b/src/array.c @@ -11,12 +11,12 @@ array *array_init(void) { array *a; - + a = calloc(1, sizeof(*a)); assert(a); - + a->next_power_of_2 = 1; - + return a; } @@ -43,29 +43,29 @@ array *array_init_array(array *src) { void array_free(array *a) { size_t i; if (!a) return; - + if (!a->is_weakref) { for (i = 0; i < a->size; i++) { if (a->data[i]) a->data[i]->free(a->data[i]); } } - + if (a->data) free(a->data); if (a->sorted) free(a->sorted); - + free(a); } void array_reset(array *a) { size_t i; if (!a) return; - + if (!a->is_weakref) { for (i = 0; i < a->used; i++) { a->data[i]->reset(a->data[i]); } } - + a->used = 0; } @@ -84,20 +84,20 @@ data_unset *array_pop(array *a) { static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) { int ndx = -1; int i, pos = 0; - + if (key == NULL) return -1; - + /* try to find the string */ for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) { int cmp; - + if (pos < 0) { pos += i; } else if (pos >= (int)a->used) { pos -= i; } else { cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used); - + if (cmp == 0) { /* found */ ndx = a->sorted[pos]; @@ -110,46 +110,46 @@ static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) } if (i == 0) break; } - + if (rndx) *rndx = pos; - + return ndx; } data_unset *array_get_element(array *a, const char *key) { int ndx; - + if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) { /* found, leave here */ - + return a->data[ndx]; - } - + } + return NULL; } data_unset *array_get_unused_element(array *a, data_type_t t) { data_unset *ds = NULL; - + UNUSED(t); if (a->size == 0) return NULL; - + if (a->used == a->size) return NULL; if (a->data[a->used]) { ds = a->data[a->used]; - + a->data[a->used] = NULL; } - + return ds; } /* replace or insert data, return the old one with the same key */ data_unset *array_replace(array *a, data_unset *du) { int ndx; - + if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) { array_insert_unique(a, du); return NULL; @@ -164,13 +164,13 @@ int array_insert_unique(array *a, data_unset *str) { int ndx = -1; int pos = 0; size_t j; - + /* generate unique index if neccesary */ if (str->key->used == 0 || str->is_index_key) { buffer_copy_long(str->key, a->unique_ndx++); str->is_index_key = 1; } - + /* try to find the string */ if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) { /* found, leave here */ @@ -181,14 +181,14 @@ int array_insert_unique(array *a, data_unset *str) { } return 0; } - + /* insert */ - + if (a->used+1 > INT_MAX) { /* we can't handle more then INT_MAX entries: see array_get_index() */ return -1; } - + if (a->size == 0) { a->size = 16; a->data = malloc(sizeof(*a->data) * a->size); @@ -204,27 +204,27 @@ int array_insert_unique(array *a, data_unset *str) { assert(a->sorted); for (j = a->used; j < a->size; j++) a->data[j] = NULL; } - + ndx = (int) a->used; - + a->data[a->used++] = str; - + if (pos != ndx && - ((pos < 0) || + ((pos < 0) || buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) { pos++; - } - + } + /* move everything on step to the right */ if (pos != ndx) { memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted)); } - + /* insert */ a->sorted[pos] = ndx; - + if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1; - + return 0; } @@ -254,7 +254,7 @@ int array_print(array *a, int depth) { size_t i; size_t maxlen; int oneline = 1; - + if (a->used > 5) { oneline = 0; } @@ -314,7 +314,7 @@ int array_print(array *a, int depth) { } array_print_indent(depth); fprintf(stdout, ")"); - + return 0; } @@ -323,47 +323,47 @@ int main (int argc, char **argv) { array *a; data_string *ds; data_count *dc; - + UNUSED(argc); UNUSED(argv); a = array_init(); - + ds = data_string_init(); buffer_copy_string(ds->key, "abc"); buffer_copy_string(ds->value, "alfrag"); - + array_insert_unique(a, (data_unset *)ds); - + ds = data_string_init(); buffer_copy_string(ds->key, "abc"); buffer_copy_string(ds->value, "hameplman"); - + array_insert_unique(a, (data_unset *)ds); - + ds = data_string_init(); buffer_copy_string(ds->key, "123"); buffer_copy_string(ds->value, "alfrag"); - + array_insert_unique(a, (data_unset *)ds); - + dc = data_count_init(); buffer_copy_string(dc->key, "def"); - + array_insert_unique(a, (data_unset *)dc); - + dc = data_count_init(); buffer_copy_string(dc->key, "def"); - + array_insert_unique(a, (data_unset *)dc); - + array_print(a, 0); - + array_free(a); - + fprintf(stderr, "%d\n", buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type"))); - + return 0; } #endif diff --git a/src/array.h b/src/array.h index b9687d7..862295c 100644 --- a/src/array.h +++ b/src/array.h @@ -29,21 +29,21 @@ typedef struct data_unset { typedef struct { data_unset **data; - + size_t *sorted; - + size_t used; size_t size; - + size_t unique_ndx; - + size_t next_power_of_2; int is_weakref; /* data is weakref, don't bother the data */ } array; typedef struct { DATA_UNSET; - + int count; } data_count; @@ -51,7 +51,7 @@ data_count *data_count_init(void); typedef struct { DATA_UNSET; - + buffer *value; } data_string; @@ -60,7 +60,7 @@ data_string *data_response_init(void); typedef struct { DATA_UNSET; - + array *value; } data_array; @@ -69,8 +69,8 @@ data_array *data_array_init(void); /** * possible compare ops in the configfile parser */ -typedef enum { - CONFIG_COND_UNSET, +typedef enum { + CONFIG_COND_UNSET, CONFIG_COND_EQ, /** == */ CONFIG_COND_MATCH, /** =~ */ CONFIG_COND_NE, /** != */ @@ -82,17 +82,17 @@ typedef enum { */ typedef enum { COMP_UNSET, - COMP_SERVER_SOCKET, - COMP_HTTP_URL, - COMP_HTTP_HOST, - COMP_HTTP_REFERER, - COMP_HTTP_USERAGENT, - COMP_HTTP_COOKIE, + COMP_SERVER_SOCKET, + COMP_HTTP_URL, + COMP_HTTP_HOST, + COMP_HTTP_REFERER, + COMP_HTTP_USERAGENT, + COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP, COMP_HTTP_QUERYSTRING } comp_key_t; -/* $HTTP["host"] == "incremental.home.kneschke.de" { ... } +/* $HTTP["host"] == "incremental.home.kneschke.de" { ... } * for print: comp_key op string * for compare: comp cond string/regex */ @@ -100,15 +100,15 @@ typedef enum { typedef struct _data_config data_config; struct _data_config { DATA_UNSET; - + array *value; - + buffer *comp_key; comp_key_t comp; - + config_cond_t cond; buffer *op; - + int context_ndx; /* more or less like an id */ array *childs; /* nested */ @@ -116,7 +116,7 @@ struct _data_config { /* for chaining only */ data_config *prev; data_config *next; - + buffer *string; #ifdef HAVE_PCRE_H pcre *regex; @@ -128,7 +128,7 @@ data_config *data_config_init(void); typedef struct { DATA_UNSET; - + int value; } data_integer; @@ -138,13 +138,13 @@ typedef struct { DATA_UNSET; buffer *host; - + unsigned short port; time_t disable_ts; int is_disabled; size_t balance; - + int usage; /* fair-balancing needs the no. of connections active on this host */ int last_used_ndx; /* round robin */ } data_fastcgi; @@ -29,7 +29,7 @@ #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H # define USE_OPENSSL -# include <openssl/ssl.h> +# include <openssl/ssl.h> #endif #ifdef HAVE_FAM_H @@ -80,25 +80,25 @@ typedef int socklen_t; #include "settings.h" -typedef enum { T_CONFIG_UNSET, - T_CONFIG_STRING, - T_CONFIG_SHORT, - T_CONFIG_BOOLEAN, - T_CONFIG_ARRAY, - T_CONFIG_LOCAL, +typedef enum { T_CONFIG_UNSET, + T_CONFIG_STRING, + T_CONFIG_SHORT, + T_CONFIG_BOOLEAN, + T_CONFIG_ARRAY, + T_CONFIG_LOCAL, T_CONFIG_DEPRECATED, T_CONFIG_UNSUPPORTED } config_values_type_t; -typedef enum { T_CONFIG_SCOPE_UNSET, - T_CONFIG_SCOPE_SERVER, +typedef enum { T_CONFIG_SCOPE_UNSET, + T_CONFIG_SCOPE_SERVER, T_CONFIG_SCOPE_CONNECTION } config_scope_type_t; typedef struct { const char *key; void *destination; - + config_values_type_t type; config_scope_type_t scope; } config_values_t; @@ -143,29 +143,29 @@ typedef struct { /* the request-line */ buffer *request; buffer *uri; - + buffer *orig_uri; - + http_method_t http_method; http_version_t http_version; - + buffer *request_line; - + /* strings to the header */ buffer *http_host; /* not alloced */ const char *http_range; const char *http_content_type; const char *http_if_modified_since; const char *http_if_none_match; - + array *headers; - + /* CONTENT */ size_t content_length; /* returned by strtoul() */ - + /* internal representation */ int accept_encoding; - + /* internal */ buffer *pathinfo; } request; @@ -173,10 +173,10 @@ typedef struct { typedef struct { off_t content_length; int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */ - + array *headers; - - enum { + + enum { HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED } transfer_encoding; } response; @@ -192,21 +192,21 @@ typedef struct { typedef struct { buffer *path; buffer *basedir; /* path = "(basedir)(.*)" */ - + buffer *doc_root; /* path = doc_root + rel_path */ buffer *rel_path; - + buffer *etag; } physical; typedef struct { buffer *name; buffer *etag; - + struct stat st; - + time_t stat_ts; - + #ifdef HAVE_LSTAT char is_symlink; #endif @@ -221,7 +221,7 @@ typedef struct { typedef struct { splay_tree *files; /* the nodes of the tree are stat_cache_entry's */ - + buffer *dir_name; /* for building the dirname from the filename */ #ifdef HAVE_FAM_H splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */ @@ -234,7 +234,7 @@ typedef struct { typedef struct { array *mimetypes; - + /* virtual-servers */ buffer *document_root; buffer *server_name; @@ -242,7 +242,7 @@ typedef struct { buffer *server_tag; buffer *dirlist_encoding; buffer *errorfile_prefix; - + unsigned short max_keep_alive_requests; unsigned short max_keep_alive_idle; unsigned short max_read_idle; @@ -250,16 +250,16 @@ typedef struct { unsigned short use_xattr; unsigned short follow_symlink; unsigned short range_requests; - + /* debug */ - + unsigned short log_file_not_found; unsigned short log_request_header; unsigned short log_request_handling; unsigned short log_response_header; unsigned short log_condition_handling; - - + + /* server wide */ buffer *ssl_pemfile; buffer *ssl_ca_file; @@ -277,9 +277,9 @@ typedef struct { /* configside */ unsigned short global_kbytes_per_second; /* */ - off_t global_bytes_per_second_cnt; + off_t global_bytes_per_second_cnt; /* server-wide traffic-shaper - * + * * each context has the counter which is inited once * a second by the global_kbytes_per_second config-var * @@ -287,12 +287,12 @@ typedef struct { * the connected conns are "offline" a little bit * * the problem: - * we somehow have to loose our "we are writable" signal + * we somehow have to loose our "we are writable" signal * on the way. - * + * */ off_t *global_bytes_per_second_cnt_ptr; /* */ - + #ifdef USE_OPENSSL SSL_CTX *ssl_ctx; #endif @@ -300,18 +300,18 @@ typedef struct { /* 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 +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; @@ -324,88 +324,88 @@ typedef struct { typedef struct { connection_state_t state; - + /* timestamps */ time_t read_idle_ts; time_t close_timeout_ts; time_t write_request_ts; - + time_t connection_start; time_t request_start; - + struct timeval start_tv; - + size_t request_count; /* number of requests handled in this connection */ size_t loops_per_request; /* to catch endless loops in a single request - * + * * used by mod_rewrite, mod_fastcgi, ... and others * this is self-protection */ - + int fd; /* the FD for this connection */ int fde_ndx; /* index for the fdevent-handler */ int ndx; /* reverse mapping to server->connection[ndx] */ - + /* fd states */ int is_readable; int is_writable; - + int keep_alive; /* only request.c can enable it, all other just disable */ - + int file_started; int file_finished; - + chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */ chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */ chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/ - + int traffic_limit_reached; - + off_t bytes_written; /* used by mod_accesslog, mod_rrd */ off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */ off_t bytes_read; /* used by mod_accesslog, mod_rrd */ off_t bytes_header; - + int http_status; - + sock_addr dst_addr; buffer *dst_addr_buf; /* request */ buffer *parse_request; unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */ - + request request; request_uri uri; - physical physical; + physical physical; response response; - + size_t header_len; - + buffer *authed_user; array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */ - + /* response */ int got_response; - + int in_joblist; - + connection_type mode; - + void **plugin_ctx; /* plugin connection specific config */ - + specific_config conf; /* global connection specific config */ cond_cache_t *cond_cache; - + buffer *server_name; - + /* error-handler */ buffer *error_handler; int error_handler_saved_status; int in_error_handler; - + void *srv_socket; /* reference to the server-socket (typecast to server_socket) */ - + #ifdef USE_OPENSSL SSL *ssl; buffer *ssl_error_want_reuse_buffer; @@ -452,36 +452,36 @@ typedef struct { typedef struct { unsigned short port; buffer *bindhost; - + buffer *errorlog_file; unsigned short errorlog_use_syslog; - + unsigned short dont_daemonize; buffer *changeroot; buffer *username; buffer *groupname; - + buffer *pid_file; - + buffer *event_handler; - + buffer *modules_dir; buffer *network_backend; array *modules; array *upload_tempdirs; - + unsigned short max_worker; unsigned short max_fds; unsigned short max_conns; unsigned short max_request_size; - + unsigned short log_request_header_on_error; unsigned short log_state_handling; - - enum { STAT_CACHE_ENGINE_UNSET, - STAT_CACHE_ENGINE_NONE, - STAT_CACHE_ENGINE_SIMPLE, - STAT_CACHE_ENGINE_FAM + + enum { STAT_CACHE_ENGINE_UNSET, + STAT_CACHE_ENGINE_NONE, + STAT_CACHE_ENGINE_SIMPLE, + STAT_CACHE_ENGINE_FAM } stat_cache_engine; unsigned short enable_cores; } server_config; @@ -490,16 +490,16 @@ typedef struct { sock_addr addr; int fd; int fde_ndx; - + buffer *ssl_pemfile; buffer *ssl_ca_file; buffer *ssl_cipher_list; unsigned short ssl_use_sslv2; unsigned short use_ipv6; unsigned short is_ssl; - + buffer *srv_token; - + #ifdef USE_OPENSSL SSL_CTX *ssl_ctx; #endif @@ -507,37 +507,37 @@ typedef struct { typedef struct { server_socket **ptr; - + size_t size; size_t used; } server_socket_array; typedef struct server { server_socket_array srv_sockets; - + /* the errorlog */ int errorlog_fd; enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode; buffer *errorlog_buf; - + fdevents *ev, *ev_ins; - + buffer_plugin plugins; void *plugin_slots; - + /* counters */ int con_opened; int con_read; int con_written; int con_closed; - + int ssl_is_init; - + int max_fds; /* max possible fds */ int cur_fds; /* currently used fds */ int want_fds; /* waiting fds */ int sockets_disabled; - + size_t max_conns; /* buffers */ @@ -545,13 +545,13 @@ typedef struct server { buffer *response_header; buffer *response_range; buffer *tmp_buf; - + buffer *tmp_chunk_len; - + buffer *empty_string; /* is necessary for cond_match */ buffer *cond_check_buf; - + /* caches */ #ifdef HAVE_IPV6 inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX]; @@ -559,32 +559,32 @@ typedef struct server { mtime_cache_type mtime_cache[FILE_CACHE_MAX]; array *split_vals; - + /* Timestamps */ time_t cur_ts; time_t last_generated_date_ts; time_t last_generated_debug_ts; time_t startup_ts; - + buffer *ts_debug_str; buffer *ts_date_str; - + /* config-file */ array *config; array *config_touched; - + array *config_context; specific_config **config_storage; - + server_config srvconf; - + short int config_deprecated; short int config_unsupported; - + connections *conns; connections *joblist; connections *fdwaitqueue; - + stat_cache *stat_cache; /** @@ -601,7 +601,7 @@ typedef struct server { * fastcgi.backend.<key>.disconnects = ... */ array *status; - + fdevent_handler_t event_handler; int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq); diff --git a/src/buffer.c b/src/buffer.c index 2026738..cf25d5b 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -12,20 +12,20 @@ static const char hex_chars[] = "0123456789abcdef"; /** - * init the buffer - * + * init the buffer + * */ buffer* buffer_init(void) { buffer *b; - + b = malloc(sizeof(*b)); assert(b); - + b->ptr = NULL; b->size = 0; b->used = 0; - + return b; } @@ -36,8 +36,8 @@ buffer *buffer_init_buffer(buffer *src) { } /** - * free the buffer - * + * free the buffer + * */ void buffer_free(buffer *b) { @@ -49,39 +49,39 @@ void buffer_free(buffer *b) { void buffer_reset(buffer *b) { if (!b) return; - + /* limit don't reuse buffer larger than ... bytes */ if (b->size > BUFFER_MAX_REUSE_SIZE) { free(b->ptr); b->ptr = NULL; b->size = 0; } - + b->used = 0; } /** - * - * allocate (if neccessary) enough space for 'size' bytes and + * + * allocate (if neccessary) enough space for 'size' bytes and * set the 'used' counter to 0 - * + * */ #define BUFFER_PIECE_SIZE 64 int buffer_prepare_copy(buffer *b, size_t size) { if (!b) return -1; - - if ((0 == b->size) || + + if ((0 == b->size) || (size > b->size)) { if (b->size) free(b->ptr); - + b->size = size; - + /* always allocate a multiply of BUFFER_PIECE_SIZE */ b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE); - + b->ptr = malloc(b->size); assert(b->ptr); } @@ -90,30 +90,30 @@ int buffer_prepare_copy(buffer *b, size_t size) { } /** - * + * * increase the internal buffer (if neccessary) to append another 'size' byte * ->used isn't changed - * + * */ int buffer_prepare_append(buffer *b, size_t size) { if (!b) return -1; - + if (0 == b->size) { b->size = size; - + /* always allocate a multiply of BUFFER_PIECE_SIZE */ b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE); - + b->ptr = malloc(b->size); b->used = 0; assert(b->ptr); } else if (b->used + size > b->size) { b->size += size; - + /* always allocate a multiply of BUFFER_PIECE_SIZE */ b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE); - + b->ptr = realloc(b->ptr, b->size); assert(b->ptr); } @@ -122,7 +122,7 @@ int buffer_prepare_append(buffer *b, size_t size) { int buffer_copy_string(buffer *b, const char *s) { size_t s_len; - + if (!s || !b) return -1; s_len = strlen(s) + 1; @@ -136,26 +136,26 @@ int buffer_copy_string(buffer *b, const char *s) { int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) { if (!s || !b) return -1; -#if 0 - /* removed optimization as we have to keep the empty string +#if 0 + /* removed optimization as we have to keep the empty string * in some cases for the config handling - * + * * url.access-deny = ( "" ) */ if (s_len == 0) return 0; -#endif +#endif buffer_prepare_copy(b, s_len + 1); - + memcpy(b->ptr, s, s_len); b->ptr[s_len] = '\0'; b->used = s_len + 1; - + return 0; } int buffer_copy_string_buffer(buffer *b, const buffer *src) { if (!src) return -1; - + if (src->used == 0) { b->used = 0; return 0; @@ -201,10 +201,10 @@ int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) { /** * append a string to the end of the buffer - * - * the resulting buffer is terminated with a '\0' + * + * the resulting buffer is terminated with a '\0' * s is treated as a un-terminated string (a \0 is handled a normal character) - * + * * @param b a buffer * @param s the string * @param s_len size of the string (without the terminating \0) @@ -228,7 +228,7 @@ int buffer_append_string_len(buffer *b, const char *s, size_t s_len) { int buffer_append_string_buffer(buffer *b, const buffer *src) { if (!src) return -1; if (src->used == 0) return 0; - + return buffer_append_string_len(b, src->ptr, src->used - 1); } @@ -245,9 +245,9 @@ int buffer_append_memory(buffer *b, const char *s, size_t s_len) { int buffer_copy_memory(buffer *b, const char *s, size_t s_len) { if (!s || !b) return -1; - + b->used = 0; - + return buffer_append_memory(b, s, s_len); } @@ -402,46 +402,46 @@ char hex2int(unsigned char hex) { /** - * init the buffer - * + * init the buffer + * */ buffer_array* buffer_array_init(void) { buffer_array *b; - + b = malloc(sizeof(*b)); - + assert(b); b->ptr = NULL; b->size = 0; b->used = 0; - + return b; } void buffer_array_reset(buffer_array *b) { size_t i; - + if (!b) return; - + /* if they are too large, reduce them */ for (i = 0; i < b->used; i++) { buffer_reset(b->ptr[i]); } - + b->used = 0; } /** - * free the buffer_array - * + * free the buffer_array + * */ void buffer_array_free(buffer_array *b) { size_t i; if (!b) return; - + for (i = 0; i < b->size; i++) { if (b->ptr[i]) buffer_free(b->ptr[i]); } @@ -451,7 +451,7 @@ void buffer_array_free(buffer_array *b) { buffer *buffer_array_append_get_buffer(buffer_array *b) { size_t i; - + if (b->size == 0) { b->size = 16; b->ptr = malloc(sizeof(*b->ptr) * b->size); @@ -467,13 +467,13 @@ buffer *buffer_array_append_get_buffer(buffer_array *b) { b->ptr[i] = NULL; } } - + if (b->ptr[b->used] == NULL) { b->ptr[b->used] = buffer_init(); } - + b->ptr[b->used]->used = 0; - + return b->ptr[b->used++]; } @@ -482,23 +482,23 @@ char * buffer_search_string_len(buffer *b, const char *needle, size_t len) { size_t i; if (len == 0) return NULL; if (needle == NULL) return NULL; - + if (b->used < len) return NULL; - + for(i = 0; i < b->used - len; i++) { if (0 == memcmp(b->ptr + i, needle, len)) { return b->ptr + i; } } - + return NULL; } buffer *buffer_init_string(const char *str) { buffer *b = buffer_init(); - + buffer_copy_string(b, str); - + return b; } @@ -508,7 +508,7 @@ int buffer_is_empty(buffer *b) { /** * check if two buffer contain the same data - * + * * HISTORY: this function was pretty much optimized, but didn't handled * alignment properly. */ @@ -522,100 +522,100 @@ int buffer_is_equal(buffer *a, buffer *b) { int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) { buffer b; - + b.ptr = (char *)s; b.used = b_len + 1; - + return buffer_is_equal(a, &b); } /* simple-assumption: - * + * * most parts are equal and doing a case conversion needs time - * + * */ int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) { size_t ndx = 0, max_ndx; size_t *al, *bl; size_t mask = sizeof(*al) - 1; - + al = (size_t *)a; bl = (size_t *)b; - + /* is the alignment correct ? */ if ( ((size_t)al & mask) == 0 && ((size_t)bl & mask) == 0 ) { - + max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask; - + for (; ndx < max_ndx; ndx += sizeof(*al)) { if (*al != *bl) break; al++; bl++; - + } - + } - + a = (char *)al; b = (char *)bl; - + max_ndx = ((a_len < b_len) ? a_len : b_len); - + for (; ndx < max_ndx; ndx++) { char a1 = *a++, b1 = *b++; - + if (a1 != b1) { if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z')) a1 |= 32; else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z')) b1 |= 32; if ((a1 - b1) != 0) return (a1 - b1); - + } } - + return 0; } /** * check if the rightmost bytes of the string are equal. - * - * + * + * */ int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) { /* no, len -> equal */ if (len == 0) return 1; - + /* len > 0, but empty buffers -> not equal */ if (b1->used == 0 || b2->used == 0) return 0; - + /* buffers too small -> not equal */ if (b1->used - 1 < len || b1->used - 1 < len) return 0; - - if (0 == strncmp(b1->ptr + b1->used - 1 - len, + + if (0 == strncmp(b1->ptr + b1->used - 1 - len, b2->ptr + b2->used - 1 - len, len)) { return 1; } - + return 0; } int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) { size_t i; - + /* BO protection */ if (in_len * 2 < in_len) return -1; - + buffer_prepare_copy(b, in_len * 2 + 1); - + for (i = 0; i < in_len; i++) { b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F]; b->ptr[b->used++] = hex_chars[in[i] & 0x0F]; } b->ptr[b->used++] = '\0'; - + return 0; } @@ -624,7 +624,7 @@ const char encoded_chars_rel_uri_part[] = { 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 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */ 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, /* 20 - 2F space " # $ % & ' + , / */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */ @@ -646,7 +646,7 @@ const char encoded_chars_rel_uri[] = { 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 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */ 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, /* 20 - 2F space " # $ % & ' + , / */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */ @@ -668,7 +668,7 @@ const char encoded_chars_html[] = { 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 */ + 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 */ @@ -690,7 +690,7 @@ 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 */ + 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 */ @@ -712,12 +712,12 @@ const char encoded_chars_hex[] = { 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 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 - 7F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */ @@ -734,13 +734,13 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_ unsigned char *ds, *d; size_t d_len, ndx; const char *map = NULL; - + if (!s || !b) return -1; - + if (b->ptr[b->used - 1] != '\0') { SEGFAULT(); } - + if (s_len == 0) return 0; switch(encoding) { @@ -764,7 +764,7 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_ } assert(map != NULL); - + /* count to-be-encoded-characters */ for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) { if (map[*ds]) { @@ -787,9 +787,9 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_ d_len ++; } } - + buffer_prepare_append(b, d_len); - + for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) { if (map[*ds]) { switch(encoding) { @@ -820,9 +820,9 @@ int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_ } } - /* terminate buffer and calculate new length */ + /* terminate buffer and calculate new length */ b->ptr[b->used + d_len - 1] = '\0'; - + b->used += d_len; return 0; @@ -854,10 +854,10 @@ static int buffer_urldecode_internal(buffer *url, int is_query) { low = hex2int(*(src + 2)); if (low != 0xFF) { high = (high << 4) | low; - - /* map control-characters out */ + + /* map control-characters out */ if (high < 32 || high == 127) high = '_'; - + *dst = high; src += 2; } @@ -925,7 +925,7 @@ int buffer_path_simplify(buffer *dest, buffer *src) } walk = src->ptr; #endif - + while (*walk == ' ') { walk++; } @@ -991,7 +991,7 @@ int light_isdigit(int c) { int light_isxdigit(int c) { if (light_isdigit(c)) return 1; - + c |= 32; return (c >= 'a' && c <= 'f'); } @@ -1007,29 +1007,29 @@ int light_isalnum(int c) { int buffer_to_lower(buffer *b) { char *c; - + if (b->used == 0) return 0; - + for (c = b->ptr; *c; c++) { if (*c >= 'A' && *c <= 'Z') { *c |= 32; } } - + return 0; } int buffer_to_upper(buffer *b) { char *c; - + if (b->used == 0) return 0; - + for (c = b->ptr; *c; c++) { if (*c >= 'a' && *c <= 'z') { *c &= ~32; } } - + return 0; } diff --git a/src/buffer.h b/src/buffer.h index 3ca22e5..82a5f83 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -12,23 +12,23 @@ typedef struct { char *ptr; - + size_t used; size_t size; } buffer; typedef struct { buffer **ptr; - + size_t used; size_t size; } buffer_array; typedef struct { char *ptr; - + size_t offset; /* input-pointer */ - + size_t used; /* output-pointer */ size_t size; } read_buffer; @@ -43,7 +43,7 @@ buffer* buffer_init_buffer(buffer *b); buffer* buffer_init_string(const char *str); void buffer_free(buffer *b); void buffer_reset(buffer *b); - + int buffer_prepare_copy(buffer *b, size_t size); int buffer_prepare_append(buffer *b, size_t size); diff --git a/src/chunk.c b/src/chunk.c index 776d59e..f5ec564 100644 --- a/src/chunk.c +++ b/src/chunk.c @@ -1,7 +1,7 @@ /** * the network chunk-API - * - * + * + * */ #include <sys/types.h> @@ -20,34 +20,34 @@ chunkqueue *chunkqueue_init(void) { chunkqueue *cq; - + cq = calloc(1, sizeof(*cq)); - + cq->first = NULL; cq->last = NULL; - + cq->unused = NULL; - + return cq; } static chunk *chunk_init(void) { chunk *c; - + c = calloc(1, sizeof(*c)); - + c->mem = buffer_init(); c->file.name = buffer_init(); c->file.fd = -1; c->file.mmap.start = MAP_FAILED; c->next = NULL; - + return c; } static void chunk_free(chunk *c) { if (!c) return; - + buffer_free(c->mem); buffer_free(c->file.name); @@ -56,13 +56,13 @@ static void chunk_free(chunk *c) { static void chunk_reset(chunk *c) { if (!c) return; - + buffer_reset(c->mem); if (c->file.is_temp && !buffer_is_empty(c->file.name)) { unlink(c->file.name->ptr); } - + buffer_reset(c->file.name); if (c->file.fd != -1) { @@ -78,27 +78,27 @@ static void chunk_reset(chunk *c) { void chunkqueue_free(chunkqueue *cq) { chunk *c, *pc; - + if (!cq) return; - + for (c = cq->first; c; ) { pc = c; c = c->next; chunk_free(pc); } - + for (c = cq->unused; c; ) { pc = c; c = c->next; chunk_free(pc); } - + free(cq); } static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) { chunk *c; - + /* check if we have a unused chunk */ if (!cq->unused) { c = chunk_init(); @@ -109,18 +109,18 @@ static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) { c->next = NULL; cq->unused_chunks--; } - + return c; } static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) { c->next = cq->first; cq->first = c; - + if (cq->last == NULL) { cq->last = c; } - + return 0; } @@ -129,19 +129,19 @@ static int chunkqueue_append_chunk(chunkqueue *cq, chunk *c) { cq->last->next = c; } cq->last = c; - + if (cq->first == NULL) { cq->first = c; } - + return 0; } void chunkqueue_reset(chunkqueue *cq) { chunk *c; /* move everything to the unused queue */ - - /* mark all read written */ + + /* mark all read written */ for (c = cq->first; c; c = c->next) { switch(c->type) { case MEM_CHUNK: @@ -150,7 +150,7 @@ void chunkqueue_reset(chunkqueue *cq) { case FILE_CHUNK: c->offset = c->file.length; break; - default: + default: break; } } @@ -162,110 +162,110 @@ void chunkqueue_reset(chunkqueue *cq) { int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) { chunk *c; - + if (len == 0) return 0; - + c = chunkqueue_get_unused_chunk(cq); - + c->type = FILE_CHUNK; - + buffer_copy_string_buffer(c->file.name, fn); c->file.start = offset; c->file.length = len; c->offset = 0; - + chunkqueue_append_chunk(cq, c); - + return 0; } int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) { chunk *c; - + if (mem->used == 0) return 0; - + c = chunkqueue_get_unused_chunk(cq); c->type = MEM_CHUNK; c->offset = 0; buffer_copy_string_buffer(c->mem, mem); - + chunkqueue_append_chunk(cq, c); - + return 0; } int chunkqueue_append_buffer_weak(chunkqueue *cq, buffer *mem) { chunk *c; - + if (mem->used == 0) return 0; - + c = chunkqueue_get_unused_chunk(cq); c->type = MEM_CHUNK; c->offset = 0; if (c->mem) buffer_free(c->mem); c->mem = mem; - + chunkqueue_append_chunk(cq, c); - + return 0; } int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) { chunk *c; - + if (mem->used == 0) return 0; - + c = chunkqueue_get_unused_chunk(cq); c->type = MEM_CHUNK; c->offset = 0; buffer_copy_string_buffer(c->mem, mem); - + chunkqueue_prepend_chunk(cq, c); - + return 0; } int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) { chunk *c; - + if (len == 0) return 0; - + c = chunkqueue_get_unused_chunk(cq); c->type = MEM_CHUNK; c->offset = 0; buffer_copy_string_len(c->mem, mem, len - 1); - + chunkqueue_append_chunk(cq, c); - + return 0; } buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) { chunk *c; - + c = chunkqueue_get_unused_chunk(cq); - + c->type = MEM_CHUNK; c->offset = 0; buffer_reset(c->mem); - + chunkqueue_prepend_chunk(cq, c); - + return c->mem; } buffer *chunkqueue_get_append_buffer(chunkqueue *cq) { chunk *c; - + c = chunkqueue_get_unused_chunk(cq); - + c->type = MEM_CHUNK; c->offset = 0; buffer_reset(c->mem); - + chunkqueue_append_chunk(cq, c); - + return c->mem; } @@ -280,7 +280,7 @@ int chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) { chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { chunk *c; buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX"); - + c = chunkqueue_get_unused_chunk(cq); c->type = FILE_CHUNK; @@ -290,7 +290,7 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { size_t i; /* we have several tempdirs, only if all of them fail we jump out */ - + for (i = 0; i < cq->tempdirs->used; i++) { data_string *ds = (data_string *)cq->tempdirs->data[i]; @@ -317,7 +317,7 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { chunkqueue_append_chunk(cq, c); buffer_free(template); - + return c; } @@ -325,7 +325,7 @@ chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { off_t chunkqueue_length(chunkqueue *cq) { off_t len = 0; chunk *c; - + for (c = cq->first; c; c = c->next) { switch (c->type) { case MEM_CHUNK: @@ -338,14 +338,14 @@ off_t chunkqueue_length(chunkqueue *cq) { break; } } - + return len; } off_t chunkqueue_written(chunkqueue *cq) { off_t len = 0; chunk *c; - + for (c = cq->first; c; c = c->next) { switch (c->type) { case MEM_CHUNK: @@ -356,7 +356,7 @@ off_t chunkqueue_written(chunkqueue *cq) { break; } } - + return len; } @@ -375,9 +375,9 @@ int chunkqueue_remove_finished_chunks(chunkqueue *cq) { if (c->mem->used == 0 || (c->offset == (off_t)c->mem->used - 1)) is_finished = 1; break; case FILE_CHUNK: - if (c->offset == c->file.length) is_finished = 1; + if (c->offset == c->file.length) is_finished = 1; break; - default: + default: break; } diff --git a/src/chunk.h b/src/chunk.h index 3893919..c3c91ab 100644 --- a/src/chunk.h +++ b/src/chunk.h @@ -6,7 +6,7 @@ typedef struct chunk { enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type; - + buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */ struct { @@ -16,7 +16,7 @@ typedef struct chunk { off_t length; /* octets to send from the starting offset */ int fd; - struct { + struct { char *start; /* the start pointer of the mmap'ed area */ size_t length; /* size of the mmap'ed area */ off_t offset; /* start is <n> octet away from the start of the file */ @@ -24,20 +24,20 @@ typedef struct chunk { int is_temp; /* file is temporary and will be deleted if on cleanup */ } file; - - off_t offset; /* octets sent from this chunk - the size of the chunk is either + + off_t offset; /* octets sent from this chunk + the size of the chunk is either - mem-chunk: mem->used - 1 - file-chunk: file.length */ - + struct chunk *next; } chunk; typedef struct { chunk *first; chunk *last; - + chunk *unused; size_t unused_chunks; diff --git a/src/configfile-glue.c b/src/configfile-glue.c index 5d1c8ec..d783689 100644 --- a/src/configfile-glue.c +++ b/src/configfile-glue.c @@ -11,10 +11,10 @@ * are the external interface of lighttpd. The functions * are used by the server itself and the plugins. * - * The main-goal is to have a small library in the end - * which is linked against both and which will define + * The main-goal is to have a small library in the end + * which is linked against both and which will define * the interface itself in the end. - * + * */ @@ -24,56 +24,56 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) { size_t i; data_unset *du; - + for (i = 0; cv[i].key; i++) { - + if (NULL == (du = array_get_element(ca, cv[i].key))) { /* no found */ - + continue; } - + switch (cv[i].type) { case T_CONFIG_ARRAY: if (du->type == TYPE_ARRAY) { size_t j; data_array *da = (data_array *)du; - + for (j = 0; j < da->value->used; j++) { if (da->value->data[j]->type == TYPE_STRING) { data_string *ds = data_string_init(); - + buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value); if (!da->is_index_key) { /* the id's were generated automaticly, as we copy now we might have to renumber them - * this is used to prepend server.modules by mod_indexfiles as it has to be loaded + * this is used to prepend server.modules by mod_indexfiles as it has to be loaded * before mod_fastcgi and friends */ buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key); } - + array_insert_unique(cv[i].destination, (data_unset *)ds); } else { - log_error_write(srv, __FILE__, __LINE__, "sssd", - "the key of an array can only be a string or a integer, variable:", - cv[i].key, "type:", da->value->data[j]->type); - + log_error_write(srv, __FILE__, __LINE__, "sssd", + "the key of an array can only be a string or a integer, variable:", + cv[i].key, "type:", da->value->data[j]->type); + return -1; } } } else { log_error_write(srv, __FILE__, __LINE__, "ss", cv[i].key, "should have been a array of strings like ... = ( \"...\" )"); - + return -1; } break; case T_CONFIG_STRING: if (du->type == TYPE_STRING) { data_string *ds = (data_string *)du; - + buffer_copy_string_buffer(cv[i].destination, ds->value); } else { log_error_write(srv, __FILE__, __LINE__, "ssss", cv[i].key, "should have been a string like ... = \"...\""); - + return -1; } break; @@ -81,15 +81,15 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t switch(du->type) { case TYPE_INTEGER: { data_integer *di = (data_integer *)du; - + *((unsigned short *)(cv[i].destination)) = di->value; break; } case TYPE_STRING: { data_string *ds = (data_string *)du; - + log_error_write(srv, __FILE__, __LINE__, "ssb", "got a string but expected a short:", cv[i].key, ds->value); - + return -1; } default: @@ -100,19 +100,19 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t case T_CONFIG_BOOLEAN: if (du->type == TYPE_STRING) { data_string *ds = (data_string *)du; - + if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) { *((unsigned short *)(cv[i].destination)) = 1; } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) { *((unsigned short *)(cv[i].destination)) = 0; } else { log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)"); - + return -1; } } else { log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\""); - + return -1; } break; @@ -121,15 +121,15 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t break; case T_CONFIG_UNSUPPORTED: log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found unsupported key:", cv[i].key, "-", (char *)(cv[i].destination)); - + srv->config_unsupported = 1; - + break; case T_CONFIG_DEPRECATED: log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination)); - + srv->config_deprecated = 1; - + break; } } @@ -139,25 +139,25 @@ int config_insert_values_internal(server *srv, array *ca, const config_values_t int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) { size_t i; data_unset *du; - + for (i = 0; cv[i].key; i++) { data_string *touched; - + if (NULL == (du = array_get_element(ca, cv[i].key))) { /* no found */ - + continue; } - + /* touched */ touched = data_string_init(); - + buffer_copy_string(touched->value, ""); buffer_copy_string_buffer(touched->key, du->key); - + array_insert_unique(srv->config_touched, (data_unset *)touched); } - + return config_insert_values_internal(srv, ca, cv); } @@ -197,25 +197,25 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat } /* pass the rules */ - + switch (dc->comp) { case COMP_HTTP_HOST: { char *ck_colon = NULL, *val_colon = NULL; - + if (!buffer_is_empty(con->uri.authority)) { - - /* + + /* * append server-port to the HTTP_POST if necessary */ - + l = con->uri.authority; - + switch(dc->cond) { case CONFIG_COND_NE: case CONFIG_COND_EQ: ck_colon = strchr(dc->string->ptr, ':'); val_colon = strchr(l->ptr, ':'); - + if (ck_colon == val_colon) { /* nothing to do with it */ break; @@ -242,15 +242,15 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat } case COMP_HTTP_REMOTEIP: { char *nm_slash; - /* handle remoteip limitations - * + /* handle remoteip limitations + * * "10.0.0.1" is provided for all comparisions - * + * * only for == and != we support - * + * * "10.0.0.1/24" */ - + if ((dc->cond == CONFIG_COND_EQ || dc->cond == CONFIG_COND_NE) && (con->dst_addr.plain.sa_family == AF_INET) && @@ -259,41 +259,41 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat long nm; char *err; struct in_addr val_inp; - + if (*(nm_slash+1) == '\0') { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string); - + return COND_RESULT_FALSE; } - + nm_bits = strtol(nm_slash + 1, &err, 10); - + if (*err) { log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err); - + return COND_RESULT_FALSE; } - + /* take IP convert to the native */ buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr); -#ifdef __WIN32 +#ifdef __WIN32 if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf); - + return COND_RESULT_FALSE; } #else if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) { log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf); - + return COND_RESULT_FALSE; } #endif - + /* build netmask */ nm = htonl(~((1 << (32 - nm_bits)) - 1)); - + if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) { return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE; } else { @@ -318,7 +318,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat case COMP_HTTP_REFERER: { data_string *ds; - + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) { l = ds->value; } else { @@ -348,7 +348,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat default: return COND_RESULT_FALSE; } - + if (NULL == l) { if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key, @@ -356,7 +356,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat } return COND_RESULT_FALSE; } - + if (con->conf.log_condition_handling) { log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key, "(", l, ") compare to ", dc->string); @@ -375,13 +375,13 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat case CONFIG_COND_MATCH: { cond_cache_t *cache = &con->cond_cache[dc->context_ndx]; int n; - + #ifndef elementsof #define elementsof(x) (sizeof(x) / sizeof(x[0])) #endif n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0, cache->matches, elementsof(cache->matches)); - + cache->patterncount = n; if (n > 0) { cache->comp_value = l; @@ -397,7 +397,7 @@ static cond_result_t config_check_cond_nocache(server *srv, connection *con, dat /* no way */ break; } - + return COND_RESULT_FALSE; } @@ -440,7 +440,7 @@ void config_cond_cache_reset(server *srv, connection *con) { con->cond_cache[i].result = COND_RESULT_UNSET; con->cond_cache[i].patterncount = 0; } -#else +#else memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used); #endif } diff --git a/src/configfile.c b/src/configfile.c index e5d1610..1d3d532 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -26,8 +26,8 @@ static int config_insert(server *srv) { size_t i; int ret = 0; buffer *stat_cache_string; - - config_values_t cv[] = { + + config_values_t cv[] = { { "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */ { "server.errorlog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 */ { "server.errorfile-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 */ @@ -38,7 +38,7 @@ static int config_insert(server *srv) { { "server.tag", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */ { "server.use-ipv6", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */ { "server.modules", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 9 */ - + { "server.event-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 */ { "server.pid-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 */ { "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */ @@ -49,7 +49,7 @@ static int config_insert(server *srv) { { "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 */ { "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */ - + { "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */ { "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */ { "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */ @@ -67,19 +67,19 @@ static int config_insert(server *srv) { { "mimetype.use-xattr", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */ { "mimetype.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 28 */ { "ssl.pemfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 29 */ - + { "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 30 */ - + { "debug.log-file-not-found", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 31 */ { "debug.log-request-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 32 */ { "debug.log-response-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 33 */ { "debug.log-request-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 34 */ - + { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */ { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */ { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */ { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */ - + { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 39 */ { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */ { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */ @@ -89,7 +89,7 @@ static int config_insert(server *srv) { { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */ { "ssl.cipher-list", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 46 */ { "ssl.use-sslv2", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 47 */ - + { "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 }, { "server.virtual-root", "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET }, @@ -99,11 +99,11 @@ static int config_insert(server *srv) { { "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 } }; - + /* 0 */ cv[0].destination = srv->srvconf.bindhost; cv[1].destination = srv->srvconf.errorlog_file; @@ -111,33 +111,33 @@ static int config_insert(server *srv) { cv[4].destination = srv->srvconf.username; cv[5].destination = srv->srvconf.groupname; cv[6].destination = &(srv->srvconf.port); - + cv[9].destination = srv->srvconf.modules; cv[10].destination = srv->srvconf.event_handler; cv[11].destination = srv->srvconf.pid_file; - + cv[13].destination = &(srv->srvconf.max_worker); cv[23].destination = &(srv->srvconf.max_fds); cv[36].destination = &(srv->srvconf.log_request_header_on_error); cv[37].destination = &(srv->srvconf.log_state_handling); - + cv[39].destination = &(srv->srvconf.errorlog_use_syslog); - + stat_cache_string = buffer_init(); 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); srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); assert(srv->config_storage); - + for (i = 0; i < srv->config_context->used; i++) { specific_config *s; - + s = calloc(1, sizeof(specific_config)); assert(s); s->document_root = buffer_init(); @@ -167,13 +167,13 @@ static int config_insert(server *srv) { 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; - + cv[2].destination = s->errorfile_prefix; - + cv[7].destination = s->server_tag; cv[8].destination = &(s->use_ipv6); - - + + /* 13 max-worker */ cv[14].destination = s->document_root; cv[15].destination = &(s->force_lowercase_filenames); @@ -194,26 +194,26 @@ static int config_insert(server *srv) { cv[28].destination = s->mimetypes; cv[29].destination = s->ssl_pemfile; cv[30].destination = &(s->is_ssl); - + cv[31].destination = &(s->log_file_not_found); cv[32].destination = &(s->log_request_handling); cv[33].destination = &(s->log_response_header); cv[34].destination = &(s->log_request_header); - + cv[35].destination = &(s->allow_http11); cv[38].destination = s->ssl_ca_file; cv[40].destination = &(s->range_requests); - + cv[46].destination = s->ssl_cipher_list; cv[47].destination = &(s->ssl_use_sslv2); srv->config_storage[i] = s; - + if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) { break; } } - + if (buffer_is_empty(stat_cache_string)) { srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE; } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) { @@ -223,22 +223,22 @@ static int config_insert(server *srv) { } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) { srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE; } else { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string); ret = HANDLER_ERROR; } - + buffer_free(stat_cache_string); - + return ret; - + } #define PATCH(x) con->conf.x = s->x int config_setup_connection(server *srv, connection *con) { specific_config *s = srv->config_storage[0]; - + PATCH(allow_http11); PATCH(mimetypes); PATCH(document_root); @@ -256,20 +256,20 @@ int config_setup_connection(server *srv, connection *con) { PATCH(kbytes_per_second); PATCH(global_kbytes_per_second); PATCH(global_bytes_per_second_cnt); - + con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt; buffer_copy_string_buffer(con->server_name, s->server_name); - + PATCH(log_request_header); PATCH(log_response_header); PATCH(log_request_handling); PATCH(log_condition_handling); PATCH(log_file_not_found); - + PATCH(range_requests); PATCH(force_lowercase_filenames); PATCH(is_ssl); - + PATCH(ssl_pemfile); PATCH(ssl_ca_file); PATCH(ssl_cipher_list); @@ -281,22 +281,22 @@ int config_setup_connection(server *srv, connection *con) { int config_patch_connection(server *srv, connection *con, comp_key_t comp) { size_t i, j; - + /* 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]; specific_config *s = srv->config_storage[i]; - + /* not our stage */ if (comp != dc->comp) continue; - + /* 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("server.document-root"))) { PATCH(document_root); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) { @@ -349,7 +349,7 @@ 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-lowercase-filenames"))) { + } 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); @@ -358,7 +358,7 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) { } } } - + return 0; } #undef PATCH @@ -366,15 +366,15 @@ int config_patch_connection(server *srv, connection *con, comp_key_t comp) { typedef struct { int foo; int bar; - + const buffer *source; const char *input; size_t offset; size_t size; - + int line_pos; int line; - + int in_key; int in_brace; int in_cond; @@ -392,7 +392,7 @@ static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const ch } if (0 != stream_open(&(t->s), t->file)) { - log_error_write(srv, __FILE__, __LINE__, "sbss", + log_error_write(srv, __FILE__, __LINE__, "sbss", "opening configfile ", t->file, "failed:", strerror(errno)); buffer_free(t->file); return -1; @@ -403,7 +403,7 @@ static int tokenizer_open(server *srv, tokenizer_t *t, buffer *basedir, const ch t->size = t->s.size; t->line = 1; t->line_pos = 1; - + t->in_key = 1; t->in_brace = 0; t->in_cond = 0; @@ -431,7 +431,7 @@ static int config_skip_newline(tokenizer_t *t) { static int config_skip_comment(tokenizer_t *t) { int i; assert(t->input[t->offset] == '#'); - for (i = 1; t->input[t->offset + i] && + for (i = 1; t->input[t->offset + i] && (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r'); i++); t->offset += i; @@ -441,44 +441,44 @@ static int config_skip_comment(tokenizer_t *t) { static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) { int tid = 0; size_t i; - + for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) { char c = t->input[t->offset]; const char *start = NULL; - + switch (c) { - case '=': + case '=': if (t->in_brace) { if (t->input[t->offset + 1] == '>') { t->offset += 2; - + buffer_copy_string(token, "=>"); - + tid = TK_ARRAY_ASSIGN; } else { - log_error_write(srv, __FILE__, __LINE__, "sbsdsds", + log_error_write(srv, __FILE__, __LINE__, "sbsdsds", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "use => for assignments in arrays"); return -1; } } else if (t->in_cond) { if (t->input[t->offset + 1] == '=') { t->offset += 2; - + buffer_copy_string(token, "=="); - + tid = TK_EQ; } else if (t->input[t->offset + 1] == '~') { t->offset += 2; - + buffer_copy_string(token, "=~"); - + tid = TK_MATCH; } else { - log_error_write(srv, __FILE__, __LINE__, "sbsdsds", + log_error_write(srv, __FILE__, __LINE__, "sbsdsds", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "only =~ and == are allowed in the condition"); return -1; } @@ -486,51 +486,51 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer * t->in_cond = 0; } else if (t->in_key) { tid = TK_ASSIGN; - + buffer_copy_string_len(token, t->input + t->offset, 1); - + t->offset++; t->line_pos++; } else { - log_error_write(srv, __FILE__, __LINE__, "sbsdsds", + log_error_write(srv, __FILE__, __LINE__, "sbsdsds", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "unexpected equal-sign: ="); return -1; } - + break; - case '!': + case '!': if (t->in_cond) { if (t->input[t->offset + 1] == '=') { t->offset += 2; - + buffer_copy_string(token, "!="); - + tid = TK_NE; } else if (t->input[t->offset + 1] == '~') { t->offset += 2; - + buffer_copy_string(token, "!~"); - + tid = TK_NOMATCH; } else { - log_error_write(srv, __FILE__, __LINE__, "sbsdsds", + log_error_write(srv, __FILE__, __LINE__, "sbsdsds", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "only !~ and != are allowed in the condition"); return -1; } t->in_key = 1; t->in_cond = 0; } else { - log_error_write(srv, __FILE__, __LINE__, "sbsdsds", + log_error_write(srv, __FILE__, __LINE__, "sbsdsds", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "unexpected exclamation-marks: !"); return -1; } - + break; case '\t': case ' ': @@ -576,10 +576,10 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer * case ',': if (t->in_brace > 0) { tid = TK_COMMA; - + buffer_copy_string(token, "(COMMA)"); } - + t->offset++; t->line_pos++; break; @@ -587,70 +587,70 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer * /* search for the terminating " */ start = t->input + t->offset + 1; buffer_copy_string(token, ""); - + for (i = 1; t->input[t->offset + i]; i++) { if (t->input[t->offset + i] == '\\' && t->input[t->offset + i + 1] == '"') { - + buffer_append_string_len(token, start, t->input + t->offset + i - start); - + start = t->input + t->offset + i + 1; - + /* skip the " */ i++; continue; } - - + + if (t->input[t->offset + i] == '"') { tid = TK_STRING; - + buffer_append_string_len(token, start, t->input + t->offset + i - start); - + break; } } if (t->input[t->offset + i] == '\0') { /* ERROR */ - - log_error_write(srv, __FILE__, __LINE__, "sbsdsds", + + log_error_write(srv, __FILE__, __LINE__, "sbsdsds", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "missing closing quote"); - + return -1; } - + t->offset += i + 1; t->line_pos += i + 1; - + break; case '(': t->offset++; t->in_brace++; - + tid = TK_LPARAN; - + buffer_copy_string(token, "("); break; case ')': t->offset++; t->in_brace--; - + tid = TK_RPARAN; - + buffer_copy_string(token, ")"); break; case '$': t->offset++; - + tid = TK_DOLLAR; t->in_cond = 1; t->in_key = 0; - + buffer_copy_string(token, "$"); - + break; case '+': @@ -667,88 +667,88 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer * case '{': t->offset++; - + tid = TK_LCURLY; - + buffer_copy_string(token, "{"); - + break; - + case '}': t->offset++; - + tid = TK_RCURLY; - + buffer_copy_string(token, "}"); - + break; case '[': t->offset++; - + tid = TK_LBRACKET; - + buffer_copy_string(token, "["); - + break; - + case ']': t->offset++; - + tid = TK_RBRACKET; - + buffer_copy_string(token, "]"); - + break; case '#': t->line_pos += config_skip_comment(t); - + break; default: if (t->in_cond) { - for (i = 0; t->input[t->offset + i] && + for (i = 0; t->input[t->offset + i] && (isalpha((unsigned char)t->input[t->offset + i]) ); i++); - + if (i && t->input[t->offset + i]) { tid = TK_SRVVARNAME; buffer_copy_string_len(token, t->input + t->offset, i); - + t->offset += i; t->line_pos += i; } else { /* ERROR */ - log_error_write(srv, __FILE__, __LINE__, "sbsdsds", + log_error_write(srv, __FILE__, __LINE__, "sbsdsds", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "invalid character in condition"); return -1; } } else if (isdigit((unsigned char)c)) { /* take all digits */ for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++); - + /* was there it least a digit ? */ if (i) { tid = TK_INTEGER; - + buffer_copy_string_len(token, t->input + t->offset, i); - + t->offset += i; t->line_pos += i; } } else { /* the key might consist of [-.0-9a-z] */ - for (i = 0; t->input[t->offset + i] && - (isalnum((unsigned char)t->input[t->offset + i]) || + for (i = 0; t->input[t->offset + i] && + (isalnum((unsigned char)t->input[t->offset + i]) || t->input[t->offset + i] == '.' || t->input[t->offset + i] == '_' || /* for env.* */ t->input[t->offset + i] == '-' ); i++); - + if (i && t->input[t->offset + i]) { buffer_copy_string_len(token, t->input + t->offset, i); - + if (strcmp(token->ptr, "include") == 0) { tid = TK_INCLUDE; } else if (strcmp(token->ptr, "include_shell") == 0) { @@ -760,14 +760,14 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer * } else { tid = TK_LKEY; } - + t->offset += i; t->line_pos += i; } else { /* ERROR */ - log_error_write(srv, __FILE__, __LINE__, "sbsdsds", + log_error_write(srv, __FILE__, __LINE__, "sbsdsds", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "invalid character in variable name"); return -1; } @@ -775,16 +775,16 @@ static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer * break; } } - + if (tid) { *token_id = tid; #if 0 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd", + log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd", "source:", t->source, "line:", t->line, "pos:", t->line_pos, token, token->used - 1, tid); #endif - + return 1; } else if (t->offset < t->size) { fprintf(stderr, "%s.%d: %d, %s\n", @@ -806,7 +806,7 @@ static int config_parse(server *srv, config_t *context, tokenizer_t *t) { while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) { buffer_copy_string_buffer(lasttoken, token); configparser(pParser, token_id, token, context); - + token = buffer_init(); } buffer_free(token); @@ -819,14 +819,14 @@ static int config_parse(server *srv, config_t *context, tokenizer_t *t) { } } configparserFree(pParser, free); - + if (ret == -1) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "configfile parser failed at:", lasttoken); } else if (context->ok == 0) { - log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb", + log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb", "source:", t->source, - "line:", t->line, "pos:", t->line_pos, + "line:", t->line, "pos:", t->line_pos, "parser failed somehow near here:", lasttoken); ret = -1; } @@ -843,7 +843,7 @@ static int tokenizer_init(tokenizer_t *t, const buffer *source, const char *inpu t->offset = 0; t->line = 1; t->line_pos = 1; - + t->in_key = 1; t->in_brace = 0; t->in_cond = 0; @@ -866,7 +866,7 @@ int config_parse_file(server *srv, config_t *context, const char *fn) { } if (0 != stream_open(&s, filename)) { - log_error_write(srv, __FILE__, __LINE__, "sbss", + log_error_write(srv, __FILE__, __LINE__, "sbss", "opening configfile ", filename, "failed:", strerror(errno)); ret = -1; } else { @@ -888,7 +888,7 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) { char oldpwd[PATH_MAX]; if (NULL == getcwd(oldpwd, sizeof(oldpwd))) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "cannot get cwd", strerror(errno)); return -1; } @@ -901,7 +901,7 @@ int config_parse_cmd(server *srv, config_t *context, const char *cmd) { } if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) { - log_error_write(srv, __FILE__, __LINE__, "sbss", + log_error_write(srv, __FILE__, __LINE__, "sbss", "opening", source, "failed:", strerror(errno)); ret = -1; } else { @@ -951,7 +951,7 @@ int config_read(server *srv, const char *fn) { buffer_copy_string_len(context.basedir, fn, pos - fn + 1); fn = pos + 1; } - + dc = data_config_init(); buffer_copy_string(dc->key, "global"); @@ -966,7 +966,7 @@ int config_read(server *srv, const char *fn) { dpid->value = getpid(); buffer_copy_string(dpid->key, "var.PID"); array_insert_unique(srv->config, (data_unset *)dpid); - + dcwd = data_string_init(); buffer_prepare_copy(dcwd->value, 1024); if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) { @@ -990,7 +990,7 @@ int config_read(server *srv, const char *fn) { } else { return -1; } - + if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) { data_string *ds; data_array *prepends; @@ -1048,12 +1048,12 @@ int config_read(server *srv, const char *fn) { buffer_copy_string(modules->key, "server.modules"); array_insert_unique(srv->config, (data_unset *)modules); } - + if (0 != config_insert(srv)) { return -1; } - + return 0; } @@ -1061,9 +1061,9 @@ int config_set_defaults(server *srv) { size_t i; specific_config *s = srv->config_storage[0]; struct stat st1, st2; - - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = - { + + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = + { /* - poll is most reliable * - select works everywhere * - linux-* are experimental @@ -1089,20 +1089,20 @@ int config_set_defaults(server *srv) { #endif { FDEVENT_HANDLER_UNSET, NULL } }; - - - if (buffer_is_empty(s->document_root)) { - log_error_write(srv, __FILE__, __LINE__, "s", - "a default document-root has to be set"); - - return -1; - } - + + + if (buffer_is_empty(s->document_root)) { + log_error_write(srv, __FILE__, __LINE__, "s", + "a default document-root has to be set"); + + return -1; + } + if (buffer_is_empty(srv->srvconf.changeroot)) { - if (-1 == stat(s->document_root->ptr, &st1)) { - log_error_write(srv, __FILE__, __LINE__, "sb", + if (-1 == stat(s->document_root->ptr, &st1)) { + log_error_write(srv, __FILE__, __LINE__, "sb", "base-docroot doesn't exist:", - s->document_root); + s->document_root); return -1; } @@ -1110,18 +1110,18 @@ int config_set_defaults(server *srv) { buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot); buffer_append_string_buffer(srv->tmp_buf, s->document_root); - if (-1 == stat(srv->tmp_buf->ptr, &st1)) { - log_error_write(srv, __FILE__, __LINE__, "sb", + if (-1 == stat(srv->tmp_buf->ptr, &st1)) { + log_error_write(srv, __FILE__, __LINE__, "sb", "base-docroot doesn't exist:", - srv->tmp_buf); + srv->tmp_buf); return -1; } - + } - - buffer_copy_string_buffer(srv->tmp_buf, s->document_root); - buffer_to_lower(srv->tmp_buf); + buffer_copy_string_buffer(srv->tmp_buf, s->document_root); + + buffer_to_lower(srv->tmp_buf); if (0 == stat(srv->tmp_buf->ptr, &st1)) { int is_lower = 0; @@ -1129,68 +1129,68 @@ int config_set_defaults(server *srv) { is_lower = buffer_is_equal(srv->tmp_buf, s->document_root); /* lower-case existed, check upper-case */ - buffer_copy_string_buffer(srv->tmp_buf, s->document_root); + buffer_copy_string_buffer(srv->tmp_buf, s->document_root); - buffer_to_upper(srv->tmp_buf); + buffer_to_upper(srv->tmp_buf); /* we have to handle the special case that upper and lower-casing results in the same filename * as in server.document-root = "/" or "/12345/" */ if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) { - /* lower-casing and upper-casing didn't result in - * an other filename, no need to stat(), + /* lower-casing and upper-casing didn't result in + * an other filename, no need to stat(), * just assume it is case-sensitive. */ s->force_lowercase_filenames = 0; - } else if (0 == stat(srv->tmp_buf->ptr, &st2)) { - - /* upper case exists too, doesn't the FS handle this ? */ - - /* upper and lower have the same inode -> case-insensitve FS */ - - if (st1.st_ino == st2.st_ino) { - /* upper and lower have the same inode -> case-insensitve FS */ - - s->force_lowercase_filenames = 1; - } - } - } - + } else if (0 == stat(srv->tmp_buf->ptr, &st2)) { + + /* upper case exists too, doesn't the FS handle this ? */ + + /* upper and lower have the same inode -> case-insensitve FS */ + + if (st1.st_ino == st2.st_ino) { + /* upper and lower have the same inode -> case-insensitve FS */ + + s->force_lowercase_filenames = 1; + } + } + } + if (srv->srvconf.port == 0) { srv->srvconf.port = s->is_ssl ? 443 : 80; } - + if (srv->srvconf.event_handler->used == 0) { /* choose a good default - * - * the event_handler list is sorted by 'goodness' + * + * the event_handler list is sorted by 'goodness' * taking the first available should be the best solution */ srv->event_handler = event_handlers[0].et; - + if (FDEVENT_HANDLER_UNSET == srv->event_handler) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "sorry, there is no event handler for this system"); - + return -1; } } else { /* * User override */ - + for (i = 0; event_handlers[i].name; i++) { if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) { srv->event_handler = event_handlers[i].et; break; } } - + if (FDEVENT_HANDLER_UNSET == srv->event_handler) { - log_error_write(srv, __FILE__, __LINE__, "sb", - "the selected event-handler in unknown or not supported:", + log_error_write(srv, __FILE__, __LINE__, "sb", + "the selected event-handler in unknown or not supported:", srv->srvconf.event_handler ); - + return -1; } } @@ -1198,19 +1198,19 @@ int config_set_defaults(server *srv) { if (s->is_ssl) { if (buffer_is_empty(s->ssl_pemfile)) { /* PEM file is require */ - - log_error_write(srv, __FILE__, __LINE__, "s", + + log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set"); return -1; } - + #ifndef USE_OPENSSL - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "ssl support is missing, recompile with --with-openssl"); - + return -1; #endif } - + return 0; } diff --git a/src/configparser.c b/src/configparser.c index 266a1c7..292cff0 100644 --- a/src/configparser.c +++ b/src/configparser.c @@ -110,10 +110,10 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { /* Next is all token values, in a form suitable for use by makeheaders. ** This section will be null unless lemon is run with the -m switch. */ -/* +/* ** These constants (all generated automatically by the parser generator) ** specify the various kinds of tokens (terminals) that the parser -** understands. +** understands. ** ** Each symbol here is a terminal symbol in the grammar. */ @@ -130,7 +130,7 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { ** and nonterminals. "int" is used otherwise. ** YYNOCODE is a number of type YYCODETYPE which corresponds ** to no legal terminal or nonterminal number. This -** number is used to fill in empty slots of the hash +** number is used to fill in empty slots of the hash ** table. ** YYFALLBACK If defined, this indicates that one or more tokens ** have fall-back values which should be used if the @@ -139,7 +139,7 @@ data_unset *configparser_merge_data(data_unset *op1, const data_unset *op2) { ** and nonterminal numbers. "unsigned char" is ** used if there are fewer than 250 rules and ** states combined. "int" is used otherwise. -** configparserTOKENTYPE is the data type used for minor tokens given +** configparserTOKENTYPE is the data type used for minor tokens given ** directly to the parser from the tokenizer. ** YYMINORTYPE is the data type used for all minor tokens. ** This is typically a union of many types, one of @@ -185,7 +185,7 @@ typedef union { /* Next are that tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an -** action integer. +** action integer. ** ** Suppose the action integer is N. Then the action is determined as ** follows @@ -210,7 +210,7 @@ typedef union { ** If the index value yy_shift_ofst[S]+X is out of range or if the value ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that yy_default[S] should be used instead. +** and that yy_default[S] should be used instead. ** ** The formula above is for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after @@ -292,7 +292,7 @@ static YYACTIONTYPE yy_default[] = { /* The next table maps tokens into fallback tokens. If a construct ** like the following: -** +** ** %fallback ID X Y Z. ** ** appears in the grammer, then ID becomes a fallback token for X, Y, @@ -343,10 +343,10 @@ static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG -/* +/* ** Turn parser tracing on by giving a stream to which to write the trace ** and a prompt to preface each trace message. Tracing is turned off -** by making either argument NULL +** by making either argument NULL ** ** Inputs: ** <ul> @@ -371,7 +371,7 @@ void configparserTrace(FILE *TraceFILE, char *zTracePrompt){ #ifndef NDEBUG /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ -static const char *yyTokenName[] = { +static const char *yyTokenName[] = { "$", "EOL", "ASSIGN", "APPEND", "LKEY", "PLUS", "STRING", "INTEGER", "LPARAN", "RPARAN", "COMMA", "ARRAY_ASSIGN", @@ -450,7 +450,7 @@ const char *configparserTokenName(int tokenType){ #endif } -/* +/* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like ** malloc. @@ -481,7 +481,7 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen ** when the symbol is popped from the stack during a - ** reduce or during error processing or when a parser is + ** reduce or during error processing or when a parser is ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those @@ -582,7 +582,7 @@ static int yy_pop_parser_stack(yyParser *pParser){ return yymajor; } -/* +/* ** Deallocate and destroy a parser. Destructors are all called for ** all stack elements before shutting the parser down. ** @@ -618,7 +618,7 @@ static int yy_find_shift_action( ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */ i = yy_shift_ofst[stateno]; if( i==YY_SHIFT_USE_DFLT ){ @@ -662,7 +662,7 @@ static int yy_find_reduce_action( ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - + i = yy_reduce_ofst[stateno]; if( i==YY_REDUCE_USE_DFLT ){ return yy_default[stateno]; @@ -786,7 +786,7 @@ static void yy_reduce( configparserARG_FETCH; yymsp = &yypParser->yystack[yypParser->yyidx]; #ifndef NDEBUG - if( yyTraceFILE && yyruleno>=0 + if( yyTraceFILE && yyruleno>=0 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, yyRuleName[yyruleno]); @@ -845,7 +845,7 @@ static void yy_reduce( array_insert_unique(ctx->current->value, yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } else { - fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", + fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", ctx->current->context_ndx, ctx->current->key->ptr, yymsp[0].minor.yy41->key->ptr); ctx->ok = 0; @@ -1024,13 +1024,13 @@ static void yy_reduce( array_insert_unique(yymsp[-2].minor.yy40, yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } else { - fprintf(stderr, "Duplicate array-key: %s\n", + fprintf(stderr, "Duplicate array-key: %s\n", yymsp[0].minor.yy41->key->ptr); ctx->ok = 0; yymsp[0].minor.yy41->free(yymsp[0].minor.yy41); yymsp[0].minor.yy41 = NULL; } - + yygotominor.yy40 = yymsp[-2].minor.yy40; yymsp[-2].minor.yy40 = NULL; } @@ -1069,7 +1069,7 @@ static void yy_reduce( buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43); buffer_free(yymsp[-2].minor.yy43); yymsp[-2].minor.yy43 = NULL; - + yygotominor.yy41 = yymsp[0].minor.yy41; yymsp[0].minor.yy41 = NULL; } @@ -1096,7 +1096,7 @@ static void yy_reduce( #line 336 "./configparser.y" { data_config *cur; - + cur = ctx->current; configparser_pop(ctx); @@ -1136,7 +1136,7 @@ static void yy_reduce( #line 361 "./configparser.y" { data_config *cur; - + cur = ctx->current; configparser_pop(ctx); @@ -1187,7 +1187,7 @@ static void yy_reduce( buffer_append_string_buffer(b, op); rvalue = ((data_string*)yymsp[0].minor.yy41)->value; buffer_append_string_buffer(b, rvalue); - + if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) { configparser_push(ctx, dc, 0); } else { @@ -1209,7 +1209,7 @@ static void yy_reduce( size_t i; dc = data_config_init(); - + buffer_copy_string_buffer(dc->key, b); buffer_copy_string_buffer(dc->op, op); buffer_copy_string_buffer(dc->comp_key, yymsp[-5].minor.yy0); @@ -1217,7 +1217,7 @@ static void yy_reduce( buffer_append_string_buffer(dc->comp_key, yymsp[-3].minor.yy43); buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]")); dc->cond = yymsp[-1].minor.yy27; - + for (i = 0; comps[i].comp_key; i ++) { if (buffer_is_equal_string( dc->comp_key, comps[i].comp_key, comps[i].len)) { @@ -1240,20 +1240,20 @@ static void yy_reduce( #ifdef HAVE_PCRE_H const char *errptr; int erroff; - - if (NULL == (dc->regex = + + if (NULL == (dc->regex = pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) { dc->string = buffer_init_string(errptr); dc->cond = CONFIG_COND_UNSET; - fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n", + fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n", rvalue->ptr, errptr, erroff); ctx->ok = 0; } else if (NULL == (dc->regex_study = - pcre_study(dc->regex, 0, &errptr)) && + pcre_study(dc->regex, 0, &errptr)) && errptr != NULL) { - fprintf(stderr, "studying regex failed: %s -> %s\n", + fprintf(stderr, "studying regex failed: %s -> %s\n", rvalue->ptr, errptr); ctx->ok = 0; } else { @@ -1261,7 +1261,7 @@ static void yy_reduce( } #else fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n" - "(perhaps just a missing pcre-devel package ?) \n", + "(perhaps just a missing pcre-devel package ?) \n", yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr); ctx->ok = 0; #endif @@ -1269,12 +1269,12 @@ static void yy_reduce( } default: - fprintf(stderr, "unknown condition for $%s[%s]\n", + fprintf(stderr, "unknown condition for $%s[%s]\n", yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr); ctx->ok = 0; break; } - + configparser_push(ctx, dc, 1); } @@ -1510,7 +1510,7 @@ void configparser( #ifdef YYERRORSYMBOL /* A syntax error has occurred. ** The response to an error depends upon whether or not the - ** grammar defines an error token "ERROR". + ** grammar defines an error token "ERROR". ** ** This is what we do if the grammar does define ERROR: ** diff --git a/src/configparser.y b/src/configparser.y index 122f424..b5bc785 100644 --- a/src/configparser.y +++ b/src/configparser.y @@ -152,7 +152,7 @@ varline ::= key(A) ASSIGN expression(B). { array_insert_unique(ctx->current->value, B); B = NULL; } else { - fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", + fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n", ctx->current->context_ndx, ctx->current->key->ptr, B->key->ptr); ctx->ok = 0; @@ -288,13 +288,13 @@ aelements(A) ::= aelements(C) COMMA aelement(B). { array_insert_unique(C, B); B = NULL; } else { - fprintf(stderr, "Duplicate array-key: %s\n", + fprintf(stderr, "Duplicate array-key: %s\n", B->key->ptr); ctx->ok = 0; B->free(B); B = NULL; } - + A = C; C = NULL; } @@ -318,7 +318,7 @@ aelement(A) ::= stringop(B) ARRAY_ASSIGN expression(C). { buffer_copy_string_buffer(C->key, B); buffer_free(B); B = NULL; - + A = C; C = NULL; } @@ -335,7 +335,7 @@ globalstart ::= GLOBAL. { global(A) ::= globalstart LCURLY metalines RCURLY. { data_config *cur; - + cur = ctx->current; configparser_pop(ctx); @@ -360,7 +360,7 @@ condlines(A) ::= condline(B). { condline(A) ::= context LCURLY metalines RCURLY. { data_config *cur; - + cur = ctx->current; configparser_pop(ctx); @@ -404,7 +404,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio buffer_append_string_buffer(b, op); rvalue = ((data_string*)D)->value; buffer_append_string_buffer(b, rvalue); - + if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) { configparser_push(ctx, dc, 0); } else { @@ -426,7 +426,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio size_t i; dc = data_config_init(); - + buffer_copy_string_buffer(dc->key, b); buffer_copy_string_buffer(dc->op, op); buffer_copy_string_buffer(dc->comp_key, B); @@ -434,7 +434,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio buffer_append_string_buffer(dc->comp_key, C); buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]")); dc->cond = E; - + for (i = 0; comps[i].comp_key; i ++) { if (buffer_is_equal_string( dc->comp_key, comps[i].comp_key, comps[i].len)) { @@ -457,20 +457,20 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio #ifdef HAVE_PCRE_H const char *errptr; int erroff; - - if (NULL == (dc->regex = + + if (NULL == (dc->regex = pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) { dc->string = buffer_init_string(errptr); dc->cond = CONFIG_COND_UNSET; - fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n", + fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n", rvalue->ptr, errptr, erroff); ctx->ok = 0; } else if (NULL == (dc->regex_study = - pcre_study(dc->regex, 0, &errptr)) && + pcre_study(dc->regex, 0, &errptr)) && errptr != NULL) { - fprintf(stderr, "studying regex failed: %s -> %s\n", + fprintf(stderr, "studying regex failed: %s -> %s\n", rvalue->ptr, errptr); ctx->ok = 0; } else { @@ -478,7 +478,7 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio } #else fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n" - "(perhaps just a missing pcre-devel package ?) \n", + "(perhaps just a missing pcre-devel package ?) \n", B->ptr, C->ptr); ctx->ok = 0; #endif @@ -486,12 +486,12 @@ context ::= DOLLAR SRVVARNAME(B) LBRACKET stringop(C) RBRACKET cond(E) expressio } default: - fprintf(stderr, "unknown condition for $%s[%s]\n", + fprintf(stderr, "unknown condition for $%s[%s]\n", B->ptr, C->ptr); ctx->ok = 0; break; } - + configparser_push(ctx, dc, 1); } diff --git a/src/connections-glue.c b/src/connections-glue.c index ac6d267..89180b4 100644 --- a/src/connections-glue.c +++ b/src/connections-glue.c @@ -13,7 +13,7 @@ const char *connection_get_state(connection_state_t state) { case CON_STATE_REQUEST_END: return "req-end"; case CON_STATE_RESPONSE_START: return "resp-start"; case CON_STATE_RESPONSE_END: return "resp-end"; - default: return "(unknown)"; + default: return "(unknown)"; } } @@ -30,15 +30,15 @@ const char *connection_get_short_state(connection_state_t state) { case CON_STATE_REQUEST_END: return "Q"; case CON_STATE_RESPONSE_START: return "s"; case CON_STATE_RESPONSE_END: return "S"; - default: return "x"; + default: return "x"; } } int connection_set_state(server *srv, connection *con, connection_state_t state) { UNUSED(srv); - + con->state = state; - + return 0; } diff --git a/src/connections.c b/src/connections.c index 4e5a4fb..5596eff 100644 --- a/src/connections.c +++ b/src/connections.c @@ -26,8 +26,8 @@ #include "inet_ntop_cache.h" #ifdef USE_OPENSSL -# include <openssl/ssl.h> -# include <openssl/err.h> +# include <openssl/ssl.h> +# include <openssl/err.h> #endif #ifdef HAVE_SYS_FILIO_H @@ -43,7 +43,7 @@ typedef struct { static connection *connections_get_new_connection(server *srv) { connections *conns = srv->conns; size_t i; - + if (conns->size == 0) { conns->size = 128; conns->ptr = NULL; @@ -54,21 +54,21 @@ static connection *connections_get_new_connection(server *srv) { } else if (conns->size == conns->used) { conns->size += 128; conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size); - + for (i = conns->used; i < conns->size; i++) { conns->ptr[i] = connection_init(srv); } } connection_reset(srv, conns->ptr[conns->used]); -#if 0 +#if 0 fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__); for (i = 0; i < conns->used + 1; i++) { fprintf(stderr, "%d ", conns->ptr[i]->fd); } fprintf(stderr, "\n"); -#endif - +#endif + conns->ptr[conns->used]->ndx = conns->used; return conns->ptr[conns->used++]; } @@ -77,26 +77,26 @@ static int connection_del(server *srv, connection *con) { size_t i; connections *conns = srv->conns; connection *temp; - + if (con == NULL) return -1; - + if (-1 == con->ndx) return -1; - + i = con->ndx; - + /* not last element */ - + if (i != conns->used - 1) { temp = conns->ptr[i]; conns->ptr[i] = conns->ptr[conns->used - 1]; conns->ptr[conns->used - 1] = temp; - + conns->ptr[i]->ndx = i; conns->ptr[conns->used - 1]->ndx = -1; } - + conns->used--; - + con->ndx = -1; #if 0 fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used); @@ -104,7 +104,7 @@ static int connection_del(server *srv, connection *con) { fprintf(stderr, "%d ", conns->ptr[i]->fd); } fprintf(stderr, "\n"); -#endif +#endif return 0; } @@ -112,14 +112,14 @@ int connection_close(server *srv, connection *con) { #ifdef USE_OPENSSL server_socket *srv_sock = con->srv_socket; #endif - + #ifdef USE_OPENSSL if (srv_sock->is_ssl) { if (con->ssl) SSL_free(con->ssl); con->ssl = NULL; } #endif - + fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd); fdevent_unregister(srv->ev, con->fd); #ifdef __WIN32 @@ -133,62 +133,62 @@ int connection_close(server *srv, connection *con) { "(warning) close:", con->fd, strerror(errno)); } #endif - + srv->cur_fds--; #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "closed()", con->fd); #endif - + connection_del(srv, con); connection_set_state(srv, con, CON_STATE_CONNECT); - + return 0; } #if 0 static void dump_packet(const unsigned char *data, size_t len) { size_t i, j; - + if (len == 0) return; - + for (i = 0; i < len; i++) { if (i % 16 == 0) fprintf(stderr, " "); - + fprintf(stderr, "%02x ", data[i]); - + if ((i + 1) % 16 == 0) { fprintf(stderr, " "); for (j = 0; j <= i % 16; j++) { unsigned char c; - + if (i-15+j >= len) break; - + c = data[i-15+j]; - + fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.'); } - + fprintf(stderr, "\n"); } } - + if (len % 16 != 0) { for (j = i % 16; j < 16; j++) { fprintf(stderr, " "); } - + fprintf(stderr, " "); for (j = i & ~0xf; j < len; j++) { unsigned char c; - + c = data[j]; fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.'); } fprintf(stderr, "\n"); } } -#endif +#endif static int connection_handle_read_ssl(server *srv, connection *con) { #ifdef USE_OPENSSL @@ -216,10 +216,10 @@ static int connection_handle_read_ssl(server *srv, connection *con) { if (len > 0) { b->used = len; b->ptr[b->used++] = '\0'; - + /* we move the buffer to the chunk-queue, no need to free it */ - chunkqueue_append_buffer_weak(con->read_queue, b); + chunkqueue_append_buffer_weak(con->read_queue, b); con->bytes_read += len; b = NULL; } @@ -240,52 +240,52 @@ static int connection_handle_read_ssl(server *srv, connection *con) { case SSL_ERROR_SYSCALL: /** * man SSL_get_error() - * + * * SSL_ERROR_SYSCALL - * Some I/O error occurred. The OpenSSL error queue may contain more + * Some I/O error occurred. The OpenSSL error queue may contain more * information on the error. If the error queue is empty (i.e. - * ERR_get_error() returns 0), ret can be used to find out more about + * ERR_get_error() returns 0), ret can be used to find out more about * the error: If ret == 0, an EOF was observed that violates the - * protocol. If ret == -1, the underlying BIO reported an I/O error + * protocol. If ret == -1, the underlying BIO reported an I/O error * (for socket I/O on Unix systems, consult errno for details). * */ while((ssl_err = ERR_get_error())) { /* get all errors from the error-queue */ - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", r, ERR_error_string(ssl_err, NULL)); } switch(errno) { default: - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", len, r, errno, strerror(errno)); break; } - + break; case SSL_ERROR_ZERO_RETURN: /* clean shutdown on the remote side */ - + if (r == 0) { /* FIXME: later */ } - + /* fall thourgh */ default: while((ssl_err = ERR_get_error())) { /* get all errors from the error-queue */ - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", r, ERR_error_string(ssl_err, NULL)); } break; } - + connection_set_state(srv, con, CON_STATE_ERROR); buffer_free(b); - + return -1; } else if (len == 0) { con->is_readable = 0; @@ -318,34 +318,34 @@ static int connection_handle_read(server *srv, connection *con) { len = recv(con->fd, b->ptr, b->size - 1, 0); #else if (ioctl(con->fd, FIONREAD, &toread)) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "unexpected end-of-file:", con->fd); return -1; } b = chunkqueue_get_append_buffer(con->read_queue); - buffer_prepare_copy(b, toread); + buffer_prepare_copy(b, toread + 1); len = read(con->fd, b->ptr, b->size - 1); #endif - + if (len < 0) { con->is_readable = 0; - + if (errno == EAGAIN) return 0; if (errno == EINTR) { /* we have been interrupted before we could read */ con->is_readable = 1; return 0; } - + if (errno != ECONNRESET) { /* expected for keep-alive */ log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno); } connection_set_state(srv, con, CON_STATE_ERROR); - + return -1; } else if (len == 0) { con->is_readable = 0; @@ -356,18 +356,18 @@ static int connection_handle_read(server *srv, connection *con) { return -2; } else if ((size_t)len < b->size - 1) { /* we got less then expected, wait for the next fd-event */ - + con->is_readable = 0; } - + b->used = len; b->ptr[b->used++] = '\0'; - + con->bytes_read += len; #if 0 dump_packet(b->ptr, len); #endif - + return 0; } @@ -385,12 +385,14 @@ static int connection_handle_write_prepare(server *srv, connection *con) { case HTTP_METHOD_MOVE: case HTTP_METHOD_PROPFIND: case HTTP_METHOD_PROPPATCH: + case HTTP_METHOD_LOCK: + case HTTP_METHOD_UNLOCK: break; case HTTP_METHOD_OPTIONS: /* * 400 is coming from the request-parser BEFORE uri.path is set - * 403 is from the response handler when noone else catched it - * + * 403 is from the response handler when noone else catched it + * * */ if (con->uri.path->used && con->uri.path->ptr[0] != '*') { @@ -416,55 +418,56 @@ static int connection_handle_write_prepare(server *srv, connection *con) { break; } } - + if (con->http_status == 0) { con->http_status = 403; } - + switch(con->http_status) { case 400: /* class: header + custom body */ case 401: case 403: case 404: case 408: + case 409: case 411: case 416: case 423: case 500: case 501: case 503: - case 505: + case 505: if (con->mode != DIRECT) break; - + con->file_finished = 0; - + buffer_reset(con->physical.path); - + /* try to send static errorfile */ if (!buffer_is_empty(con->conf.errorfile_prefix)) { stat_cache_entry *sce = NULL; - + buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix); buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status)); - + if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { con->file_finished = 1; - + http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type)); } } - - if (!con->file_finished) { + + if (!con->file_finished) { buffer *b; - + buffer_reset(con->physical.path); - + con->file_finished = 1; b = chunkqueue_get_append_buffer(con->write_queue); - + /* build default error-page */ - buffer_copy_string(b, + buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" @@ -474,7 +477,7 @@ static int connection_handle_write_prepare(server *srv, connection *con) { buffer_append_long(b, con->http_status); buffer_append_string(b, " - "); buffer_append_string(b, get_http_status_name(con->http_status)); - + buffer_append_string(b, "</title>\n" " </head>\n" @@ -483,12 +486,12 @@ static int connection_handle_write_prepare(server *srv, connection *con) { buffer_append_long(b, con->http_status); buffer_append_string(b, " - "); buffer_append_string(b, get_http_status_name(con->http_status)); - - buffer_append_string(b,"</h1>\n" + + buffer_append_string(b,"</h1>\n" " </body>\n" "</html>\n" ); - + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); } /* fall through */ @@ -498,10 +501,10 @@ static int connection_handle_write_prepare(server *srv, connection *con) { case 301: case 302: break; - + case 206: /* write_queue is already prepared */ con->file_finished = 1; - + break; case 205: /* class: header only */ case 304: @@ -509,20 +512,27 @@ static int connection_handle_write_prepare(server *srv, connection *con) { /* disable chunked encoding again as we have no body */ con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; chunkqueue_reset(con->write_queue); - + con->file_finished = 1; break; } - + if (con->file_finished) { - /* we have all the content and chunked encoding is not used, set a content-length */ - - if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && + /* we have all the content and chunked encoding is not used, set a content-length */ + + if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) && (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) { - buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue)); - - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf)); + off_t qlen = chunkqueue_length(con->write_queue); + + /* if we have no content for a GET/PORT request, send Content-Length: 0 + * if it is a HEAD request, don't generate a Content-Length as + * the backend might have already cut it off */ + if (qlen > 0 || con->request.http_method != HTTP_METHOD_HEAD) { + buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue)); + + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf)); + } } } else { /* disable keep-alive if size-info for the body is missing */ @@ -530,34 +540,39 @@ static int connection_handle_write_prepare(server *srv, connection *con) { ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) { con->keep_alive = 0; } - + if (0 == (con->parsed_response & HTTP_CONNECTION)) { /* (f)cgi did'nt send Connection: header - * + * * shall we ? */ if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) && (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) { /* without content_length, no keep-alive */ - + con->keep_alive = 0; } } else { /* a subrequest disable keep-alive although the client wanted it */ if (con->keep_alive && !con->response.keep_alive) { con->keep_alive = 0; - + /* FIXME: we have to drop the Connection: Header from the subrequest */ } } } - + if (con->request.http_method == HTTP_METHOD_HEAD) { + /** + * a HEAD request has the same as a GET + * without the content + */ chunkqueue_reset(con->write_queue); + con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; } http_response_write_header(srv, con); - + return 0; } @@ -581,11 +596,11 @@ static int connection_handle_write(server *srv, connection *con) { break; case 1: con->is_writable = 0; - + /* not finished yet -> WRITE */ break; } - + return 0; } @@ -593,11 +608,11 @@ static int connection_handle_write(server *srv, connection *con) { connection *connection_init(server *srv) { connection *con; - + UNUSED(srv); con = calloc(1, sizeof(*con)); - + con->fd = 0; con->ndx = -1; con->fde_ndx = -1; @@ -608,32 +623,32 @@ connection *connection_init(server *srv) { #define CLEAN(x) \ con->x = buffer_init(); - + CLEAN(request.uri); CLEAN(request.request_line); CLEAN(request.request); CLEAN(request.pathinfo); - + CLEAN(request.orig_uri); - + CLEAN(uri.scheme); CLEAN(uri.authority); CLEAN(uri.path); CLEAN(uri.path_raw); CLEAN(uri.query); - + CLEAN(physical.doc_root); CLEAN(physical.path); CLEAN(physical.basedir); CLEAN(physical.rel_path); CLEAN(physical.etag); CLEAN(parse_request); - + CLEAN(authed_user); CLEAN(server_name); CLEAN(error_handler); CLEAN(dst_addr_buf); - + #undef CLEAN con->write_queue = chunkqueue_init(); con->read_queue = chunkqueue_init(); @@ -643,26 +658,26 @@ connection *connection_init(server *srv) { con->request.headers = array_init(); con->response.headers = array_init(); con->environment = array_init(); - + /* init plugin specific connection structures */ - + con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *)); - + con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t)); config_setup_connection(srv, con); - + return con; } void connections_free(server *srv) { connections *conns = srv->conns; - size_t i; - + size_t i; + for (i = 0; i < conns->size; i++) { connection *con = conns->ptr[i]; - + connection_reset(srv, con); - + chunkqueue_free(con->write_queue); chunkqueue_free(con->read_queue); chunkqueue_free(con->request_content_queue); @@ -672,27 +687,27 @@ void connections_free(server *srv) { #define CLEAN(x) \ buffer_free(con->x); - + CLEAN(request.uri); CLEAN(request.request_line); CLEAN(request.request); CLEAN(request.pathinfo); - + CLEAN(request.orig_uri); - + CLEAN(uri.scheme); CLEAN(uri.authority); CLEAN(uri.path); CLEAN(uri.path_raw); CLEAN(uri.query); - + CLEAN(physical.doc_root); CLEAN(physical.path); CLEAN(physical.basedir); CLEAN(physical.etag); CLEAN(physical.rel_path); CLEAN(parse_request); - + CLEAN(authed_user); CLEAN(server_name); CLEAN(error_handler); @@ -700,97 +715,97 @@ void connections_free(server *srv) { #undef CLEAN free(con->plugin_ctx); free(con->cond_cache); - + free(con); } - + free(conns->ptr); } int connection_reset(server *srv, connection *con) { size_t i; - + plugins_call_connection_reset(srv, con); - + con->is_readable = 1; con->is_writable = 1; con->http_status = 0; con->file_finished = 0; con->file_started = 0; con->got_response = 0; - + con->parsed_response = 0; - + con->bytes_written = 0; con->bytes_written_cur_second = 0; con->bytes_read = 0; con->bytes_header = 0; con->loops_per_request = 0; - + con->request.http_method = HTTP_METHOD_UNSET; con->request.http_version = HTTP_VERSION_UNSET; - + con->request.http_if_modified_since = NULL; con->request.http_if_none_match = NULL; - + con->response.keep_alive = 0; con->response.content_length = -1; con->response.transfer_encoding = 0; - + con->mode = DIRECT; - + #define CLEAN(x) \ if (con->x) buffer_reset(con->x); - + CLEAN(request.uri); CLEAN(request.request_line); CLEAN(request.pathinfo); CLEAN(request.request); - + CLEAN(request.orig_uri); - + CLEAN(uri.scheme); CLEAN(uri.authority); CLEAN(uri.path); CLEAN(uri.path_raw); CLEAN(uri.query); - + CLEAN(physical.doc_root); CLEAN(physical.path); CLEAN(physical.basedir); CLEAN(physical.rel_path); CLEAN(physical.etag); - + CLEAN(parse_request); - + CLEAN(authed_user); CLEAN(server_name); CLEAN(error_handler); -#undef CLEAN - +#undef CLEAN + #define CLEAN(x) \ - if (con->x) con->x->used = 0; - + if (con->x) con->x->used = 0; + #undef CLEAN - + #define CLEAN(x) \ con->request.x = NULL; - + CLEAN(http_host); CLEAN(http_range); CLEAN(http_content_type); #undef CLEAN con->request.content_length = 0; - + array_reset(con->request.headers); array_reset(con->response.headers); array_reset(con->environment); - + chunkqueue_reset(con->write_queue); chunkqueue_reset(con->request_content_queue); - /* the plugins should cleanup themself */ + /* the plugins should cleanup themself */ for (i = 0; i < srv->plugins.used; i++) { plugin *p = ((plugin **)(srv->plugins.ptr))[i]; plugin_data *pd = p->data; @@ -803,7 +818,7 @@ int connection_reset(server *srv, connection *con) { con->plugin_ctx[pd->id] = NULL; } - + #if COND_RESULT_UNSET for (i = srv->config_context->used - 1; i >= 0; i --) { con->cond_cache[i].result = COND_RESULT_UNSET; @@ -819,12 +834,12 @@ int connection_reset(server *srv, connection *con) { con->ssl_error_want_reuse_buffer = NULL; } #endif - + con->header_len = 0; con->in_error_handler = 0; - + config_setup_connection(srv, con); - + return 0; } @@ -834,16 +849,16 @@ int connection_reset(server *srv, connection *con) { * we get called by the state-engine and by the fdevent-handler */ int connection_handle_read_state(server *srv, connection *con) { - int ostate = con->state; + connection_state_t ostate = con->state; chunk *c, *last_chunk; off_t last_offset; chunkqueue *cq = con->read_queue; chunkqueue *dst_cq = con->request_content_queue; int is_closed = 0; /* the connection got closed, if we don't have a complete header, -> error */ - + if (con->is_readable) { con->read_idle_ts = srv->cur_ts; - + switch(connection_handle_read(srv, con)) { case -1: return -1; @@ -884,14 +899,14 @@ int connection_handle_read_state(server *srv, connection *con) { /* the last node was empty */ if (c->next == NULL) { cq->last = c; - } + } c = c->next; } else { c = c->next; } } - + /* we might have got several packets at once */ @@ -911,7 +926,7 @@ int connection_handle_read_state(server *srv, connection *con) { for (c = cq->first; !last_chunk && c; c = c->next) { buffer b; size_t i; - + b.ptr = c->mem->ptr + c->offset; b.used = c->mem->used - c->offset; @@ -926,7 +941,7 @@ int connection_handle_read_state(server *srv, connection *con) { if (have_chars >= 4) { /* all chars are in this buffer */ - + if (0 == strncmp(b.ptr + i, "\r\n\r\n", 4)) { /* found */ last_chunk = c; @@ -949,7 +964,7 @@ int connection_handle_read_state(server *srv, connection *con) { 0 == strncmp(lookahead_chunk->mem->ptr, "\r\n\r\n" + have_chars, missing_chars)) { last_chunk = lookahead_chunk; - last_offset = missing_chars + 1; + last_offset = missing_chars; break; } @@ -971,16 +986,16 @@ int connection_handle_read_state(server *srv, connection *con) { for (c = cq->first; c; c = c->next) { buffer b; - + b.ptr = c->mem->ptr + c->offset; b.used = c->mem->used - c->offset; - + if (c == last_chunk) { b.used = last_offset + 1; } buffer_append_string_buffer(con->request.request, &b); - + if (c == last_chunk) { c->offset += last_offset; @@ -1000,16 +1015,16 @@ int connection_handle_read_state(server *srv, connection *con) { connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); } break; - case CON_STATE_READ_POST: + case CON_STATE_READ_POST: for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) { off_t weWant, weHave, toRead; - + weWant = con->request.content_length - dst_cq->bytes_in; - + assert(c->mem->used); - + weHave = c->mem->used - c->offset - 1; - + toRead = weHave > weWant ? weWant : weHave; /* the new way, copy everything into a chunkqueue whcih might use tempfiles */ @@ -1018,13 +1033,13 @@ int connection_handle_read_state(server *srv, connection *con) { /* copy everything to max 1Mb sized tempfiles */ /* - * if the last chunk is + * if the last chunk is * - smaller than 1Mb (size < 1Mb) * - not read yet (offset == 0) * -> append to it * otherwise - * -> create a new chunk - * + * -> create a new chunk + * * */ if (dst_cq->last && @@ -1057,14 +1072,14 @@ int connection_handle_read_state(server *srv, connection *con) { /* we have a chunk, let's write to it */ if (dst_c->file.fd == -1) { - /* we don't have file to write to, + /* we don't have file to write to, * EACCES might be one reason. * * Instead of sending 500 we send 413 and say the request is too large * */ log_error_write(srv, __FILE__, __LINE__, "sbs", - "denying upload as opening to temp-file for upload failed:", + "denying upload as opening to temp-file for upload failed:", dst_c->file.name, strerror(errno)); con->http_status = 413; /* Request-Entity too large */ @@ -1075,15 +1090,15 @@ int connection_handle_read_state(server *srv, connection *con) { } if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) { - /* write failed for some reason ... disk full ? */ + /* write failed for some reason ... disk full ? */ log_error_write(srv, __FILE__, __LINE__, "sbs", - "denying upload as writing to file failed:", + "denying upload as writing to file failed:", dst_c->file.name, strerror(errno)); - + con->http_status = 413; /* Request-Entity too large */ con->keep_alive = 0; connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); - + close(dst_c->file.fd); dst_c->file.fd = -1; @@ -1091,7 +1106,7 @@ int connection_handle_read_state(server *srv, connection *con) { } dst_c->file.length += toRead; - + if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) { /* we read everything, close the chunk */ close(dst_c->file.fd); @@ -1103,7 +1118,7 @@ int connection_handle_read_state(server *srv, connection *con) { b = chunkqueue_get_append_buffer(dst_cq); buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead); } - + c->offset += toRead; dst_cq->bytes_in += toRead; } @@ -1112,8 +1127,9 @@ int connection_handle_read_state(server *srv, connection *con) { if (dst_cq->bytes_in == (off_t)con->request.content_length) { connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); } - + break; + default: break; } /* the connection got closed and we didn't got enough data to leave one of the READ states @@ -1130,9 +1146,9 @@ int connection_handle_read_state(server *srv, connection *con) { handler_t connection_handle_fdevent(void *s, void *context, int revents) { server *srv = (server *)s; connection *con = context; - + joblist_append(srv, con); - + if (revents & FDEVENT_IN) { con->is_readable = 1; #if 0 @@ -1143,19 +1159,19 @@ handler_t connection_handle_fdevent(void *s, void *context, int revents) { con->is_writable = 1; /* we don't need the event twice */ } - - + + if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) { /* looks like an error */ - + /* FIXME: revents = 0x19 still means that we should read from the queue */ if (revents & FDEVENT_HUP) { if (con->state == CON_STATE_CLOSE) { con->close_timeout_ts = 0; } else { /* sigio reports the wrong event here - * - * there was no HUP at all + * + * there was no HUP at all */ #ifdef USE_LINUX_SIGIO if (srv->ev->in_sigio == 1) { @@ -1167,32 +1183,32 @@ handler_t connection_handle_fdevent(void *s, void *context, int revents) { #else connection_set_state(srv, con, CON_STATE_ERROR); #endif - + } } else if (revents & FDEVENT_ERR) { #ifndef USE_LINUX_SIGIO log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed: poll() -> ERR", con->fd); -#endif +#endif connection_set_state(srv, con, CON_STATE_ERROR); } else { log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed: poll() -> ???", revents); - } + } } - + if (con->state == CON_STATE_READ || con->state == CON_STATE_READ_POST) { connection_handle_read_state(srv, con); } - + if (con->state == CON_STATE_WRITE && !chunkqueue_is_empty(con->write_queue) && con->is_writable) { - + if (-1 == connection_handle_write(srv, con)) { connection_set_state(srv, con, CON_STATE_ERROR); - + log_error_write(srv, __FILE__, __LINE__, "ds", con->fd, "handle write failed."); @@ -1200,30 +1216,30 @@ handler_t connection_handle_fdevent(void *s, void *context, int revents) { con->write_request_ts = srv->cur_ts; } } - + if (con->state == CON_STATE_CLOSE) { /* flush the read buffers */ int b; - + if (ioctl(con->fd, FIONREAD, &b)) { log_error_write(srv, __FILE__, __LINE__, "ss", "ioctl() failed", strerror(errno)); } - + if (b > 0) { char buf[1024]; log_error_write(srv, __FILE__, __LINE__, "sdd", "CLOSE-read()", con->fd, b); - + /* */ read(con->fd, buf, sizeof(buf)); } else { /* nothing to read */ - + con->close_timeout_ts = 0; } } - + return HANDLER_FINISHED; } @@ -1236,7 +1252,7 @@ connection *connection_accept(server *srv, server_socket *srv_socket) { sock_addr cnt_addr; socklen_t cnt_len; /* accept it and register the fd */ - + cnt_len = sizeof(cnt_addr); if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) { @@ -1256,32 +1272,32 @@ connection *connection_accept(server *srv, server_socket *srv_socket) { return NULL; } else { connection *con; - + srv->cur_fds++; - + /* ok, we have the connection, register it */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "appected()", cnt); #endif srv->con_opened++; - + con = connections_get_new_connection(srv); - + con->fd = cnt; con->fde_ndx = -1; -#if 0 +#if 0 gettimeofday(&(con->start_tv), NULL); -#endif +#endif fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con); - + connection_set_state(srv, con, CON_STATE_REQUEST_START); - + con->connection_start = srv->cur_ts; con->dst_addr = cnt_addr; buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); con->srv_socket = srv_socket; - + if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); return NULL; @@ -1290,17 +1306,17 @@ connection *connection_accept(server *srv, server_socket *srv_socket) { /* connect FD to SSL */ if (srv_socket->is_ssl) { if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) { - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); - + return NULL; } - + SSL_set_accept_state(con->ssl); con->conf.is_ssl=1; - + if (1 != (SSL_set_fd(con->ssl, cnt))) { - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return NULL; } @@ -1316,10 +1332,10 @@ int connection_state_machine(server *srv, connection *con) { #ifdef USE_OPENSSL server_socket *srv_sock = con->srv_socket; #endif - + if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", - "state at start", + log_error_write(srv, __FILE__, __LINE__, "sds", + "state at start", con->fd, connection_get_state(con->state)); } @@ -1327,20 +1343,20 @@ int connection_state_machine(server *srv, connection *con) { while (done == 0) { size_t ostate = con->state; int b; - + switch (con->state) { case CON_STATE_REQUEST_START: /* transient */ if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + con->request_start = srv->cur_ts; con->read_idle_ts = srv->cur_ts; - + con->request_count++; con->loops_per_request = 0; - + connection_set_state(srv, con, CON_STATE_READ); /* patch con->conf.is_ssl if the connection is a ssl-socket already */ @@ -1348,103 +1364,96 @@ int connection_state_machine(server *srv, connection *con) { #ifdef USE_OPENSSL con->conf.is_ssl = srv_sock->is_ssl; #endif - + break; case CON_STATE_REQUEST_END: /* transient */ if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + if (http_request_parse(srv, con)) { /* we have to read some data from the POST request */ - + connection_set_state(srv, con, CON_STATE_READ_POST); break; } - + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); - + break; case CON_STATE_HANDLE_REQUEST: - /* + /* * the request is parsed - * + * * decided what to do with the request - * - - * - * + * - + * + * */ - + if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + switch (r = http_response_prepare(srv, con)) { case HANDLER_FINISHED: if (con->http_status == 404 || con->http_status == 403) { /* 404 error-handler */ - - if (con->in_error_handler == 0 && + + if (con->in_error_handler == 0 && (!buffer_is_empty(con->conf.error_handler) || !buffer_is_empty(con->error_handler))) { /* call error-handler */ - + con->error_handler_saved_status = con->http_status; con->http_status = 0; - + if (buffer_is_empty(con->error_handler)) { buffer_copy_string_buffer(con->request.uri, con->conf.error_handler); } else { buffer_copy_string_buffer(con->request.uri, con->error_handler); } buffer_reset(con->physical.path); - + con->in_error_handler = 1; - + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); - + done = -1; break; } else if (con->in_error_handler) { /* error-handler is a 404 */ - - /* continue as normal, status is the same */ - log_error_write(srv, __FILE__, __LINE__, "sb", - "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri); - log_error_write(srv, __FILE__, __LINE__, "sd", - "returning the original status", con->error_handler_saved_status); - log_error_write(srv, __FILE__, __LINE__, "s", - "If this is a rails app: check your production.log"); + con->http_status = con->error_handler_saved_status; } } else if (con->in_error_handler) { /* error-handler is back and has generated content */ /* if Status: was set, take it otherwise use 200 */ } - + if (con->http_status == 0) con->http_status = 200; - + /* we have something to send, go on */ connection_set_state(srv, con, CON_STATE_RESPONSE_START); break; case HANDLER_WAIT_FOR_FD: srv->want_fds++; - + fdwaitqueue_append(srv, con); - + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); - + break; case HANDLER_COMEBACK: done = -1; case HANDLER_WAIT_FOR_EVENT: /* come back here */ connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); - + break; case HANDLER_ERROR: /* something went wrong */ @@ -1454,44 +1463,44 @@ int connection_state_machine(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r); break; } - + break; case CON_STATE_RESPONSE_START: - /* + /* * the decision is done * - create the HTTP-Response-Header - * + * */ - + if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + if (-1 == connection_handle_write_prepare(srv, con)) { connection_set_state(srv, con, CON_STATE_ERROR); - + break; } - + connection_set_state(srv, con, CON_STATE_WRITE); break; case CON_STATE_RESPONSE_END: /* transient */ /* log the request */ - + if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + plugins_call_handle_request_done(srv, con); - + srv->con_written++; - + if (con->keep_alive) { connection_set_state(srv, con, CON_STATE_REQUEST_START); - -#if 0 + +#if 0 con->request_start = srv->cur_ts; con->read_idle_ts = srv->cur_ts; #endif @@ -1504,7 +1513,7 @@ int connection_state_machine(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r); break; } - + #ifdef USE_OPENSSL if (srv_sock->is_ssl) { switch (SSL_shutdown(con->ssl)) { @@ -1512,44 +1521,44 @@ int connection_state_machine(server *srv, connection *con) { /* done */ break; case 0: - /* wait for fd-event - * + /* wait for fd-event + * * FIXME: wait for fdevent and call SSL_shutdown again - * + * */ - + break; default: - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); } } #endif connection_close(srv, con); - + srv->con_closed++; } - + connection_reset(srv, con); - + break; case CON_STATE_CONNECT: if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + chunkqueue_reset(con->read_queue); - + con->request_count = 0; - + break; case CON_STATE_CLOSE: if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + if (con->keep_alive) { if (ioctl(con->fd, FIONREAD, &b)) { log_error_write(srv, __FILE__, __LINE__, "ss", @@ -1559,43 +1568,43 @@ int connection_state_machine(server *srv, connection *con) { char buf[1024]; log_error_write(srv, __FILE__, __LINE__, "sdd", "CLOSE-read()", con->fd, b); - + /* */ read(con->fd, buf, sizeof(buf)); } else { /* nothing to read */ - + con->close_timeout_ts = 0; } } else { con->close_timeout_ts = 0; } - + if (srv->cur_ts - con->close_timeout_ts > 1) { connection_close(srv, con); - + if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed for fd", con->fd); } } - + break; case CON_STATE_READ_POST: case CON_STATE_READ: if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + connection_handle_read_state(srv, con); break; case CON_STATE_WRITE: if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "state for fd", con->fd, connection_get_state(con->state)); } - + /* only try to write if we have something in the queue */ if (!chunkqueue_is_empty(con->write_queue)) { #if 0 @@ -1615,10 +1624,10 @@ int connection_state_machine(server *srv, connection *con) { con->write_request_ts = srv->cur_ts; } } - + break; case CON_STATE_ERROR: /* transient */ - + /* even if the connection was drop we still have to write it to the access log */ if (con->http_status) { plugins_call_handle_request_done(srv, con); @@ -1634,19 +1643,19 @@ int connection_state_machine(server *srv, connection *con) { SSL_shutdown(con->ssl); break; default: - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", - SSL_get_error(con->ssl, ret), + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:", + SSL_get_error(con->ssl, ret), ERR_error_string(ERR_get_error(), NULL)); return -1; } } #endif - + switch(con->mode) { case DIRECT: #if 0 - log_error_write(srv, __FILE__, __LINE__, "sd", - "emergency exit: direct", + log_error_write(srv, __FILE__, __LINE__, "sd", + "emergency exit: direct", con->fd); #endif break; @@ -1661,35 +1670,35 @@ int connection_state_machine(server *srv, connection *con) { } break; } - + connection_reset(srv, con); - + /* close the connection */ if ((con->keep_alive == 1) && (0 == shutdown(con->fd, SHUT_WR))) { con->close_timeout_ts = srv->cur_ts; connection_set_state(srv, con, CON_STATE_CLOSE); - + if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "shutdown for fd", con->fd); } } else { connection_close(srv, con); } - + con->keep_alive = 0; - + srv->con_closed++; - + break; default: - log_error_write(srv, __FILE__, __LINE__, "sdd", + log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown state:", con->fd, con->state); - + break; } - + if (done == -1) { done = 0; } else if (ostate == con->state) { @@ -1698,12 +1707,12 @@ int connection_state_machine(server *srv, connection *con) { } if (srv->srvconf.log_state_handling) { - log_error_write(srv, __FILE__, __LINE__, "sds", - "state at exit:", + log_error_write(srv, __FILE__, __LINE__, "sds", + "state at exit:", con->fd, connection_get_state(con->state)); } - + switch(con->state) { case CON_STATE_READ_POST: case CON_STATE_READ: @@ -1711,11 +1720,11 @@ int connection_state_machine(server *srv, connection *con) { fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN); break; case CON_STATE_WRITE: - /* request write-fdevent only if we really need it + /* request write-fdevent only if we really need it * - if we have data to write - * - if the socket is not writable yet + * - if the socket is not writable yet */ - if (!chunkqueue_is_empty(con->write_queue) && + if (!chunkqueue_is_empty(con->write_queue) && (con->is_writable == 0) && (con->traffic_limit_reached == 0)) { fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT); diff --git a/src/data_array.c b/src/data_array.c index 9dfa6fd..c07effb 100644 --- a/src/data_array.c +++ b/src/data_array.c @@ -17,16 +17,16 @@ static data_unset *data_array_copy(const data_unset *s) { static void data_array_free(data_unset *d) { data_array *ds = (data_array *)d; - + buffer_free(ds->key); array_free(ds->value); - + free(d); } static void data_array_reset(data_unset *d) { data_array *ds = (data_array *)d; - + /* reused array elements */ buffer_reset(ds->key); array_reset(ds->value); @@ -36,7 +36,7 @@ static int data_array_insert_dup(data_unset *dst, data_unset *src) { UNUSED(dst); src->free(src); - + return 0; } @@ -48,18 +48,18 @@ static void data_array_print(const data_unset *d, int depth) { data_array *data_array_init(void) { data_array *ds; - + ds = calloc(1, sizeof(*ds)); - + ds->key = buffer_init(); ds->value = array_init(); - + ds->copy = data_array_copy; ds->free = data_array_free; ds->reset = data_array_reset; ds->insert_dup = data_array_insert_dup; ds->print = data_array_print; ds->type = TYPE_ARRAY; - + return ds; } diff --git a/src/data_config.c b/src/data_config.c index 03595a3..a3b8cff 100644 --- a/src/data_config.c +++ b/src/data_config.c @@ -17,26 +17,26 @@ static data_unset *data_config_copy(const data_unset *s) { static void data_config_free(data_unset *d) { data_config *ds = (data_config *)d; - + buffer_free(ds->key); buffer_free(ds->op); buffer_free(ds->comp_key); - + array_free(ds->value); array_free(ds->childs); - + if (ds->string) buffer_free(ds->string); #ifdef HAVE_PCRE_H if (ds->regex) pcre_free(ds->regex); if (ds->regex_study) pcre_free(ds->regex_study); #endif - + free(d); } static void data_config_reset(data_unset *d) { data_config *ds = (data_config *)d; - + /* reused array elements */ buffer_reset(ds->key); buffer_reset(ds->comp_key); @@ -45,9 +45,9 @@ static void data_config_reset(data_unset *d) { static int data_config_insert_dup(data_unset *dst, data_unset *src) { UNUSED(dst); - + src->free(src); - + return 0; } @@ -56,7 +56,7 @@ static void data_config_print(const data_unset *d, int depth) { array *a = (array *)ds->value; size_t i; size_t maxlen; - + if (0 == ds->context_ndx) { fprintf(stdout, "config {\n"); } @@ -117,22 +117,22 @@ static void data_config_print(const data_unset *d, int depth) { data_config *data_config_init(void) { data_config *ds; - + ds = calloc(1, sizeof(*ds)); - + ds->key = buffer_init(); ds->op = buffer_init(); ds->comp_key = buffer_init(); ds->value = array_init(); ds->childs = array_init(); ds->childs->is_weakref = 1; - + ds->copy = data_config_copy; ds->free = data_config_free; ds->reset = data_config_reset; ds->insert_dup = data_config_insert_dup; ds->print = data_config_print; ds->type = TYPE_CONFIG; - + return ds; } diff --git a/src/data_count.c b/src/data_count.c index fbc35e0..5c5a5f0 100644 --- a/src/data_count.c +++ b/src/data_count.c @@ -16,53 +16,53 @@ static data_unset *data_count_copy(const data_unset *s) { static void data_count_free(data_unset *d) { data_count *ds = (data_count *)d; - + buffer_free(ds->key); - + free(d); } static void data_count_reset(data_unset *d) { data_count *ds = (data_count *)d; - + buffer_reset(ds->key); - + ds->count = 0; } static int data_count_insert_dup(data_unset *dst, data_unset *src) { data_count *ds_dst = (data_count *)dst; data_count *ds_src = (data_count *)src; - + ds_dst->count += ds_src->count; - + src->free(src); - + return 0; } static void data_count_print(const data_unset *d, int depth) { data_count *ds = (data_count *)d; UNUSED(depth); - + fprintf(stdout, "count(%d)", ds->count); } data_count *data_count_init(void) { data_count *ds; - + ds = calloc(1, sizeof(*ds)); - + ds->key = buffer_init(); ds->count = 1; - + ds->copy = data_count_copy; ds->free = data_count_free; ds->reset = data_count_reset; ds->insert_dup = data_count_insert_dup; ds->print = data_count_print; ds->type = TYPE_COUNT; - + return ds; } diff --git a/src/data_fastcgi.c b/src/data_fastcgi.c index ad981bf..83e9266 100644 --- a/src/data_fastcgi.c +++ b/src/data_fastcgi.c @@ -17,53 +17,53 @@ static data_unset *data_fastcgi_copy(const data_unset *s) { static void data_fastcgi_free(data_unset *d) { data_fastcgi *ds = (data_fastcgi *)d; - + buffer_free(ds->key); buffer_free(ds->host); - + free(d); } static void data_fastcgi_reset(data_unset *d) { data_fastcgi *ds = (data_fastcgi *)d; - + buffer_reset(ds->key); buffer_reset(ds->host); - + } static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) { UNUSED(dst); src->free(src); - + return 0; } static void data_fastcgi_print(const data_unset *d, int depth) { data_fastcgi *ds = (data_fastcgi *)d; UNUSED(depth); - + fprintf(stdout, "fastcgi(%s)", ds->host->ptr); } data_fastcgi *data_fastcgi_init(void) { data_fastcgi *ds; - + ds = calloc(1, sizeof(*ds)); - + ds->key = buffer_init(); ds->host = buffer_init(); ds->port = 0; ds->is_disabled = 0; - + ds->copy = data_fastcgi_copy; ds->free = data_fastcgi_free; ds->reset = data_fastcgi_reset; ds->insert_dup = data_fastcgi_insert_dup; ds->print = data_fastcgi_print; ds->type = TYPE_FASTCGI; - + return ds; } diff --git a/src/data_integer.c b/src/data_integer.c index c557b90..5423407 100644 --- a/src/data_integer.c +++ b/src/data_integer.c @@ -16,15 +16,15 @@ static data_unset *data_integer_copy(const data_unset *s) { static void data_integer_free(data_unset *d) { data_integer *ds = (data_integer *)d; - + buffer_free(ds->key); - + free(d); } static void data_integer_reset(data_unset *d) { data_integer *ds = (data_integer *)d; - + /* reused integer elements */ buffer_reset(ds->key); ds->value = 0; @@ -32,9 +32,9 @@ static void data_integer_reset(data_unset *d) { static int data_integer_insert_dup(data_unset *dst, data_unset *src) { UNUSED(dst); - + src->free(src); - + return 0; } @@ -48,18 +48,18 @@ static void data_integer_print(const data_unset *d, int depth) { data_integer *data_integer_init(void) { data_integer *ds; - + ds = calloc(1, sizeof(*ds)); - + ds->key = buffer_init(); ds->value = 0; - + ds->copy = data_integer_copy; ds->free = data_integer_free; ds->reset = data_integer_reset; ds->insert_dup = data_integer_insert_dup; ds->print = data_integer_print; ds->type = TYPE_INTEGER; - + return ds; } diff --git a/src/data_string.c b/src/data_string.c index 391af9e..e7aab1a 100644 --- a/src/data_string.c +++ b/src/data_string.c @@ -17,16 +17,16 @@ static data_unset *data_string_copy(const data_unset *s) { static void data_string_free(data_unset *d) { data_string *ds = (data_string *)d; - + buffer_free(ds->key); buffer_free(ds->value); - + free(d); } static void data_string_reset(data_unset *d) { data_string *ds = (data_string *)d; - + /* reused array elements */ buffer_reset(ds->key); buffer_reset(ds->value); @@ -35,23 +35,23 @@ static void data_string_reset(data_unset *d) { static int data_string_insert_dup(data_unset *dst, data_unset *src) { data_string *ds_dst = (data_string *)dst; data_string *ds_src = (data_string *)src; - + if (ds_dst->value->used) { buffer_append_string(ds_dst->value, ", "); buffer_append_string_buffer(ds_dst->value, ds_src->value); } else { buffer_copy_string_buffer(ds_dst->value, ds_src->value); } - + src->free(src); - + return 0; } static int data_response_insert_dup(data_unset *dst, data_unset *src) { data_string *ds_dst = (data_string *)dst; data_string *ds_src = (data_string *)src; - + if (ds_dst->value->used) { buffer_append_string(ds_dst->value, "\r\n"); buffer_append_string_buffer(ds_dst->value, ds_dst->key); @@ -60,9 +60,9 @@ static int data_response_insert_dup(data_unset *dst, data_unset *src) { } else { buffer_copy_string_buffer(ds_dst->value, ds_src->value); } - + src->free(src); - + return 0; } @@ -77,28 +77,28 @@ static void data_string_print(const data_unset *d, int depth) { data_string *data_string_init(void) { data_string *ds; - + ds = calloc(1, sizeof(*ds)); assert(ds); - + ds->key = buffer_init(); ds->value = buffer_init(); - + ds->copy = data_string_copy; ds->free = data_string_free; ds->reset = data_string_reset; ds->insert_dup = data_string_insert_dup; ds->print = data_string_print; ds->type = TYPE_STRING; - + return ds; } data_string *data_response_init(void) { data_string *ds; - + ds = data_string_init(); ds->insert_dup = data_response_insert_dup; - + return ds; } @@ -14,19 +14,19 @@ int etag_create(buffer *etag, struct stat *st) { buffer_append_off_t(etag, st->st_size); buffer_append_string_len(etag, CONST_STR_LEN("-")); buffer_append_long(etag, st->st_mtime); - + return 0; } int etag_mutate(buffer *mut, buffer *etag) { size_t h, i; - + for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]); - + buffer_reset(mut); buffer_copy_string_len(mut, CONST_STR_LEN("\"")); buffer_append_long(mut, h); buffer_append_string_len(mut, CONST_STR_LEN("\"")); - + return 0; } @@ -10,6 +10,6 @@ int etag_is_equal(buffer *etag, const char *matches); int etag_create(buffer *etag, struct stat *st); int etag_mutate(buffer *mut, buffer *etag); - + #endif diff --git a/src/fastcgi.h b/src/fastcgi.h index 15f1dea..31c00ad 100644 --- a/src/fastcgi.h +++ b/src/fastcgi.h @@ -1,4 +1,4 @@ -/* +/* * fastcgi.h -- * * Defines for the FastCGI protocol. @@ -123,7 +123,7 @@ typedef struct { typedef struct { - unsigned char type; + unsigned char type; unsigned char reserved[7]; } FCGI_UnknownTypeBody; diff --git a/src/fdevent.c b/src/fdevent.c index fdf834f..e59e110 100644 --- a/src/fdevent.c +++ b/src/fdevent.c @@ -14,57 +14,57 @@ fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) { fdevents *ev; - + ev = calloc(1, sizeof(*ev)); ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray)); ev->maxfds = maxfds; - + switch(type) { case FDEVENT_HANDLER_POLL: if (0 != fdevent_poll_init(ev)) { - fprintf(stderr, "%s.%d: event-handler poll failed\n", + fprintf(stderr, "%s.%d: event-handler poll failed\n", __FILE__, __LINE__); - + return NULL; } break; case FDEVENT_HANDLER_SELECT: if (0 != fdevent_select_init(ev)) { - fprintf(stderr, "%s.%d: event-handler select failed\n", + fprintf(stderr, "%s.%d: event-handler select failed\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_LINUX_RTSIG: if (0 != fdevent_linux_rtsig_init(ev)) { - fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", + fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_LINUX_SYSEPOLL: if (0 != fdevent_linux_sysepoll_init(ev)) { - fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", + fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_SOLARIS_DEVPOLL: if (0 != fdevent_solaris_devpoll_init(ev)) { - fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", + fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } break; case FDEVENT_HANDLER_FREEBSD_KQUEUE: if (0 != fdevent_freebsd_kqueue_init(ev)) { - fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", + fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } break; default: - fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", + fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); return NULL; } @@ -75,26 +75,26 @@ fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) { void fdevent_free(fdevents *ev) { size_t i; if (!ev) return; - + if (ev->free) ev->free(ev); - + for (i = 0; i < ev->maxfds; i++) { if (ev->fdarray[i]) free(ev->fdarray[i]); } - + free(ev->fdarray); free(ev); } int fdevent_reset(fdevents *ev) { if (ev->reset) return ev->reset(ev); - + return 0; } fdnode *fdnode_init() { fdnode *fdn; - + fdn = calloc(1, sizeof(*fdn)); fdn->fd = -1; return fdn; @@ -106,12 +106,12 @@ void fdnode_free(fdnode *fdn) { int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) { fdnode *fdn; - + fdn = fdnode_init(); fdn->handler = handler; fdn->fd = fd; fdn->ctx = ctx; - + ev->fdarray[fd] = fdn; return 0; @@ -121,31 +121,31 @@ int fdevent_unregister(fdevents *ev, int fd) { fdnode *fdn; if (!ev) return 0; fdn = ev->fdarray[fd]; - + fdnode_free(fdn); - + ev->fdarray[fd] = NULL; - + return 0; } int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) { int fde = fde_ndx ? *fde_ndx : -1; - + if (ev->event_del) fde = ev->event_del(ev, fde, fd); - + if (fde_ndx) *fde_ndx = fde; - + return 0; } int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) { int fde = fde_ndx ? *fde_ndx : -1; - + if (ev->event_add) fde = ev->event_add(ev, fde, fd, events); - + if (fde_ndx) *fde_ndx = fde; - + return 0; } @@ -156,27 +156,27 @@ int fdevent_poll(fdevents *ev, int timeout_ms) { int fdevent_event_get_revent(fdevents *ev, size_t ndx) { if (ev->event_get_revent == NULL) SEGFAULT(); - + return ev->event_get_revent(ev, ndx); } int fdevent_event_get_fd(fdevents *ev, size_t ndx) { if (ev->event_get_fd == NULL) SEGFAULT(); - + return ev->event_get_fd(ev, ndx); } fdevent_handler fdevent_get_handler(fdevents *ev, int fd) { if (ev->fdarray[fd] == NULL) SEGFAULT(); if (ev->fdarray[fd]->fd != fd) SEGFAULT(); - + return ev->fdarray[fd]->handler; } void * fdevent_get_context(fdevents *ev, int fd) { if (ev->fdarray[fd] == NULL) SEGFAULT(); if (ev->fdarray[fd]->fd != fd) SEGFAULT(); - + return ev->fdarray[fd]->ctx; } @@ -186,7 +186,7 @@ int fdevent_fcntl_set(fdevents *ev, int fd) { fcntl(fd, F_SETFD, FD_CLOEXEC); #endif if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd); -#ifdef O_NONBLOCK +#ifdef O_NONBLOCK return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR); #else return 0; @@ -196,7 +196,7 @@ int fdevent_fcntl_set(fdevents *ev, int fd) { int fdevent_event_next_fdndx(fdevents *ev, int ndx) { if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx); - + return -1; } diff --git a/src/fdevent.h b/src/fdevent.h index 0bc05ca..5629e9c 100644 --- a/src/fdevent.h +++ b/src/fdevent.h @@ -17,13 +17,13 @@ # include <sys/epoll.h> #endif -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes * under /usr/include/sys/ */ #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H)) # define USE_POLL # ifdef HAVE_POLL_H # include <poll.h> -# else +# else # include <sys/poll.h> # endif # if defined HAVE_SIGTIMEDWAIT && defined(__linux__) @@ -67,14 +67,14 @@ typedef handler_t (*fdevent_handler)(void *srv, void *ctx, int revents); #define FDEVENT_HUP BV(4) #define FDEVENT_NVAL BV(5) -typedef enum { FD_EVENT_TYPE_UNSET = -1, - FD_EVENT_TYPE_CONNECTION, - FD_EVENT_TYPE_FCGI_CONNECTION, - FD_EVENT_TYPE_DIRWATCH, - FD_EVENT_TYPE_CGI_CONNECTION +typedef enum { FD_EVENT_TYPE_UNSET = -1, + FD_EVENT_TYPE_CONNECTION, + FD_EVENT_TYPE_FCGI_CONNECTION, + FD_EVENT_TYPE_DIRWATCH, + FD_EVENT_TYPE_CGI_CONNECTION } fd_event_t; -typedef enum { FDEVENT_HANDLER_UNSET, +typedef enum { FDEVENT_HANDLER_UNSET, FDEVENT_HANDLER_SELECT, FDEVENT_HANDLER_POLL, FDEVENT_HANDLER_LINUX_RTSIG, @@ -86,7 +86,7 @@ typedef enum { FDEVENT_HANDLER_UNSET, /** * a mapping from fd to connection structure - * + * */ typedef struct { int fd; /**< the fd */ @@ -98,41 +98,41 @@ typedef struct { typedef struct { fd_conn *ptr; - + size_t size; size_t used; } fd_conn_buffer; /** * array of unused fd's - * + * */ typedef struct _fdnode { fdevent_handler handler; void *ctx; int fd; - + struct _fdnode *prev, *next; } fdnode; typedef struct { int *ptr; - + size_t used; size_t size; } buffer_int; /** * fd-event handler for select(), poll() and rt-signals on Linux 2.4 - * + * */ typedef struct fdevents { fdevent_handler_t type; - + fdnode **fdarray; size_t maxfds; - + #ifdef USE_LINUX_SIGIO int in_sigio; int signum; @@ -146,21 +146,21 @@ typedef struct fdevents { #endif #ifdef USE_POLL struct pollfd *pollfds; - + size_t size; size_t used; - + buffer_int unused; #endif #ifdef USE_SELECT fd_set select_read; fd_set select_write; fd_set select_error; - + fd_set select_set_read; fd_set select_set_write; fd_set select_set_error; - + int select_max_fd; #endif #ifdef USE_SOLARIS_DEVPOLL @@ -177,16 +177,16 @@ typedef struct fdevents { #endif int (*reset)(struct fdevents *ev); void (*free)(struct fdevents *ev); - + int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events); int (*event_del)(struct fdevents *ev, int fde_ndx, int fd); int (*event_get_revent)(struct fdevents *ev, size_t ndx); int (*event_get_fd)(struct fdevents *ev, size_t ndx); - + int (*event_next_fdndx)(struct fdevents *ev, int ndx); - + int (*poll)(struct fdevents *ev, int timeout_ms); - + int (*fcntl_set)(struct fdevents *ev, int fd); } fdevents; diff --git a/src/fdevent_freebsd_kqueue.c b/src/fdevent_freebsd_kqueue.c index b955726..e21d6fd 100644 --- a/src/fdevent_freebsd_kqueue.c +++ b/src/fdevent_freebsd_kqueue.c @@ -48,7 +48,7 @@ static int fdevent_freebsd_kqueue_event_del(fdevents *ev, int fde_ndx, int fd) { return -1; } - + return -1; } @@ -65,7 +65,7 @@ static int fdevent_freebsd_kqueue_event_add(fdevents *ev, int fde_ndx, int fd, i ts.tv_sec = 0; ts.tv_nsec = 0; - + ret = kevent(ev->kq_fd, &kev, 1, NULL, 0, @@ -77,7 +77,7 @@ static int fdevent_freebsd_kqueue_event_add(fdevents *ev, int fde_ndx, int fd, i return -1; } - + if (filter == EVFILT_READ) { bitset_set_bit(ev->kq_bevents, fd); } else { @@ -124,7 +124,7 @@ static int fdevent_freebsd_kqueue_event_get_revent(fdevents *ev, size_t ndx) { } else if (e == EVFILT_WRITE) { events |= FDEVENT_OUT; } - + e = ev->kq_results[ndx].flags; if (e & EV_EOF) { @@ -152,10 +152,10 @@ static int fdevent_freebsd_kqueue_reset(fdevents *ev) { if (-1 == (ev->kq_fd = kqueue())) { fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__, strerror(errno)); - + return -1; } - + return 0; } @@ -186,7 +186,7 @@ int fdevent_freebsd_kqueue_init(fdevents *ev) { if (-1 == (ev->kq_fd = kqueue())) { fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__, strerror(errno)); - + return -1; } diff --git a/src/fdevent_linux_rtsig.c b/src/fdevent_linux_rtsig.c index dcefff8..924e4c7 100644 --- a/src/fdevent_linux_rtsig.c +++ b/src/fdevent_linux_rtsig.c @@ -26,19 +26,19 @@ static void fdevent_linux_rtsig_free(fdevents *ev) { static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) { if (fde_ndx < 0) return -1; - + if ((size_t)fde_ndx >= ev->used) { fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used); SEGFAULT(); } - + if (ev->pollfds[fde_ndx].fd == fd) { size_t k = fde_ndx; - + ev->pollfds[k].fd = -1; bitset_clear_bit(ev->sigbset, fd); - + if (ev->unused.size == 0) { ev->unused.size = 16; ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size); @@ -46,29 +46,29 @@ static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) { ev->unused.size += 16; ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size); } - + ev->unused.ptr[ev->unused.used++] = k; } else { fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd); - + SEGFAULT(); } - + return -1; } #if 0 static int fdevent_linux_rtsig_event_compress(fdevents *ev) { size_t j; - + if (ev->used == 0) return 0; if (ev->unused.used != 0) return 0; - + for (j = ev->used - 1; j + 1 > 0; j--) { if (ev->pollfds[j].fd == -1) ev->used--; } - - + + return 0; } #endif @@ -78,21 +78,21 @@ static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int if (fde_ndx != -1) { if (ev->pollfds[fde_ndx].fd == fd) { ev->pollfds[fde_ndx].events = events; - + return fde_ndx; } fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd); SEGFAULT(); } - + if (ev->unused.used > 0) { int k = ev->unused.ptr[--ev->unused.used]; - + ev->pollfds[k].fd = fd; ev->pollfds[k].events = events; bitset_set_bit(ev->sigbset, fd); - + return k; } else { if (ev->size == 0) { @@ -102,12 +102,12 @@ static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int ev->size += 16; ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size); } - + ev->pollfds[ev->used].fd = fd; ev->pollfds[ev->used].events = events; bitset_set_bit(ev->sigbset, fd); - + return ev->used++; } } @@ -115,20 +115,20 @@ static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) { struct timespec ts; int r; - + #if 0 fdevent_linux_rtsig_event_compress(ev); #endif - + ev->in_sigio = 1; - + ts.tv_sec = timeout_ms / 1000; ts.tv_nsec = (timeout_ms % 1000) * 1000000; r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts)); - - if (r == -1) { + + if (r == -1) { if (errno == EAGAIN) return 0; - return r; + return r; } else if (r == SIGIO) { struct sigaction act; @@ -140,7 +140,7 @@ static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) { /* re-enable the signal queue */ act.sa_handler = SIG_DFL; sigaction(ev->signum, &act, NULL); - + ev->in_sigio = 0; r = poll(ev->pollfds, ev->used, timeout_ms); @@ -162,12 +162,12 @@ static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) { if (ev->siginfo.si_band == POLLERR) { fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno)); } -# endif +# endif if (ndx != 0) { fprintf(stderr, "+\n"); return 0; } - + return ev->siginfo.si_band & 0x3f; } else { if (ndx >= ev->used) { @@ -188,13 +188,13 @@ static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) { static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) { static pid_t pid = 0; - + if (pid == 0) pid = getpid(); - + if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1; - + if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1; - + return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR); } @@ -205,12 +205,12 @@ static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) { return -1; } else { size_t i; - + i = (ndx < 0) ? 0 : ndx + 1; for (; i < ev->used; i++) { if (ev->pollfds[i].revents) break; } - + return i; } } @@ -219,34 +219,34 @@ int fdevent_linux_rtsig_init(fdevents *ev) { ev->type = FDEVENT_HANDLER_LINUX_RTSIG; #define SET(x) \ ev->x = fdevent_linux_rtsig_##x; - + SET(free); SET(poll); - + SET(event_del); SET(event_add); - + SET(event_next_fdndx); SET(fcntl_set); SET(event_get_fd); SET(event_get_revent); - + ev->signum = SIGRTMIN + 1; - + sigemptyset(&(ev->sigset)); sigaddset(&(ev->sigset), ev->signum); sigaddset(&(ev->sigset), SIGIO); if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) { fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__, strerror(errno)); - + return -1; } - + ev->in_sigio = 1; ev->sigbset = bitset_init(ev->maxfds); - + return 0; } #else diff --git a/src/fdevent_linux_sysepoll.c b/src/fdevent_linux_sysepoll.c index 31caabd..64125f0 100644 --- a/src/fdevent_linux_sysepoll.c +++ b/src/fdevent_linux_sysepoll.c @@ -20,36 +20,36 @@ static void fdevent_linux_sysepoll_free(fdevents *ev) { static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) { struct epoll_event ep; - + if (fde_ndx < 0) return -1; - + memset(&ep, 0, sizeof(ep)); - + ep.data.fd = fd; ep.data.ptr = NULL; - + if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) { fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno)); - + SEGFAULT(); - + return 0; } - - + + return -1; } static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) { struct epoll_event ep; int add = 0; - + if (fde_ndx == -1) add = 1; - + memset(&ep, 0, sizeof(ep)); - + ep.events = 0; - + if (events & FDEVENT_IN) ep.events |= EPOLLIN; if (events & FDEVENT_OUT) ep.events |= EPOLLOUT; @@ -60,20 +60,20 @@ static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, i * sent. * */ - + ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */; - + ep.data.ptr = NULL; ep.data.fd = fd; - + if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) { fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno)); - + SEGFAULT(); - + return 0; } - + return fd; } @@ -83,14 +83,14 @@ static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) { static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) { int events = 0, e; - + e = ev->epoll_events[ndx].events; if (e & EPOLLIN) events |= FDEVENT_IN; if (e & EPOLLOUT) events |= FDEVENT_OUT; if (e & EPOLLERR) events |= FDEVENT_ERR; if (e & EPOLLHUP) events |= FDEVENT_HUP; if (e & EPOLLPRI) events |= FDEVENT_PRI; - + return e; } @@ -98,17 +98,17 @@ static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) { # if 0 fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd); # endif - + return ev->epoll_events[ndx].data.fd; } static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) { size_t i; - + UNUSED(ev); i = (ndx < 0) ? 0 : ndx + 1; - + return i; } @@ -116,17 +116,17 @@ int fdevent_linux_sysepoll_init(fdevents *ev) { ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL; #define SET(x) \ ev->x = fdevent_linux_sysepoll_##x; - + SET(free); SET(poll); - + SET(event_del); SET(event_add); - + SET(event_next_fdndx); SET(event_get_fd); SET(event_get_revent); - + if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) { fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__, strerror(errno)); @@ -154,7 +154,7 @@ int fdevent_linux_sysepoll_init(fdevents *ev) { fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); - + return -1; } #endif diff --git a/src/fdevent_poll.c b/src/fdevent_poll.c index 7d8017a..11d2c5e 100644 --- a/src/fdevent_poll.c +++ b/src/fdevent_poll.c @@ -20,19 +20,19 @@ static void fdevent_poll_free(fdevents *ev) { static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) { if (fde_ndx < 0) return -1; - + if ((size_t)fde_ndx >= ev->used) { fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used); SEGFAULT(); } - + if (ev->pollfds[fde_ndx].fd == fd) { size_t k = fde_ndx; - + ev->pollfds[k].fd = -1; /* ev->pollfds[k].events = 0; */ /* ev->pollfds[k].revents = 0; */ - + if (ev->unused.size == 0) { ev->unused.size = 16; ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size); @@ -40,47 +40,47 @@ static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) { ev->unused.size += 16; ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size); } - + ev->unused.ptr[ev->unused.used++] = k; } else { SEGFAULT(); } - + return -1; } #if 0 static int fdevent_poll_event_compress(fdevents *ev) { size_t j; - + if (ev->used == 0) return 0; if (ev->unused.used != 0) return 0; - + for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--; - + return 0; } #endif static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) { /* known index */ - + if (fde_ndx != -1) { if (ev->pollfds[fde_ndx].fd == fd) { ev->pollfds[fde_ndx].events = events; - + return fde_ndx; } fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd); SEGFAULT(); } - + if (ev->unused.used > 0) { int k = ev->unused.ptr[--ev->unused.used]; - + ev->pollfds[k].fd = fd; ev->pollfds[k].events = events; - + return k; } else { if (ev->size == 0) { @@ -90,10 +90,10 @@ static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) ev->size += 16; ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size); } - + ev->pollfds[ev->used].fd = fd; ev->pollfds[ev->used].events = events; - + return ev->used++; } } @@ -109,12 +109,12 @@ static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) { int r, poll_r; if (ndx >= ev->used) { fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used); - + SEGFAULT(); - + return 0; } - + if (ev->pollfds[ndx].revents & POLLNVAL) { /* should never happen */ SEGFAULT(); @@ -131,7 +131,7 @@ static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) { if (poll_r & POLLHUP) r |= FDEVENT_HUP; if (poll_r & POLLNVAL) r |= FDEVENT_NVAL; if (poll_r & POLLPRI) r |= FDEVENT_PRI; - + return ev->pollfds[ndx].revents; } @@ -141,12 +141,12 @@ static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) { static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) { size_t i; - + i = (ndx < 0) ? 0 : ndx + 1; for (; i < ev->used; i++) { if (ev->pollfds[i].revents) break; } - + return i; } @@ -154,17 +154,17 @@ int fdevent_poll_init(fdevents *ev) { ev->type = FDEVENT_HANDLER_POLL; #define SET(x) \ ev->x = fdevent_poll_##x; - + SET(free); SET(poll); - + SET(event_del); SET(event_add); - + SET(event_next_fdndx); SET(event_get_fd); SET(event_get_revent); - + return 0; } diff --git a/src/fdevent_select.c b/src/fdevent_select.c index 3eb10f3..4dcb754 100644 --- a/src/fdevent_select.c +++ b/src/fdevent_select.c @@ -49,28 +49,28 @@ static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int event FD_SET(fd, &(ev->select_set_write)); } FD_SET(fd, &(ev->select_set_error)); - + if (fd > ev->select_max_fd) ev->select_max_fd = fd; - + return fd; } static int fdevent_select_poll(fdevents *ev, int timeout_ms) { struct timeval tv; - + tv.tv_sec = timeout_ms / 1000; tv.tv_usec = (timeout_ms % 1000) * 1000; - + ev->select_read = ev->select_set_read; ev->select_write = ev->select_set_write; ev->select_error = ev->select_set_error; - + return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv); } static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) { int revents = 0; - + if (FD_ISSET(ndx, &(ev->select_read))) { revents |= FDEVENT_IN; } @@ -80,7 +80,7 @@ static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) { if (FD_ISSET(ndx, &(ev->select_error))) { revents |= FDEVENT_ERR; } - + return revents; } @@ -92,15 +92,15 @@ static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) { static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) { int i; - + i = (ndx < 0) ? 0 : ndx + 1; - + for (; i < ev->select_max_fd + 1; i++) { if (FD_ISSET(i, &(ev->select_read))) break; if (FD_ISSET(i, &(ev->select_write))) break; if (FD_ISSET(i, &(ev->select_error))) break; } - + return i; } @@ -108,17 +108,17 @@ int fdevent_select_init(fdevents *ev) { ev->type = FDEVENT_HANDLER_SELECT; #define SET(x) \ ev->x = fdevent_select_##x; - + SET(reset); SET(poll); - + SET(event_del); SET(event_add); - + SET(event_next_fdndx); SET(event_get_fd); SET(event_get_revent); - + return 0; } diff --git a/src/fdevent_solaris_devpoll.c b/src/fdevent_solaris_devpoll.c index 91238b0..f77daef 100644 --- a/src/fdevent_solaris_devpoll.c +++ b/src/fdevent_solaris_devpoll.c @@ -23,55 +23,55 @@ static void fdevent_solaris_devpoll_free(fdevents *ev) { static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) { struct pollfd pfd; - + if (fde_ndx < 0) return -1; - + pfd.fd = fd; pfd.events = POLLREMOVE; pfd.revents = 0; - + if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) { - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", - __FILE__, __LINE__, + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", + __FILE__, __LINE__, fd, strerror(errno)); - + return -1; } - + return -1; } static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) { struct pollfd pfd; int add = 0; - + if (fde_ndx == -1) add = 1; - + pfd.fd = fd; pfd.events = events; pfd.revents = 0; - + if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) { - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", - __FILE__, __LINE__, + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n", + __FILE__, __LINE__, fd, strerror(errno)); - + return -1; } - + return fd; } static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) { struct dvpoll dopoll; int ret; - + dopoll.dp_timeout = timeout_ms; dopoll.dp_nfds = ev->maxfds; dopoll.dp_fds = ev->devpollfds; - + ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll); - + return ret; } @@ -85,11 +85,11 @@ static int fdevent_solaris_devpoll_event_get_fd(fdevents *ev, size_t ndx) { static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) { size_t i; - + UNUSED(ev); i = (last_ndx < 0) ? 0 : last_ndx + 1; - + return i; } @@ -117,20 +117,20 @@ int fdevent_solaris_devpoll_init(fdevents *ev) { ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL; #define SET(x) \ ev->x = fdevent_solaris_devpoll_##x; - + SET(free); SET(poll); SET(reset); - + SET(event_del); SET(event_add); - + SET(event_next_fdndx); SET(event_get_fd); SET(event_get_revent); - + ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds); - + if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) { fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__, strerror(errno)); @@ -152,7 +152,7 @@ int fdevent_solaris_devpoll_init(fdevents *ev) { fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n", __FILE__, __LINE__); - + return -1; } #endif diff --git a/src/http-header-glue.c b/src/http-header-glue.c index b40f374..9786ed8 100644 --- a/src/http-header-glue.c +++ b/src/http-header-glue.c @@ -45,20 +45,20 @@ # ifdef HAVE_STRUCT_SOCKADDR_STORAGE static size_t get_sa_len(const struct sockaddr *addr) { switch (addr->sa_family) { - + # ifdef AF_INET case AF_INET: return (sizeof (struct sockaddr_in)); # endif - + # ifdef AF_INET6 case AF_INET6: return (sizeof (struct sockaddr_in6)); # endif - + default: return (sizeof (struct sockaddr)); - + } } # define SA_LEN(addr) (get_sa_len(addr)) @@ -74,7 +74,7 @@ static size_t get_sa_len(const struct sockaddr *addr) { int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) { data_string *ds; - + UNUSED(srv); if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { @@ -82,32 +82,32 @@ int response_header_insert(server *srv, connection *con, const char *key, size_t } buffer_copy_string_len(ds->key, key, keylen); buffer_copy_string_len(ds->value, value, vallen); - + array_insert_unique(con->response.headers, (data_unset *)ds); - + return 0; } int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) { data_string *ds; - + UNUSED(srv); /* if there already is a key by this name overwrite the value */ if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) { buffer_copy_string(ds->value, value); - + return 0; } - + return response_header_insert(srv, con, key, keylen, value, vallen); } int http_response_redirect_to_directory(server *srv, connection *con) { buffer *o; - + o = buffer_init(); - + if (con->conf.is_ssl) { buffer_copy_string(o, "https://"); } else { @@ -123,36 +123,36 @@ int http_response_redirect_to_directory(server *srv, connection *con) { #endif sock_addr our_addr; socklen_t our_addr_len; - + our_addr_len = sizeof(our_addr); - + if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) { con->http_status = 500; - + log_error_write(srv, __FILE__, __LINE__, "ss", "can't get sockname", strerror(errno)); - + buffer_free(o); return 0; } - - + + /* Lookup name: secondly try to get hostname for bind address */ switch(our_addr.plain.sa_family) { #ifdef HAVE_IPV6 case AF_INET6: - if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), - SA_LEN((const struct sockaddr *)&our_addr.ipv6), + if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6), + SA_LEN((const struct sockaddr *)&our_addr.ipv6), hbuf, sizeof(hbuf), NULL, 0, 0)) { - + char dst[INET6_ADDRSTRLEN]; - + log_error_write(srv, __FILE__, __LINE__, "SSSS", "NOTICE: getnameinfo failed: ", strerror(errno), ", using ip-address instead"); - - buffer_append_string(o, - inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, + + buffer_append_string(o, + inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr, dst, sizeof(dst))); } else { buffer_append_string(o, hbuf); @@ -164,7 +164,7 @@ int http_response_redirect_to_directory(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "SdSS", "NOTICE: gethostbyaddr failed: ", h_errno, ", using ip-address instead"); - + buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr)); } else { buffer_append_string(o, he->h_name); @@ -173,12 +173,12 @@ int http_response_redirect_to_directory(server *srv, connection *con) { default: log_error_write(srv, __FILE__, __LINE__, "S", "ERROR: unsupported address-type"); - + buffer_free(o); return -1; } - - if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || + + if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) || (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) { buffer_append_string(o, ":"); buffer_append_long(o, srv->srvconf.port); @@ -190,41 +190,41 @@ int http_response_redirect_to_directory(server *srv, connection *con) { buffer_append_string(o, "?"); buffer_append_string_buffer(o, con->uri.query); } - + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o)); - + con->http_status = 301; con->file_finished = 1; - + buffer_free(o); - + return 0; } buffer * strftime_cache_get(server *srv, time_t last_mod) { struct tm *tm; size_t i; - + for (i = 0; i < FILE_CACHE_MAX; i++) { /* found cache-entry */ if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str; - + /* found empty slot */ if (srv->mtime_cache[i].mtime == 0) break; } - + if (i == FILE_CACHE_MAX) { i = 0; } - + srv->mtime_cache[i].mtime = last_mod; buffer_prepare_copy(srv->mtime_cache[i].str, 1024); tm = gmtime(&(srv->mtime_cache[i].mtime)); - srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, + srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr, srv->mtime_cache[i].str->size - 1, "%a, %d %b %Y %H:%M:%S GMT", tm); srv->mtime_cache[i].str->used++; - + return srv->mtime_cache[i].str; } @@ -239,24 +239,24 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) { * request. That is, if no entity tags match, then the server MUST NOT * return a 304 (Not Modified) response. */ - + /* last-modified handling */ if (con->request.http_if_none_match) { if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) { - if (con->request.http_method == HTTP_METHOD_GET || + if (con->request.http_method == HTTP_METHOD_GET || con->request.http_method == HTTP_METHOD_HEAD) { - + /* check if etag + last-modified */ if (con->request.http_if_modified_since) { size_t used_len; char *semicolon; - + if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) { used_len = strlen(con->request.http_if_modified_since); } else { used_len = semicolon - con->request.http_if_modified_since; } - + if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) { con->http_status = 304; return HANDLER_FINISHED; @@ -267,26 +267,26 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) { /* check if we can safely copy the string */ if (used_len >= sizeof(buf)) { - log_error_write(srv, __FILE__, __LINE__, "ssdd", - "DEBUG: Last-Modified check failed as the received timestamp was too long:", + log_error_write(srv, __FILE__, __LINE__, "ssdd", + "DEBUG: Last-Modified check failed as the received timestamp was too long:", con->request.http_if_modified_since, used_len, sizeof(buf) - 1); - + con->http_status = 412; return HANDLER_FINISHED; } - + strncpy(buf, con->request.http_if_modified_since, used_len); buf[used_len] = '\0'; - + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm); t_header = mktime(&tm); - + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm); t_file = mktime(&tm); if (t_file > t_header) return HANDLER_GO_ON; - + con->http_status = 304; return HANDLER_FINISHED; } @@ -308,7 +308,7 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) { } else { used_len = semicolon - con->request.http_if_modified_since; } - + if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) { con->http_status = 304; return HANDLER_FINISHED; @@ -322,10 +322,10 @@ int http_response_handle_cachable(server *srv, connection *con, buffer *mtime) { strncpy(buf, con->request.http_if_modified_since, used_len); buf[used_len] = '\0'; - + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm); t_header = mktime(&tm); - + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm); t_file = mktime(&tm); diff --git a/src/http_auth.c b/src/http_auth.c index 0d4637e..ae2560c 100644 --- a/src/http_auth.c +++ b/src/http_auth.c @@ -37,6 +37,21 @@ # include "md5.h" #endif +/** + * the $apr1$ handling is taken from apache 1.3.x + */ + +/* + * The apr_md5_encode() routine uses much code obtained from the FreeBSD 3.0 + * MD5 crypt() function, which is licenced as follows: + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + */ + handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s); static const char base64_pad = '='; @@ -64,25 +79,25 @@ static unsigned char * base64_decode(buffer *out, const char *in) { unsigned char *result; int ch, j = 0, k; size_t i; - + size_t in_len = strlen(in); - + buffer_prepare_copy(out, in_len); - + result = (unsigned char *)out->ptr; - + ch = in[0]; /* run through the whole string, converting as we go */ for (i = 0; i < in_len; i++) { ch = in[i]; - + if (ch == '\0') break; - + if (ch == base64_pad) break; - + ch = base64_reverse_table[ch]; if (ch < 0) continue; - + switch(i % 4) { case 0: result[j] = ch << 2; @@ -114,168 +129,168 @@ static unsigned char * base64_decode(buffer *out, const char *in) { } } result[k] = '\0'; - + out->used = k; - + return result; } static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) { int ret = -1; - + if (!username->used|| !realm->used) return -1; - + if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) { stream f; char * f_line; - + if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1; - + if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) { log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno)); - + return -1; } - + f_line = f.start; - + while (f_line - f.start != f.size) { char *f_user, *f_pwd, *e, *f_realm; size_t u_len, pwd_len, r_len; - + f_user = f_line; - - /* + + /* * htdigest format - * - * user:realm:md5(user:realm:password) + * + * user:realm:md5(user:realm:password) */ - + if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "parsed error in", p->conf.auth_htdigest_userfile, + log_error_write(srv, __FILE__, __LINE__, "sbs", + "parsed error in", p->conf.auth_htdigest_userfile, "expected 'username:realm:hashed password'"); - + stream_close(&f); - + return -1; } - + if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "parsed error in", p->conf.auth_plain_userfile, + log_error_write(srv, __FILE__, __LINE__, "sbs", + "parsed error in", p->conf.auth_plain_userfile, "expected 'username:realm:hashed password'"); - + stream_close(&f); - + return -1; } - + /* get pointers to the fields */ - u_len = f_realm - f_user; + u_len = f_realm - f_user; f_realm++; r_len = f_pwd - f_realm; f_pwd++; - + if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) { pwd_len = e - f_pwd; } else { pwd_len = f.size - (f_pwd - f.start); } - + if (username->used - 1 == u_len && (realm->used - 1 == r_len) && (0 == strncmp(username->ptr, f_user, u_len)) && (0 == strncmp(realm->ptr, f_realm, r_len))) { /* found */ - + buffer_copy_string_len(password, f_pwd, pwd_len); - + ret = 0; break; } - + /* EOL */ if (!e) break; - + f_line = e + 1; } - + stream_close(&f); } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD || p->conf.auth_backend == AUTH_BACKEND_PLAIN) { stream f; char * f_line; buffer *auth_fn; - + auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile; - + if (buffer_is_empty(auth_fn)) return -1; - + if (0 != stream_open(&f, auth_fn)) { - log_error_write(srv, __FILE__, __LINE__, "sbss", + log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-userfile", auth_fn, "failed:", strerror(errno)); - + return -1; } - + f_line = f.start; - + while (f_line - f.start != f.size) { char *f_user, *f_pwd, *e; size_t u_len, pwd_len; - + f_user = f_line; - - /* + + /* * htpasswd format - * + * * user:crypted passwd */ - + if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "parsed error in", auth_fn, + log_error_write(srv, __FILE__, __LINE__, "sbs", + "parsed error in", auth_fn, "expected 'username:hashed password'"); - + stream_close(&f); - + return -1; } - + /* get pointers to the fields */ - u_len = f_pwd - f_user; + u_len = f_pwd - f_user; f_pwd++; - + if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) { pwd_len = e - f_pwd; } else { pwd_len = f.size - (f_pwd - f.start); } - + if (username->used - 1 == u_len && (0 == strncmp(username->ptr, f_user, u_len))) { /* found */ - + buffer_copy_string_len(password, f_pwd, pwd_len); - + ret = 0; break; } - + /* EOL */ if (!e) break; - + f_line = e + 1; } - + stream_close(&f); } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { ret = 0; } else { return -1; } - + return ret; } @@ -285,7 +300,7 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha int username_len; data_string *require; array *req; - + UNUSED(group); UNUSED(host); @@ -293,12 +308,12 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha /* search auth-directives for path */ for (i = 0; i < p->conf.auth_require->used; i++) { if (p->conf.auth_require->data[i]->key->used == 0) continue; - + if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) { break; } } - + if (i == p->conf.auth_require->used) { return -1; } @@ -306,72 +321,72 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha req = ((data_array *)(p->conf.auth_require->data[i]))->value; require = (data_string *)array_get_element(req, "require"); - + /* if we get here, the user we got a authed user */ if (0 == strcmp(require->value->ptr, "valid-user")) { return 0; } - + /* user=name1|group=name3|host=name4 */ - + /* seperate the string by | */ #if 0 log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value); -#endif - +#endif + username_len = username ? strlen(username) : 0; - + r = rules = require->value->ptr; - + while (1) { const char *eq; const char *k, *v, *e; int k_len, v_len, r_len; - + e = strchr(r, '|'); - + if (e) { r_len = e - r; } else { r_len = strlen(rules) - (r - rules); } - + /* from r to r + r_len is a rule */ - + if (0 == strncmp(r, "valid-user", r_len)) { - log_error_write(srv, __FILE__, __LINE__, "sb", + 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__, "sb", - "parsing the 'require' section in 'auth.require' failed: a = 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__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "parsing the 'require' section in 'auth.require' failed: = out of range", require->value); - + return -1; } - + /* the part before the = is user|group|host */ - + k = r; k_len = eq - r; v = eq + 1; v_len = r_len - k_len - 1; - + if (k_len == 4) { if (0 == strncmp(k, "user", k_len)) { - if (username && + if (username && username_len == v_len && 0 == strncmp(username, v, v_len)) { return 0; @@ -393,19 +408,191 @@ static int http_auth_match_rules(server *srv, mod_auth_plugin_data *p, const cha log_error_write(srv, __FILE__, __LINE__, "s", "unknown key"); return -1; } - + if (!e) break; r = e + 1; } - + log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched"); - + return -1; } +#define APR_MD5_DIGESTSIZE 16 +#define APR1_ID "$apr1$" + +/* + * The following MD5 password encryption code was largely borrowed from + * the FreeBSD 3.0 /usr/src/lib/libcrypt/crypt.c file, which is + * licenced as stated at the top of this file. + */ + +static void to64(char *s, unsigned long v, int n) +{ + static unsigned char itoa64[] = /* 0 ... 63 => ASCII - 64 */ + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + while (--n >= 0) { + *s++ = itoa64[v&0x3f]; + v >>= 6; + } +} + +static void apr_md5_encode(const char *pw, const char *salt, char *result, size_t nbytes) { + /* + * Minimum size is 8 bytes for salt, plus 1 for the trailing NUL, + * plus 4 for the '$' separators, plus the password hash itself. + * Let's leave a goodly amount of leeway. + */ + + char passwd[120], *p; + const char *sp, *ep; + unsigned char final[APR_MD5_DIGESTSIZE]; + ssize_t sl, pl, i; + MD5_CTX ctx, ctx1; + unsigned long l; + + /* + * Refine the salt first. It's possible we were given an already-hashed + * string as the salt argument, so extract the actual salt value from it + * if so. Otherwise just use the string up to the first '$' as the salt. + */ + sp = salt; + + /* + * If it starts with the magic string, then skip that. + */ + if (!strncmp(sp, APR1_ID, strlen(APR1_ID))) { + sp += strlen(APR1_ID); + } + + /* + * It stops at the first '$' or 8 chars, whichever comes first + */ + for (ep = sp; (*ep != '\0') && (*ep != '$') && (ep < (sp + 8)); ep++) { + continue; + } + + /* + * Get the length of the true salt + */ + sl = ep - sp; + + /* + * 'Time to make the doughnuts..' + */ + MD5_Init(&ctx); + + /* + * The password first, since that is what is most unknown + */ + MD5_Update(&ctx, pw, strlen(pw)); + + /* + * Then our magic string + */ + MD5_Update(&ctx, APR1_ID, strlen(APR1_ID)); + + /* + * Then the raw salt + */ + MD5_Update(&ctx, sp, sl); + + /* + * Then just as many characters of the MD5(pw, salt, pw) + */ + MD5_Init(&ctx1); + MD5_Update(&ctx1, pw, strlen(pw)); + MD5_Update(&ctx1, sp, sl); + MD5_Update(&ctx1, pw, strlen(pw)); + MD5_Final(final, &ctx1); + for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) { + MD5_Update(&ctx, final, + (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl); + } + + /* + * Don't leave anything around in vm they could use. + */ + memset(final, 0, sizeof(final)); + + /* + * Then something really weird... + */ + for (i = strlen(pw); i != 0; i >>= 1) { + if (i & 1) { + MD5_Update(&ctx, final, 1); + } + else { + MD5_Update(&ctx, pw, 1); + } + } + + /* + * Now make the output string. We know our limitations, so we + * can use the string routines without bounds checking. + */ + strcpy(passwd, APR1_ID); + strncat(passwd, sp, sl); + strcat(passwd, "$"); + + MD5_Final(final, &ctx); + + /* + * And now, just to make sure things don't run too fast.. + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for (i = 0; i < 1000; i++) { + MD5_Init(&ctx1); + if (i & 1) { + MD5_Update(&ctx1, pw, strlen(pw)); + } + else { + MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE); + } + if (i % 3) { + MD5_Update(&ctx1, sp, sl); + } + + if (i % 7) { + MD5_Update(&ctx1, pw, strlen(pw)); + } + + if (i & 1) { + MD5_Update(&ctx1, final, APR_MD5_DIGESTSIZE); + } + else { + MD5_Update(&ctx1, pw, strlen(pw)); + } + MD5_Final(final,&ctx1); + } + + p = passwd + strlen(passwd); + + l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p, l, 4); p += 4; + l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p, l, 4); p += 4; + l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p, l, 4); p += 4; + l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p, l, 4); p += 4; + l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p, l, 4); p += 4; + l = final[11] ; to64(p, l, 2); p += 2; + *p = '\0'; + + /* + * Don't leave anything around in vm they could use. + */ + memset(final, 0, sizeof(final)); + + /* FIXME + */ +#define apr_cpystrn strncpy + apr_cpystrn(result, passwd, nbytes - 1); +} + + /** - * - * + * + * * @param password password-string from the auth-backend * @param pw password-string from the client */ @@ -415,16 +602,16 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p UNUSED(req); if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) { - /* + /* * htdigest format - * - * user:realm:md5(user:realm:password) + * + * user:realm:md5(user:realm:password) */ - + MD5_CTX Md5Ctx; HASH HA1; char a1[256]; - + MD5_Init(&Md5Ctx); MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1); MD5_Update(&Md5Ctx, (unsigned char *)":", 1); @@ -432,24 +619,32 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p MD5_Update(&Md5Ctx, (unsigned char *)":", 1); MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw)); MD5_Final(HA1, &Md5Ctx); - + CvtHex(HA1, a1); - + if (0 == strcmp(password->ptr, a1)) { return 0; } - } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { -#ifdef HAVE_CRYPT + } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) { + char sample[120]; + if (!strncmp(password->ptr, APR1_ID, strlen(APR1_ID))) { + /* + * The hash was created using $apr1$ custom algorithm. + */ + apr_md5_encode(pw, password->ptr, sample, sizeof(sample)); + return (strcmp(sample, password->ptr) == 0) ? 0 : 1; + } else { +#ifdef HAVE_CRYPT char salt[32]; char *crypted; size_t salt_len = 0; - /* + /* * htpasswd format - * + * * user:crypted password */ - /* + /* * Algorithm Salt * CRYPT_STD_DES 2-character (Default) * CRYPT_EXT_DES 9-character @@ -467,7 +662,7 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p salt_len = 2; } else if (password->ptr[0] == '$' && password->ptr[2] == '$') { char *dollar = NULL; - + if (NULL == (dollar = strchr(password->ptr + 3, '$'))) { fprintf(stderr, "%s.%d\n", __FILE__, __LINE__); return -1; @@ -484,7 +679,7 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p strncpy(salt, password->ptr, salt_len); salt[salt_len] = '\0'; - + crypted = crypt(pw, salt); if (0 == strcmp(password->ptr, crypted)) { @@ -492,13 +687,14 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p } else { fprintf(stderr, "%s.%d\n", __FILE__, __LINE__); } - -#endif - } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { + +#endif + } + } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { if (0 == strcmp(password->ptr, pw)) { return 0; } - } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { + } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) { #ifdef USE_LDAP LDAP *ldap; LDAPMessage *lm, *first; @@ -506,45 +702,45 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p int ret; char *attrs[] = { LDAP_NO_ATTRS, NULL }; size_t i; - + /* for now we stay synchronous */ - - /* + + /* * 1. connect anonymously (done in plugin init) * 2. get DN for uid = username * 3. auth against ldap server * 4. (optional) check a field * 5. disconnect - * + * */ - + /* check username - * + * * we have to protect us againt username which modifies out filter in * a unpleasant way */ - + for (i = 0; i < username->used - 1; i++) { char c = username->ptr[i]; - + if (!isalpha(c) && !isdigit(c)) { - - log_error_write(srv, __FILE__, __LINE__, "sbd", + + log_error_write(srv, __FILE__, __LINE__, "sbd", "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i); - + return -1; } } - - - + + + /* build filter */ buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre); buffer_append_string_buffer(p->ldap_filter, username); buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post); - - + + /* 2. */ if (p->conf.ldap == NULL || LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) { @@ -552,71 +748,71 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p return -1; if (LDAP_SUCCESS != (ret = ldap_search_s(p->conf.ldap, p->conf.auth_ldap_basedn->ptr, LDAP_SCOPE_SUBTREE, p->ldap_filter->ptr, attrs, 0, &lm))) { - log_error_write(srv, __FILE__, __LINE__, "sssb", + log_error_write(srv, __FILE__, __LINE__, "sssb", "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter); - + return -1; } } - + if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) { log_error_write(srv, __FILE__, __LINE__, "s", "ldap ..."); - + ldap_msgfree(lm); - + return -1; } - + if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) { log_error_write(srv, __FILE__, __LINE__, "s", "ldap ..."); - + ldap_msgfree(lm); - + return -1; } - + ldap_msgfree(lm); - - + + /* 3. */ if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno)); return -1; } - + ret = LDAP_VERSION3; if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret)); - + ldap_unbind_s(ldap); - + return -1; } - + if (p->conf.auth_ldap_starttls == 1) { if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL, NULL))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret)); - + ldap_unbind_s(ldap); - + return -1; } } - + if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret)); - + ldap_unbind_s(ldap); - + return -1; } - + /* 5. */ ldap_unbind_s(ldap); - + /* everything worked, good, access granted */ - + return 0; #endif } @@ -626,65 +822,65 @@ static int http_auth_basic_password_compare(server *srv, mod_auth_plugin_data *p int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) { buffer *username, *password; char *pw; - + data_string *realm; - + realm = (data_string *)array_get_element(req, "realm"); - + username = buffer_init(); password = buffer_init(); - + base64_decode(username, realm_str); - + /* r2 == user:password */ if (NULL == (pw = strchr(username->ptr, ':'))) { buffer_free(username); - + log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username); - + return 0; } - + *pw++ = '\0'; - + username->used = pw - username->ptr; - + /* copy password to r1 */ if (http_auth_get_password(srv, p, username, realm->value, password)) { buffer_free(username); buffer_free(password); - + log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed"); - + return 0; } - + /* password doesn't match */ if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) { log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username); - + buffer_free(username); buffer_free(password); - + return 0; } - + /* value is our allow-rules */ if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) { buffer_free(username); buffer_free(password); - + log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match"); - + return 0; } - + /* remember the username */ buffer_copy_string_buffer(p->auth_user, username); - + buffer_free(username); buffer_free(password); - + return 1; } @@ -697,7 +893,7 @@ typedef struct { int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) { char a1[256]; char a2[256]; - + char *username; char *realm; char *nonce; @@ -707,18 +903,18 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p char *cnonce; char *nc; char *respons; - + char *e, *c; const char *m = NULL; int i; buffer *password, *b, *username_buf, *realm_buf; - + MD5_CTX Md5Ctx; HASH HA1; HASH HA2; HASH RespHash; HASHHEX HA2Hex; - + /* init pointers */ #define S(x) \ @@ -733,11 +929,11 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p { S("cnonce=") }, { S("nc=") }, { S("response=") }, - + { NULL, 0, NULL } }; #undef S - + dkv[0].ptr = &username; dkv[1].ptr = &realm; dkv[2].ptr = &nonce; @@ -748,24 +944,24 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p dkv[7].ptr = &nc; dkv[8].ptr = &respons; dkv[9].ptr = NULL; - + UNUSED(req); - + for (i = 0; dkv[i].key; i++) { *(dkv[i].ptr) = NULL; } - - + + if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST && p->conf.auth_backend != AUTH_BACKEND_PLAIN) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "digest: unsupported backend (only htdigest or plain)"); - + return -1; } - + b = buffer_init_string(realm_str); - + /* parse credentials from client */ for (c = b->ptr; *c; c++) { /* skip whitespaces */ @@ -774,18 +970,18 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p for (i = 0; dkv[i].key; i++) { if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) { - if ((c[dkv[i].key_len] == '"') && + if ((c[dkv[i].key_len] == '"') && (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) { /* value with "..." */ *(dkv[i].ptr) = c + dkv[i].key_len + 1; c = e; - + *e = '\0'; } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) { /* value without "...", terminated by ',' */ *(dkv[i].ptr) = c + dkv[i].key_len; c = e; - + *e = '\0'; } else { /* value without "...", terminated by EOL */ @@ -795,7 +991,7 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p } } } - + if (p->conf.auth_debug > 1) { log_error_write(srv, __FILE__, __LINE__, "ss", "username", username); log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm); @@ -807,22 +1003,22 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc); log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons); } - + /* check if everything is transmitted */ - if (!username || + if (!username || !realm || !nonce || !uri || (qop && (!nc || !cnonce)) || !respons ) { /* missing field */ - - log_error_write(srv, __FILE__, __LINE__, "s", + + log_error_write(srv, __FILE__, __LINE__, "s", "digest: missing field"); return -1; } - m = get_http_method_name(con->request.http_method); + m = get_http_method_name(con->request.http_method); /* password-string == HA1 */ password = buffer_init(); @@ -835,10 +1031,10 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p buffer_free(realm_buf); return 0; } - + buffer_free(username_buf); buffer_free(realm_buf); - + if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) { /* generate password from plain-text */ MD5_Init(&Md5Ctx); @@ -852,16 +1048,16 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p /* HA1 */ /* transform the 32-byte-hex-md5 to a 16-byte-md5 */ for (i = 0; i < HASHLEN; i++) { - HA1[i] = hex2int(password->ptr[i*2]) << 4; - HA1[i] |= hex2int(password->ptr[i*2+1]); + HA1[i] = hex2int(password->ptr[i*2]) << 4; + HA1[i] |= hex2int(password->ptr[i*2+1]); } } else { /* we already check that above */ SEGFAULT(); } - + buffer_free(password); - + if (algorithm && strcasecmp(algorithm, "md5-sess") == 0) { MD5_Init(&Md5Ctx); @@ -872,9 +1068,9 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce)); MD5_Final(HA1, &Md5Ctx); } - + CvtHex(HA1, a1); - + /* calculate H(A2) */ MD5_Init(&Md5Ctx); MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m)); @@ -886,7 +1082,7 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p } MD5_Final(HA2, &Md5Ctx); CvtHex(HA2, HA2Hex); - + /* calculate response */ MD5_Init(&Md5Ctx); MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN); @@ -904,39 +1100,39 @@ int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN); MD5_Final(RespHash, &Md5Ctx); CvtHex(RespHash, a2); - + if (0 != strcmp(a2, respons)) { /* digest not ok */ - + if (p->conf.auth_debug) { - log_error_write(srv, __FILE__, __LINE__, "sss", + log_error_write(srv, __FILE__, __LINE__, "sss", "digest: digest mismatch", a2, respons); } - - log_error_write(srv, __FILE__, __LINE__, "sss", + + log_error_write(srv, __FILE__, __LINE__, "sss", "digest: auth failed for", username, "wrong password"); - + buffer_free(b); return 0; } - + /* value is our allow-rules */ if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) { buffer_free(b); - - log_error_write(srv, __FILE__, __LINE__, "s", + + log_error_write(srv, __FILE__, __LINE__, "s", "digest: rules did match"); - + return 0; } - + /* remember the username */ buffer_copy_string(p->auth_user, username); - + buffer_free(b); - + if (p->conf.auth_debug) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "digest: auth ok"); } return 1; @@ -947,23 +1143,23 @@ int http_auth_digest_generate_nonce(server *srv, mod_auth_plugin_data *p, buffer HASH h; MD5_CTX Md5Ctx; char hh[32]; - + UNUSED(p); /* generate shared-secret */ MD5_Init(&Md5Ctx); MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1); MD5_Update(&Md5Ctx, (unsigned char *)"+", 1); - + /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */ ltostr(hh, srv->cur_ts); MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); ltostr(hh, rand()); MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); - + MD5_Final(h, &Md5Ctx); - + CvtHex(h, out); - + return 0; } diff --git a/src/http_auth.h b/src/http_auth.h index b69007e..d469c0d 100644 --- a/src/http_auth.h +++ b/src/http_auth.h @@ -20,15 +20,15 @@ typedef enum { typedef struct { /* auth */ array *auth_require; - + buffer *auth_plain_groupfile; buffer *auth_plain_userfile; - + buffer *auth_htdigest_userfile; buffer *auth_htpasswd_userfile; - + buffer *auth_backend_conf; - + buffer *auth_ldap_hostname; buffer *auth_ldap_basedn; buffer *auth_ldap_binddn; @@ -36,15 +36,15 @@ typedef struct { buffer *auth_ldap_filter; buffer *auth_ldap_cafile; unsigned short auth_ldap_starttls; - + unsigned short auth_debug; - + /* generated */ auth_backend_t auth_backend; - + #ifdef USE_LDAP LDAP *ldap; - + buffer *ldap_filter_pre; buffer *ldap_filter_post; #endif @@ -53,15 +53,15 @@ typedef struct { typedef struct { PLUGIN_DATA; buffer *tmp_buf; - + buffer *auth_user; #ifdef USE_LDAP buffer *ldap_filter; #endif - + mod_auth_plugin_config **config_storage; - + mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */ } mod_auth_plugin_data; diff --git a/src/http_auth_digest.h b/src/http_auth_digest.h index 8bffce4..25d95ee 100644 --- a/src/http_auth_digest.h +++ b/src/http_auth_digest.h @@ -12,7 +12,7 @@ typedef char HASHHEX[HASHHEXLEN+1]; #ifdef USE_OPENSSL #define IN const #else -#define IN +#define IN #endif #define OUT diff --git a/src/http_chunk.c b/src/http_chunk.c index 281e86b..669ff32 100644 --- a/src/http_chunk.c +++ b/src/http_chunk.c @@ -1,7 +1,7 @@ /** * the HTTP chunk-API - * - * + * + * */ #include <sys/types.h> @@ -23,19 +23,19 @@ static int http_chunk_append_len(server *srv, connection *con, size_t len) { size_t i, olen = len, j; buffer *b; - + b = srv->tmp_chunk_len; - + if (len == 0) { buffer_copy_string(b, "0"); } else { for (i = 0; i < 8 && len; i++) { len >>= 4; } - + /* i is the number of hex digits we have */ buffer_prepare_copy(b, i + 1); - + for (j = i-1, len = olen; j+1 > 0; j--) { b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10); len >>= 4; @@ -43,61 +43,61 @@ static int http_chunk_append_len(server *srv, connection *con, size_t len) { b->used = i; b->ptr[b->used++] = '\0'; } - + buffer_append_string(b, "\r\n"); chunkqueue_append_buffer(con->write_queue, b); - + return 0; } int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) { chunkqueue *cq; - + if (!con) return -1; - + cq = con->write_queue; - + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { http_chunk_append_len(srv, con, len); } - + chunkqueue_append_file(cq, fn, offset, len); - + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) { chunkqueue_append_mem(cq, "\r\n", 2 + 1); } - + return 0; } int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) { chunkqueue *cq; - + if (!con) return -1; - + cq = con->write_queue; - + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { http_chunk_append_len(srv, con, mem->used - 1); } - + chunkqueue_append_buffer(cq, mem); - + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) { chunkqueue_append_mem(cq, "\r\n", 2 + 1); } - + return 0; } int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) { chunkqueue *cq; - + if (!con) return -1; - + cq = con->write_queue; - + if (len == 0) { if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { chunkqueue_append_mem(cq, "0\r\n\r\n", 5 + 1); @@ -106,17 +106,17 @@ int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t } return 0; } - + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { http_chunk_append_len(srv, con, len - 1); } - + chunkqueue_append_mem(cq, mem, len); - + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { chunkqueue_append_mem(cq, "\r\n", 2 + 1); } - + return 0; } @@ -124,9 +124,9 @@ int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t off_t http_chunkqueue_length(server *srv, connection *con) { if (!con) { log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!"); - + return 0; } - + return chunkqueue_length(con->write_queue); } diff --git a/src/inet_ntop_cache.c b/src/inet_ntop_cache.c index c0b3aa1..76d40f3 100644 --- a/src/inet_ntop_cache.c +++ b/src/inet_ntop_cache.c @@ -8,7 +8,7 @@ #include "sys-socket.h" const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) { -#ifdef HAVE_IPV6 +#ifdef HAVE_IPV6 size_t ndx = 0, i; for (i = 0; i < INET_NTOP_CACHE_MAX; i++) { if (srv->inet_ntop_cache[i].ts != 0) { @@ -20,31 +20,31 @@ const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) { srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) { /* IPv4 found in cache */ break; - + } } } - + if (i == INET_NTOP_CACHE_MAX) { /* not found in cache */ - + i = ndx; - inet_ntop(addr->plain.sa_family, - addr->plain.sa_family == AF_INET6 ? + inet_ntop(addr->plain.sa_family, + addr->plain.sa_family == AF_INET6 ? (const void *) &(addr->ipv6.sin6_addr) : (const void *) &(addr->ipv4.sin_addr), srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN); - + srv->inet_ntop_cache[i].ts = srv->cur_ts; srv->inet_ntop_cache[i].family = addr->plain.sa_family; - + if (srv->inet_ntop_cache[i].family == AF_INET) { srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr; } else if (srv->inet_ntop_cache[i].family == AF_INET6) { memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16); } } - + return srv->inet_ntop_cache[i].b2; #else UNUSED(srv); diff --git a/src/joblist.c b/src/joblist.c index dcab955..4ce3842 100644 --- a/src/joblist.c +++ b/src/joblist.c @@ -7,7 +7,7 @@ int joblist_append(server *srv, connection *con) { if (con->in_joblist) return 0; - + if (srv->joblist->size == 0) { srv->joblist->size = 16; srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size); @@ -15,15 +15,15 @@ int joblist_append(server *srv, connection *con) { srv->joblist->size += 16; srv->joblist->ptr = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size); } - + srv->joblist->ptr[srv->joblist->used++] = con; - + return 0; } void joblist_free(server *srv, connections *joblist) { UNUSED(srv); - + free(joblist->ptr); free(joblist); } @@ -31,14 +31,14 @@ void joblist_free(server *srv, connections *joblist) { connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) { connection *con; UNUSED(srv); - - + + if (fdwaitqueue->used == 0) return NULL; - + con = fdwaitqueue->ptr[0]; - + memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr))); - + return con; } @@ -50,9 +50,9 @@ int fdwaitqueue_append(server *srv, connection *con) { srv->fdwaitqueue->size += 16; srv->fdwaitqueue->ptr = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size); } - + srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con; - + return 0; } diff --git a/src/keyvalue.c b/src/keyvalue.c index 2b21d55..ae5df2f 100644 --- a/src/keyvalue.c +++ b/src/keyvalue.c @@ -87,7 +87,7 @@ static keyvalue http_status[] = { { 504, "Gateway Timeout" }, { 505, "HTTP Version Not Supported" }, { 507, "Insufficient Storage" }, /* WebDAV */ - + { -1, NULL } }; @@ -102,12 +102,12 @@ static keyvalue http_status_body[] = { { 501, "501.html" }, { 503, "503.html" }, { 505, "505.html" }, - + { -1, NULL } }; -const char *keyvalue_get_value(keyvalue *kv, int k) { +const char *keyvalue_get_value(keyvalue *kv, int k) { int i; for (i = 0; kv[i].value; i++) { if (kv[i].key == k) return kv[i].value; @@ -115,7 +115,7 @@ const char *keyvalue_get_value(keyvalue *kv, int k) { return NULL; } -int keyvalue_get_key(keyvalue *kv, const char *s) { +int keyvalue_get_key(keyvalue *kv, const char *s) { int i; for (i = 0; kv[i].value; i++) { if (0 == strcmp(kv[i].value, s)) return kv[i].key; @@ -125,9 +125,9 @@ int keyvalue_get_key(keyvalue *kv, const char *s) { keyvalue_buffer *keyvalue_buffer_init(void) { keyvalue_buffer *kvb; - + kvb = calloc(1, sizeof(*kvb)); - + return kvb; } @@ -135,49 +135,49 @@ int keyvalue_buffer_append(keyvalue_buffer *kvb, int key, const char *value) { size_t i; if (kvb->size == 0) { kvb->size = 4; - + kvb->kv = malloc(kvb->size * sizeof(*kvb->kv)); - + for(i = 0; i < kvb->size; i++) { kvb->kv[i] = calloc(1, sizeof(**kvb->kv)); } } else if (kvb->used == kvb->size) { kvb->size += 4; - + kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv)); - + for(i = kvb->used; i < kvb->size; i++) { kvb->kv[i] = calloc(1, sizeof(**kvb->kv)); } } - + kvb->kv[kvb->used]->key = key; kvb->kv[kvb->used]->value = strdup(value); - + kvb->used++; - + return 0; } void keyvalue_buffer_free(keyvalue_buffer *kvb) { size_t i; - + for (i = 0; i < kvb->size; i++) { if (kvb->kv[i]->value) free(kvb->kv[i]->value); free(kvb->kv[i]); } - + if (kvb->kv) free(kvb->kv); - + free(kvb); } s_keyvalue_buffer *s_keyvalue_buffer_init(void) { s_keyvalue_buffer *kvb; - + kvb = calloc(1, sizeof(*kvb)); - + return kvb; } @@ -186,50 +186,50 @@ int s_keyvalue_buffer_append(s_keyvalue_buffer *kvb, const char *key, const char if (kvb->size == 0) { kvb->size = 4; kvb->used = 0; - + kvb->kv = malloc(kvb->size * sizeof(*kvb->kv)); - + for(i = 0; i < kvb->size; i++) { kvb->kv[i] = calloc(1, sizeof(**kvb->kv)); } } else if (kvb->used == kvb->size) { kvb->size += 4; - + kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv)); - + for(i = kvb->used; i < kvb->size; i++) { kvb->kv[i] = calloc(1, sizeof(**kvb->kv)); } } - + kvb->kv[kvb->used]->key = key ? strdup(key) : NULL; kvb->kv[kvb->used]->value = strdup(value); - + kvb->used++; - + return 0; } void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) { size_t i; - + for (i = 0; i < kvb->size; i++) { if (kvb->kv[i]->key) free(kvb->kv[i]->key); if (kvb->kv[i]->value) free(kvb->kv[i]->value); free(kvb->kv[i]); } - + if (kvb->kv) free(kvb->kv); - + free(kvb); } httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) { httpauth_keyvalue_buffer *kvb; - + kvb = calloc(1, sizeof(*kvb)); - + return kvb; } @@ -237,42 +237,42 @@ int httpauth_keyvalue_buffer_append(httpauth_keyvalue_buffer *kvb, const char *k size_t i; if (kvb->size == 0) { kvb->size = 4; - + kvb->kv = malloc(kvb->size * sizeof(*kvb->kv)); - + for(i = 0; i < kvb->size; i++) { kvb->kv[i] = calloc(1, sizeof(**kvb->kv)); } } else if (kvb->used == kvb->size) { kvb->size += 4; - + kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv)); - + for(i = kvb->used; i < kvb->size; i++) { kvb->kv[i] = calloc(1, sizeof(**kvb->kv)); } } - + kvb->kv[kvb->used]->key = strdup(key); kvb->kv[kvb->used]->realm = strdup(realm); kvb->kv[kvb->used]->type = type; - + kvb->used++; - + return 0; } void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) { size_t i; - + for (i = 0; i < kvb->size; i++) { if (kvb->kv[i]->key) free(kvb->kv[i]->key); if (kvb->kv[i]->realm) free(kvb->kv[i]->realm); free(kvb->kv[i]); } - + if (kvb->kv) free(kvb->kv); - + free(kvb); } @@ -306,9 +306,9 @@ http_method_t get_http_method_key(const char *s) { pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) { pcre_keyvalue_buffer *kvb; - + kvb = calloc(1, sizeof(*kvb)); - + return kvb; } @@ -319,46 +319,46 @@ int pcre_keyvalue_buffer_append(pcre_keyvalue_buffer *kvb, const char *key, cons int erroff; pcre_keyvalue *kv; #endif - + if (!key) return -1; #ifdef HAVE_PCRE_H if (kvb->size == 0) { kvb->size = 4; kvb->used = 0; - + kvb->kv = malloc(kvb->size * sizeof(*kvb->kv)); - + for(i = 0; i < kvb->size; i++) { kvb->kv[i] = calloc(1, sizeof(**kvb->kv)); } } else if (kvb->used == kvb->size) { kvb->size += 4; - + kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv)); - + for(i = kvb->used; i < kvb->size; i++) { kvb->kv[i] = calloc(1, sizeof(**kvb->kv)); } } - + kv = kvb->kv[kvb->used]; if (NULL == (kv->key = pcre_compile(key, 0, &errptr, &erroff, NULL))) { - + fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr); return -1; } - if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) && + if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) && errptr != NULL) { return -1; } - + kv->value = buffer_init_string(value); - + kvb->used++; - + return 0; #else UNUSED(kvb); @@ -380,9 +380,9 @@ void pcre_keyvalue_buffer_free(pcre_keyvalue_buffer *kvb) { if (kv->value) buffer_free(kv->value); free(kv); } - + if (kvb->kv) free(kvb->kv); #endif - + free(kvb); } diff --git a/src/keyvalue.h b/src/keyvalue.h index 5caca63..1f37837 100644 --- a/src/keyvalue.h +++ b/src/keyvalue.h @@ -9,19 +9,19 @@ # include <pcre.h> #endif -typedef enum { - HTTP_METHOD_UNSET = -1, - HTTP_METHOD_GET, - HTTP_METHOD_POST, - HTTP_METHOD_HEAD, - HTTP_METHOD_OPTIONS, +typedef enum { + HTTP_METHOD_UNSET = -1, + HTTP_METHOD_GET, + HTTP_METHOD_POST, + HTTP_METHOD_HEAD, + HTTP_METHOD_OPTIONS, HTTP_METHOD_PROPFIND, /* WebDAV */ - HTTP_METHOD_MKCOL, - HTTP_METHOD_PUT, - HTTP_METHOD_DELETE, - HTTP_METHOD_COPY, - HTTP_METHOD_MOVE, - HTTP_METHOD_PROPPATCH, + HTTP_METHOD_MKCOL, + HTTP_METHOD_PUT, + HTTP_METHOD_DELETE, + HTTP_METHOD_COPY, + HTTP_METHOD_MOVE, + HTTP_METHOD_PROPPATCH, HTTP_METHOD_REPORT, /* DeltaV */ HTTP_METHOD_CHECKOUT, HTTP_METHOD_CHECKIN, @@ -39,13 +39,13 @@ typedef enum { HTTP_VERSION_UNSET = -1, HTTP_VERSION_1_0, HTTP_VERSION_1_1 } htt typedef struct { int key; - + char *value; } keyvalue; typedef struct { char *key; - + char *value; } s_keyvalue; @@ -54,7 +54,7 @@ typedef struct { pcre *key; pcre_extra *key_extra; #endif - + buffer *value; } pcre_keyvalue; @@ -62,7 +62,7 @@ typedef enum { HTTP_AUTH_BASIC, HTTP_AUTH_DIGEST } httpauth_type; typedef struct { char *key; - + char *realm; httpauth_type type; } httpauth_keyvalue; diff --git a/src/lemon.c b/src/lemon.c index dd87cdf..5dcf144 100644 --- a/src/lemon.c +++ b/src/lemon.c @@ -579,7 +579,7 @@ int line; */ /* Find a precedence symbol of every rule in the grammar. -** +** ** Those rules which have a precedence symbol coded in the input ** grammar using the "[symbol]" construct will already have the ** rp->precsym field filled. Other rules take as their precedence @@ -869,7 +869,7 @@ struct lemon *lemp; cfp->status = INCOMPLETE; } } - + do{ progress = 0; for(i=0; i<lemp->nstate; i++){ @@ -900,7 +900,7 @@ struct lemon *lemp; struct symbol *sp; struct rule *rp; - /* Add all of the reduce actions + /* Add all of the reduce actions ** A reduce action is added for each element of the followset of ** a configuration which has its dot at the extreme right. */ @@ -1017,7 +1017,7 @@ struct symbol *errsym; /* The error symbol (if defined. NULL otherwise) */ apx->type = RD_RESOLVED; } }else{ - assert( + assert( apx->type==SH_RESOLVED || apx->type==RD_RESOLVED || apx->type==CONFLICT || @@ -1350,7 +1350,7 @@ char **argv; OptInit(argv,options,stderr); if( version ){ printf("Lemon version 1.0\n"); - exit(0); + exit(0); } if( OptNArgs() < 1 ){ fprintf(stderr,"Exactly one filename argument is required.\n"); @@ -2031,7 +2031,7 @@ to follow the previous rule."); case IN_RHS: if( x[0]=='.' ){ struct rule *rp; - rp = (struct rule *)malloc( sizeof(struct rule) + + rp = (struct rule *)malloc( sizeof(struct rule) + sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs ); if( rp==0 ){ ErrorMsg(psp->filename,psp->tokenlineno, @@ -2546,7 +2546,7 @@ char *mode; return fp; } -/* Duplicate the input file without comments and without actions +/* Duplicate the input file without comments and without actions ** on rules */ void Reprint(lemp) struct lemon *lemp; @@ -2822,7 +2822,7 @@ int *lineno; PRIVATE FILE *tplt_open(lemp) struct lemon *lemp; { - + char buf[1000]; FILE *in; char *tpltname; @@ -2930,7 +2930,7 @@ struct lemon *lemp; return ret; } -/* +/* ** Generate code which executes when the rule "rp" is reduced. Write ** the code to "out". Make sure lineno stays up-to-date. */ @@ -3384,7 +3384,7 @@ int mhflag; /* Output in makeheaders format if true */ /* Output the yy_shift_ofst[] table */ fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; - fprintf(out, "static %s yy_shift_ofst[] = {\n", + fprintf(out, "static %s yy_shift_ofst[] = {\n", minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++; n = lemp->nstate; for(i=j=0; i<n; i++){ @@ -3405,7 +3405,7 @@ int mhflag; /* Output in makeheaders format if true */ /* Output the yy_reduce_ofst[] table */ fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++; - fprintf(out, "static %s yy_reduce_ofst[] = {\n", + fprintf(out, "static %s yy_reduce_ofst[] = {\n", minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++; n = lemp->nstate; for(i=j=0; i<n; i++){ @@ -3480,7 +3480,7 @@ int mhflag; /* Output in makeheaders format if true */ tplt_xfer(lemp->name,in,out,&lineno); /* Generate code which executes every time a symbol is popped from - ** the stack while processing errors or while destroying the parser. + ** the stack while processing errors or while destroying the parser. ** (In other words, generate the %destructor actions) */ if( lemp->tokendest ){ @@ -3522,7 +3522,7 @@ int mhflag; /* Output in makeheaders format if true */ tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno); tplt_xfer(lemp->name,in,out,&lineno); - /* Generate the table of rule information + /* Generate the table of rule information ** ** Note: This code depends on the fact that rules are number ** sequentually beginning with 0. @@ -3589,7 +3589,7 @@ struct lemon *lemp; for(i=1; i<lemp->nterminal; i++){ fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i); } - fclose(out); + fclose(out); } return; } @@ -3630,7 +3630,7 @@ struct lemon *lemp; rbest = rp; } } - + /* Do not make a default if the number of rules to default ** is not at least 2 */ if( nbest<2 ) continue; @@ -3781,7 +3781,7 @@ void Strsafe_init(){ if( x1a ){ x1a->size = 1024; x1a->count = 0; - x1a->tbl = (x1node*)malloc( + x1a->tbl = (x1node*)malloc( (sizeof(x1node) + sizeof(x1node*))*1024 ); if( x1a->tbl==0 ){ free(x1a); @@ -3943,7 +3943,7 @@ void Symbol_init(){ if( x2a ){ x2a->size = 128; x2a->count = 0; - x2a->tbl = (x2node*)malloc( + x2a->tbl = (x2node*)malloc( (sizeof(x2node) + sizeof(x2node*))*128 ); if( x2a->tbl==0 ){ free(x2a); @@ -4149,7 +4149,7 @@ void State_init(){ if( x3a ){ x3a->size = 128; x3a->count = 0; - x3a->tbl = (x3node*)malloc( + x3a->tbl = (x3node*)malloc( (sizeof(x3node) + sizeof(x3node*))*128 ); if( x3a->tbl==0 ){ free(x3a); @@ -4295,7 +4295,7 @@ void Configtable_init(){ if( x4a ){ x4a->size = 64; x4a->count = 0; - x4a->tbl = (x4node*)malloc( + x4a->tbl = (x4node*)malloc( (sizeof(x4node) + sizeof(x4node*))*64 ); if( x4a->tbl==0 ){ free(x4a); diff --git a/src/lempar.c b/src/lempar.c index ee1edbf..9ab9075 100644 --- a/src/lempar.c +++ b/src/lempar.c @@ -8,10 +8,10 @@ /* Next is all token values, in a form suitable for use by makeheaders. ** This section will be null unless lemon is run with the -m switch. */ -/* +/* ** These constants (all generated automatically by the parser generator) ** specify the various kinds of tokens (terminals) that the parser -** understands. +** understands. ** ** Each symbol here is a terminal symbol in the grammar. */ @@ -29,7 +29,7 @@ ** and nonterminals. "int" is used otherwise. ** YYNOCODE is a number of type YYCODETYPE which corresponds ** to no legal terminal or nonterminal number. This -** number is used to fill in empty slots of the hash +** number is used to fill in empty slots of the hash ** table. ** YYFALLBACK If defined, this indicates that one or more tokens ** have fall-back values which should be used if the @@ -38,7 +38,7 @@ ** and nonterminal numbers. "unsigned char" is ** used if there are fewer than 250 rules and ** states combined. "int" is used otherwise. -** ParseTOKENTYPE is the data type used for minor tokens given +** ParseTOKENTYPE is the data type used for minor tokens given ** directly to the parser from the tokenizer. ** YYMINORTYPE is the data type used for all minor tokens. ** This is typically a union of many types, one of @@ -62,7 +62,7 @@ /* Next are that tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an -** action integer. +** action integer. ** ** Suppose the action integer is N. Then the action is determined as ** follows @@ -87,7 +87,7 @@ ** If the index value yy_shift_ofst[S]+X is out of range or if the value ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that yy_default[S] should be used instead. +** and that yy_default[S] should be used instead. ** ** The formula above is for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after @@ -111,7 +111,7 @@ /* The next table maps tokens into fallback tokens. If a construct ** like the following: -** +** ** %fallback ID X Y Z. ** ** appears in the grammer, then ID becomes a fallback token for X, Y, @@ -163,10 +163,10 @@ static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG -/* +/* ** Turn parser tracing on by giving a stream to which to write the trace ** and a prompt to preface each trace message. Tracing is turned off -** by making either argument NULL +** by making either argument NULL ** ** Inputs: ** <ul> @@ -191,7 +191,7 @@ void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ #ifndef NDEBUG /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ -static const char *yyTokenName[] = { +static const char *yyTokenName[] = { %% }; #endif /* NDEBUG */ @@ -220,7 +220,7 @@ const char *ParseTokenName(int tokenType){ #endif } -/* +/* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like ** malloc. @@ -251,7 +251,7 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen ** when the symbol is popped from the stack during a - ** reduce or during error processing or when a parser is + ** reduce or during error processing or when a parser is ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those @@ -289,7 +289,7 @@ static int yy_pop_parser_stack(yyParser *pParser){ return yymajor; } -/* +/* ** Deallocate and destroy a parser. Destructors are all called for ** all stack elements before shutting the parser down. ** @@ -325,7 +325,7 @@ static int yy_find_shift_action( ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */ i = yy_shift_ofst[stateno]; if( i==YY_SHIFT_USE_DFLT ){ @@ -369,7 +369,7 @@ static int yy_find_reduce_action( ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - + i = yy_reduce_ofst[stateno]; if( i==YY_REDUCE_USE_DFLT ){ return yy_default[stateno]; @@ -455,7 +455,7 @@ static void yy_reduce( ParseARG_FETCH; yymsp = &yypParser->yystack[yypParser->yyidx]; #ifndef NDEBUG - if( yyTraceFILE && yyruleno>=0 + if( yyTraceFILE && yyruleno>=0 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, yyRuleName[yyruleno]); @@ -608,7 +608,7 @@ void Parse( #ifdef YYERRORSYMBOL /* A syntax error has occurred. ** The response to an error depends upon whether or not the - ** grammar defines an error token "ERROR". + ** grammar defines an error token "ERROR". ** ** This is what we do if the grammar does define ERROR: ** @@ -31,38 +31,38 @@ # define O_LARGEFILE 0 #endif -/** +/** * open the errorlog - * + * * we have 3 possibilities: * - stderr (default) - * - syslog + * - syslog * - logfile - * + * * if the open failed, report to the user and die - * + * */ int log_error_open(server *srv) { int fd; int close_stderr = 1; - + #ifdef HAVE_SYSLOG_H /* perhaps someone wants to use syslog() */ openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON); #endif srv->errorlog_mode = ERRORLOG_STDERR; - + if (srv->srvconf.errorlog_use_syslog) { srv->errorlog_mode = ERRORLOG_SYSLOG; } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) { const char *logfile = srv->srvconf.errorlog_file->ptr; - + if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { - log_error_write(srv, __FILE__, __LINE__, "SSSS", + log_error_write(srv, __FILE__, __LINE__, "SSSS", "opening errorlog '", logfile, "' failed: ", strerror(errno)); - + return -1; } #ifdef FD_CLOEXEC @@ -71,15 +71,15 @@ int log_error_open(server *srv) { #endif srv->errorlog_mode = ERRORLOG_FILE; } - + log_error_write(srv, __FILE__, __LINE__, "s", "server started"); - + #ifdef HAVE_VALGRIND_VALGRIND_H /* don't close stderr for debugging purposes if run in valgrind */ if (RUNNING_ON_VALGRIND) close_stderr = 0; #endif if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0; - + /* move stderr to /dev/null */ if (close_stderr && -1 != (fd = open("/dev/null", O_WRONLY))) { @@ -90,33 +90,33 @@ int log_error_open(server *srv) { return 0; } -/** +/** * open the errorlog - * + * * if the open failed, report to the user and die * if no filename is given, use syslog instead - * + * */ int log_error_cycle(server *srv) { /* only cycle if we are not in syslog-mode */ - + if (srv->errorlog_mode == ERRORLOG_FILE) { const char *logfile = srv->srvconf.errorlog_file->ptr; /* already check of opening time */ - + int new_fd; - + if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { /* write to old log */ - log_error_write(srv, __FILE__, __LINE__, "SSSSS", + log_error_write(srv, __FILE__, __LINE__, "SSSSS", "cycling errorlog '", logfile, "' failed: ", strerror(errno), ", falling back to syslog()"); - + close(srv->errorlog_fd); srv->errorlog_fd = -1; -#ifdef HAVE_SYSLOG_H +#ifdef HAVE_SYSLOG_H srv->errorlog_mode = ERRORLOG_SYSLOG; #endif } else { @@ -125,15 +125,15 @@ int log_error_cycle(server *srv) { srv->errorlog_fd = new_fd; } } - + log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled"); - + return 0; } int log_error_close(server *srv) { log_error_write(srv, __FILE__, __LINE__, "s", "server stopped"); - + switch(srv->errorlog_mode) { case ERRORLOG_FILE: close(srv->errorlog_fd); @@ -146,13 +146,13 @@ int log_error_close(server *srv) { case ERRORLOG_STDERR: break; } - + return 0; } int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) { va_list ap; - + switch(srv->errorlog_mode) { case ERRORLOG_FILE: case ERRORLOG_STDERR: @@ -161,7 +161,7 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const buffer_prepare_copy(srv->ts_debug_str, 255); strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts))); srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1; - + srv->last_generated_debug_ts = srv->cur_ts; } @@ -173,19 +173,19 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "("); break; } - + buffer_append_string(srv->errorlog_buf, filename); BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "."); buffer_append_long(srv->errorlog_buf, line); BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") "); - - + + for(va_start(ap, fmt); *fmt; fmt++) { int d; char *s; buffer *b; off_t o; - + switch(*fmt) { case 's': /* string */ s = va_arg(ap, char *); @@ -227,7 +227,7 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const break; case '(': case ')': - case '<': + case '<': case '>': case ',': case ' ': @@ -236,7 +236,7 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const } } va_end(ap); - + switch(srv->errorlog_mode) { case ERRORLOG_FILE: BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n"); @@ -250,7 +250,7 @@ int log_error_write(server *srv, const char *filename, unsigned int line, const syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr); break; } - + return 0; } @@ -9,5 +9,5 @@ int log_error_open(server *srv); int log_error_close(server *srv); int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...); int log_error_cycle(server *srv); - + #endif diff --git a/src/mod_access.c b/src/mod_access.c index f3f7071..3fc0599 100644 --- a/src/mod_access.c +++ b/src/mod_access.c @@ -14,70 +14,70 @@ typedef struct { typedef struct { PLUGIN_DATA; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; INIT_FUNC(mod_access_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + return p; } FREE_FUNC(mod_access_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]; - + array_free(s->access_deny); - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } SETDEFAULTS_FUNC(mod_access_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "url.access-deny", NULL, T_CONFIG_ARRAY, 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->access_deny = array_init(); - + cv[0].destination = s->access_deny; - + 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; } @@ -88,25 +88,25 @@ static int mod_access_patch_connection(server *srv, connection *con, plugin_data plugin_config *s = p->config_storage[0]; PATCH(access_deny); - + /* 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("url.access-deny"))) { PATCH(access_deny); } } } - + return 0; } #undef PATCH @@ -115,19 +115,19 @@ URIHANDLER_FUNC(mod_access_uri_handler) { plugin_data *p = p_d; int s_len; size_t k; - + if (con->uri.path->used == 0) return HANDLER_GO_ON; - + mod_access_patch_connection(srv, con, p); - + s_len = con->uri.path->used - 1; - + for (k = 0; k < p->conf.access_deny->used; k++) { data_string *ds = (data_string *)p->conf.access_deny->data[k]; int ct_len = ds->value->used - 1; - + if (ct_len > s_len) continue; - + if (ds->value->used == 0) continue; /* if we have a case-insensitive FS we have to lower-case the URI here too */ @@ -135,18 +135,18 @@ URIHANDLER_FUNC(mod_access_uri_handler) { 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; } } else { if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) { con->http_status = 403; - + return HANDLER_FINISHED; } } } - + /* not found */ return HANDLER_GO_ON; } @@ -155,13 +155,13 @@ URIHANDLER_FUNC(mod_access_uri_handler) { int mod_access_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("access"); - + p->init = mod_access_init; p->set_defaults = mod_access_set_defaults; p->handle_uri_clean = mod_access_uri_handler; p->cleanup = mod_access_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_accesslog.c b/src/mod_accesslog.c index bdd0dbc..b00cf06 100644 --- a/src/mod_accesslog.c +++ b/src/mod_accesslog.c @@ -29,7 +29,7 @@ typedef struct { char key; - enum { + enum { FORMAT_UNSET, FORMAT_UNSUPPORTED, FORMAT_PERCENT, @@ -41,7 +41,7 @@ typedef struct { FORMAT_STATUS, FORMAT_BYTES_OUT_NO_HEADER, FORMAT_HEADER, - + FORMAT_REMOTE_ADDR, FORMAT_LOCAL_ADDR, FORMAT_COOKIE, @@ -59,20 +59,20 @@ typedef struct { FORMAT_CONNECTION_STATUS, FORMAT_BYTES_IN, FORMAT_BYTES_OUT, - + FORMAT_RESPONSE_HEADER } type; } format_mapping; /** - * - * + * + * * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" - * + * */ -const format_mapping fmap[] = -{ +const format_mapping fmap[] = +{ { '%', FORMAT_PERCENT }, { 'h', FORMAT_REMOTE_HOST }, { 'l', FORMAT_REMOTE_IDENT }, @@ -82,7 +82,7 @@ const format_mapping fmap[] = { 's', FORMAT_STATUS }, { 'b', FORMAT_BYTES_OUT_NO_HEADER }, { 'i', FORMAT_HEADER }, - + { 'a', FORMAT_REMOTE_ADDR }, { 'A', FORMAT_LOCAL_ADDR }, { 'B', FORMAT_BYTES_OUT_NO_HEADER }, @@ -103,23 +103,23 @@ const format_mapping fmap[] = { 'X', FORMAT_CONNECTION_STATUS }, { 'I', FORMAT_BYTES_IN }, { 'O', FORMAT_BYTES_OUT }, - + { 'o', FORMAT_RESPONSE_HEADER }, - + { '\0', FORMAT_UNSET } }; typedef struct { enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type; - + buffer *string; int field; } format_field; typedef struct { format_field **ptr; - + size_t used; size_t size; } format_fields; @@ -128,39 +128,39 @@ typedef struct { buffer *access_logfile; buffer *format; unsigned short use_syslog; - - + + int log_access_fd; time_t last_generated_accesslog_ts; time_t *last_generated_accesslog_ts_ptr; - - + + buffer *access_logbuffer; buffer *ts_accesslog_str; - + format_fields *parsed_format; } plugin_config; typedef struct { PLUGIN_DATA; - + plugin_config **config_storage; - plugin_config conf; + plugin_config conf; } plugin_data; INIT_FUNC(mod_accesslog_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + return p; } int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) { size_t i, j, k = 0, start = 0; - + for (i = 0; i < format->used - 1; i++) { - + switch(format->ptr[i]) { case '%': if (start != i) { @@ -173,19 +173,19 @@ int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) { fields->size += 16; fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * )); } - + fields->ptr[fields->used] = malloc(sizeof(format_fields)); fields->ptr[fields->used]->type = FIELD_STRING; fields->ptr[fields->used]->string = buffer_init(); - + buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start); - + fields->used++; } - - + + /* we need a new field */ - + if (fields->size == 0) { fields->size = 16; fields->used = 0; @@ -194,43 +194,43 @@ int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) { fields->size += 16; fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * )); } - + /* search for the terminating command */ switch (format->ptr[i+1]) { case '>': case '<': /* only for s */ - + for (j = 0; fmap[j].key != '\0'; j++) { if (fmap[j].key != format->ptr[i+2]) continue; - + /* found key */ - + fields->ptr[fields->used] = malloc(sizeof(format_fields)); fields->ptr[fields->used]->type = FIELD_FORMAT; fields->ptr[fields->used]->field = fmap[j].type; fields->ptr[fields->used]->string = NULL; - + fields->used++; - + break; } - + if (fmap[j].key == '\0') { log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed"); return -1; } - + start = i + 3; - + break; case '{': /* go forward to } */ - + for (k = i+2; k < format->used - 1; k++) { if (format->ptr[k] == '}') break; } - + if (k == format->used - 1) { log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed"); return -1; @@ -239,62 +239,62 @@ int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) { log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed"); return -1; } - + for (j = 0; fmap[j].key != '\0'; j++) { if (fmap[j].key != format->ptr[k+1]) continue; - + /* found key */ - + fields->ptr[fields->used] = malloc(sizeof(format_fields)); fields->ptr[fields->used]->type = FIELD_FORMAT; fields->ptr[fields->used]->field = fmap[j].type; fields->ptr[fields->used]->string = buffer_init(); - + buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2)); - + fields->used++; - + break; } - + if (fmap[j].key == '\0') { log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed"); return -1; } - + start = k + 2; - + break; default: for (j = 0; fmap[j].key != '\0'; j++) { if (fmap[j].key != format->ptr[i+1]) continue; - + /* found key */ - + fields->ptr[fields->used] = malloc(sizeof(format_fields)); fields->ptr[fields->used]->type = FIELD_FORMAT; fields->ptr[fields->used]->field = fmap[j].type; fields->ptr[fields->used]->string = NULL; - + fields->used++; - + break; } - + if (fmap[j].key == '\0') { log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed"); return -1; } - + start = i + 2; - + break; } - + break; } } - + if (start < i) { /* copy the string */ if (fields->size == 0) { @@ -305,32 +305,32 @@ int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) { fields->size += 16; fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * )); } - + fields->ptr[fields->used] = malloc(sizeof(format_fields)); fields->ptr[fields->used]->type = FIELD_STRING; fields->ptr[fields->used]->string = buffer_init(); - + buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start); - + fields->used++; } - + return 0; } FREE_FUNC(mod_accesslog_free) { plugin_data *p = p_d; size_t i; - + if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + if (s->access_logbuffer->used) { if (s->use_syslog) { # ifdef HAVE_SYSLOG_H @@ -342,14 +342,14 @@ FREE_FUNC(mod_accesslog_free) { write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1); } } - + if (s->log_access_fd != -1) close(s->log_access_fd); - + buffer_free(s->ts_accesslog_str); buffer_free(s->access_logbuffer); buffer_free(s->format); buffer_free(s->access_logfile); - + if (s->parsed_format) { size_t j; for (j = 0; j < s->parsed_format->used; j++) { @@ -359,36 +359,36 @@ FREE_FUNC(mod_accesslog_free) { free(s->parsed_format->ptr); free(s->parsed_format); } - + free(s); } - + free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } SETDEFAULTS_FUNC(log_access_open) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, { "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->access_logfile = buffer_init(); s->format = buffer_init(); @@ -397,44 +397,44 @@ SETDEFAULTS_FUNC(log_access_open) { s->log_access_fd = -1; s->last_generated_accesslog_ts = 0; s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts); - - + + cv[0].destination = s->access_logfile; cv[1].destination = &(s->use_syslog); cv[2].destination = s->format; - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } - + if (i == 0 && buffer_is_empty(s->format)) { /* set a default logfile string */ - + buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""); } - + /* parse */ - + if (s->format->used) { s->parsed_format = calloc(1, sizeof(*(s->parsed_format))); - + if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "parsing accesslog-definition failed:", s->format); return HANDLER_ERROR; } #if 0 - /* debugging */ + /* debugging */ for (j = 0; j < s->parsed_format->used; j++) { switch (s->parsed_format->ptr[j]->type) { case FIELD_FORMAT: - log_error_write(srv, __FILE__, __LINE__, "ssds", + log_error_write(srv, __FILE__, __LINE__, "ssds", "config:", "format", s->parsed_format->ptr[j]->field, - s->parsed_format->ptr[j]->string ? + s->parsed_format->ptr[j]->string ? s->parsed_format->ptr[j]->string->ptr : "" ); break; case FIELD_STRING: @@ -446,52 +446,52 @@ SETDEFAULTS_FUNC(log_access_open) { } #endif } - + if (s->use_syslog) { /* ignore the next checks */ continue; } - + if (buffer_is_empty(s->access_logfile)) continue; - + if (s->access_logfile->ptr[0] == '|') { #ifdef HAVE_FORK /* create write pipe and spawn process */ - + int to_log_fds[2]; pid_t pid; - + if (pipe(to_log_fds)) { log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno)); return HANDLER_ERROR; } - + /* fork, execve */ switch (pid = fork()) { - case 0: + case 0: /* child */ - + close(STDIN_FILENO); dup2(to_log_fds[0], STDIN_FILENO); close(to_log_fds[0]); /* not needed */ close(to_log_fds[1]); - + /* we don't need the client socket */ for (i = 3; i < 256; i++) { close(i); } - - /* exec the log-process (skip the | ) - * + + /* exec the log-process (skip the | ) + * */ - + execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL); - log_error_write(srv, __FILE__, __LINE__, "sss", - "spawning log-process failed: ", strerror(errno), + log_error_write(srv, __FILE__, __LINE__, "sss", + "spawning log-process failed: ", strerror(errno), s->access_logfile->ptr + 1); - + exit(-1); break; case -1: @@ -500,27 +500,27 @@ SETDEFAULTS_FUNC(log_access_open) { break; default: close(to_log_fds[0]); - + s->log_access_fd = to_log_fds[1]; - + break; } #else return -1; #endif - } else if (-1 == (s->log_access_fd = + } else if (-1 == (s->log_access_fd = open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { - - log_error_write(srv, __FILE__, __LINE__, "ssb", - "opening access-log failed:", + + log_error_write(srv, __FILE__, __LINE__, "ssb", + "opening access-log failed:", strerror(errno), s->access_logfile); - + return HANDLER_ERROR; } fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC); - + } - + return HANDLER_GO_ON; } @@ -529,7 +529,7 @@ SIGHUP_FUNC(log_access_cycle) { size_t i; if (!p->config_storage) return HANDLER_GO_ON; - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; @@ -544,26 +544,26 @@ SIGHUP_FUNC(log_access_cycle) { } else if (s->log_access_fd != -1) { write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1); } - + buffer_reset(s->access_logbuffer); } - + if (s->use_syslog == 0 && !buffer_is_empty(s->access_logfile) && s->access_logfile->ptr[0] != '|') { - + close(s->log_access_fd); - - if (-1 == (s->log_access_fd = + + if (-1 == (s->log_access_fd = open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) { - + log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno)); - + return HANDLER_ERROR; } } } - + return HANDLER_GO_ON; } @@ -572,7 +572,7 @@ SIGHUP_FUNC(log_access_cycle) { static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(access_logfile); PATCH(format); PATCH(log_access_fd); @@ -581,19 +581,19 @@ static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_d PATCH(ts_accesslog_str); PATCH(parsed_format); PATCH(use_syslog); - + /* 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("accesslog.filename"))) { PATCH(access_logfile); PATCH(log_access_fd); @@ -608,7 +608,7 @@ static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_d } } } - + return 0; } #undef PATCH @@ -617,17 +617,17 @@ REQUESTDONE_FUNC(log_access_write) { plugin_data *p = p_d; buffer *b; size_t j; - + int newts = 0; data_string *ds; - + mod_accesslog_patch_connection(srv, con, p); - + b = p->conf.access_logbuffer; if (b->used == 0) { buffer_copy_string(b, ""); } - + for (j = 0; j < p->conf.parsed_format->used; j++) { switch(p->conf.parsed_format->ptr[j]->type) { case FIELD_STRING: @@ -636,14 +636,14 @@ REQUESTDONE_FUNC(log_access_write) { case FIELD_FORMAT: switch(p->conf.parsed_format->ptr[j]->field) { case FORMAT_TIMESTAMP: - + /* cache the generated timestamp */ if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) { struct tm tm; #if defined(HAVE_STRUCT_TM_GMTOFF) long scd, hrs, min; #endif - + buffer_prepare_copy(p->conf.ts_accesslog_str, 255); #if defined(HAVE_STRUCT_TM_GMTOFF) # ifdef HAVE_LOCALTIME_R @@ -653,17 +653,17 @@ REQUESTDONE_FUNC(log_access_write) { strftime(p->conf.ts_accesslog_str->ptr, p->conf.ts_accesslog_str->size - 1, "[%d/%b/%Y:%H:%M:%S ", localtime_r(&(srv->cur_ts))); # endif p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1; - + buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-"); - + scd = abs(tm.tm_gmtoff); hrs = scd / 3600; min = (scd % 3600) / 60; - + /* hours */ if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0"); buffer_append_long(p->conf.ts_accesslog_str, hrs); - + if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0"); buffer_append_long(p->conf.ts_accesslog_str, min); BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]"); @@ -676,20 +676,20 @@ REQUESTDONE_FUNC(log_access_write) { #endif p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1; #endif - + *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts; newts = 1; } - + buffer_append_string_buffer(b, p->conf.ts_accesslog_str); - + break; case FORMAT_REMOTE_HOST: - + /* handle inet_ntop cache */ - + buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr))); - + break; case FORMAT_REMOTE_IDENT: /* ident */ @@ -710,10 +710,10 @@ REQUESTDONE_FUNC(log_access_write) { case FORMAT_STATUS: buffer_append_long(b, con->http_status); break; - + case FORMAT_BYTES_OUT_NO_HEADER: if (con->bytes_written > 0) { - buffer_append_off_t(b, + buffer_append_off_t(b, con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header); } else { BUFFER_APPEND_STRING_CONST(b, "-"); @@ -772,7 +772,7 @@ REQUESTDONE_FUNC(log_access_write) { } break; case FORMAT_REQUEST_PROTOCOL: - buffer_append_string(b, + buffer_append_string(b, con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0"); break; case FORMAT_REQUEST_METHOD: @@ -801,7 +801,7 @@ REQUESTDONE_FUNC(log_access_write) { { 'D', FORMAT_TIME_USED_MS }, { 'e', FORMAT_ENV }, */ - + break; } break; @@ -809,7 +809,7 @@ REQUESTDONE_FUNC(log_access_write) { break; } } - + BUFFER_APPEND_STRING_CONST(b, "\n"); if (p->conf.use_syslog || /* syslog doesn't cache */ @@ -828,7 +828,7 @@ REQUESTDONE_FUNC(log_access_write) { } buffer_reset(b); } - + return HANDLER_GO_ON; } @@ -836,15 +836,15 @@ REQUESTDONE_FUNC(log_access_write) { int mod_accesslog_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("accesslog"); - + p->init = mod_accesslog_init; p->set_defaults= log_access_open; p->cleanup = mod_accesslog_free; - + p->handle_request_done = log_access_write; p->handle_sighup = log_access_cycle; - + p->data = NULL; - + return 0; } diff --git a/src/mod_alias.c b/src/mod_alias.c index f56afeb..43b11c2 100644 --- a/src/mod_alias.c +++ b/src/mod_alias.c @@ -16,44 +16,44 @@ typedef struct { typedef struct { PLUGIN_DATA; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_alias_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - - - + + + return p; } /* detroy the plugin data */ FREE_FUNC(mod_alias_free) { plugin_data *p = p_d; - + 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]; - + array_free(s->alias); - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } @@ -62,25 +62,25 @@ FREE_FUNC(mod_alias_free) { SETDEFAULTS_FUNC(mod_alias_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); - s->alias = array_init(); + s->alias = array_init(); cv[0].destination = s->alias; - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } @@ -110,7 +110,7 @@ SETDEFAULTS_FUNC(mod_alias_set_defaults) { } } } - + return HANDLER_GO_ON; } @@ -119,27 +119,27 @@ SETDEFAULTS_FUNC(mod_alias_set_defaults) { static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(alias); - + /* 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("alias.url"))) { PATCH(alias); } } } - + return 0; } #undef PATCH @@ -149,37 +149,37 @@ PHYSICALPATH_FUNC(mod_alias_physical_handler) { int uri_len, basedir_len; char *uri_ptr; size_t k; - + if (con->physical.path->used == 0) return HANDLER_GO_ON; - + mod_alias_patch_connection(srv, con, p); - + /* not to include the tailing slash */ basedir_len = (con->physical.basedir->used - 1) - 1; uri_len = con->physical.path->used - 1 - basedir_len; uri_ptr = con->physical.path->ptr + basedir_len; - + for (k = 0; k < p->conf.alias->used; k++) { data_string *ds = (data_string *)p->conf.alias->data[k]; int alias_len = ds->key->used - 1; - + if (alias_len > uri_len) continue; if (ds->key->used == 0) continue; - + if (0 == (con->conf.force_lowercase_filenames ? strncasecmp(uri_ptr, ds->key->ptr, alias_len) : strncmp(uri_ptr, ds->key->ptr, alias_len))) { /* matched */ - + buffer_copy_string_buffer(con->physical.basedir, ds->value); buffer_copy_string_buffer(srv->tmp_buf, ds->value); buffer_append_string(srv->tmp_buf, uri_ptr + alias_len); buffer_copy_string_buffer(con->physical.path, srv->tmp_buf); - + return HANDLER_GO_ON; } } - + /* not found */ return HANDLER_GO_ON; } @@ -189,13 +189,13 @@ PHYSICALPATH_FUNC(mod_alias_physical_handler) { int mod_alias_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("alias"); - + p->init = mod_alias_init; p->handle_physical= mod_alias_physical_handler; p->set_defaults = mod_alias_set_defaults; p->cleanup = mod_alias_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_auth.c b/src/mod_auth.c index b075a2b..d7e8276 100644 --- a/src/mod_auth.c +++ b/src/mod_auth.c @@ -17,79 +17,79 @@ handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s); /** * the basic and digest auth framework - * + * * - config handling * - protocol handling - * - * http_auth.c - * http_auth_digest.c - * + * + * http_auth.c + * http_auth_digest.c + * * do the real work */ INIT_FUNC(mod_auth_init) { mod_auth_plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->tmp_buf = buffer_init(); - + p->auth_user = buffer_init(); #ifdef USE_LDAP p->ldap_filter = buffer_init(); #endif - + return p; } FREE_FUNC(mod_auth_free) { mod_auth_plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + buffer_free(p->tmp_buf); buffer_free(p->auth_user); #ifdef USE_LDAP buffer_free(p->ldap_filter); #endif - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { mod_auth_plugin_config *s = p->config_storage[i]; - + if (!s) continue; - + array_free(s->auth_require); buffer_free(s->auth_plain_groupfile); buffer_free(s->auth_plain_userfile); buffer_free(s->auth_htdigest_userfile); buffer_free(s->auth_htpasswd_userfile); buffer_free(s->auth_backend_conf); - + buffer_free(s->auth_ldap_hostname); buffer_free(s->auth_ldap_basedn); buffer_free(s->auth_ldap_binddn); buffer_free(s->auth_ldap_bindpw); buffer_free(s->auth_ldap_filter); buffer_free(s->auth_ldap_cafile); - + #ifdef USE_LDAP buffer_free(s->ldap_filter_pre); buffer_free(s->ldap_filter_post); - + if (s->ldap) ldap_unbind_s(s->ldap); #endif - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } @@ -118,19 +118,19 @@ static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plug PATCH(ldap_filter_pre); PATCH(ldap_filter_post); #endif - + /* 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("auth.backend"))) { PATCH(auth_backend); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) { @@ -163,7 +163,7 @@ static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plug } } } - + return 0; } #undef PATCH @@ -175,22 +175,22 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) { data_string *ds; mod_auth_plugin_data *p = p_d; array *req; - + /* select the right config */ mod_auth_patch_connection(srv, con, p); - + if (p->conf.auth_require == NULL) return HANDLER_GO_ON; - + /* * AUTH - * + * */ - + /* do we have to ask for auth ? */ - + auth_required = 0; auth_satisfied = 0; - + /* search auth-directives for path */ for (k = 0; k < p->conf.auth_require->used; k++) { buffer *require = p->conf.auth_require->data[k]->key; @@ -212,31 +212,31 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) { } } } - + /* nothing to do for us */ if (auth_required == 0) return HANDLER_GO_ON; - + req = ((data_array *)(p->conf.auth_require->data[k]))->value; - + /* try to get Authorization-header */ - + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) { http_authorization = ds->value->ptr; } - + if (ds && ds->value && ds->value->used) { char *auth_realm; data_string *method; - + method = (data_string *)array_get_element(req, "method"); - + /* parse auth-header */ if (NULL != (auth_realm = strchr(http_authorization, ' '))) { int auth_type_len = auth_realm - http_authorization; - + if ((auth_type_len == 5) && (0 == strncmp(http_authorization, "Basic", auth_type_len))) { - + if (0 == strcmp(method->value->ptr, "basic")) { auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1); } @@ -245,43 +245,43 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) { if (0 == strcmp(method->value->ptr, "digest")) { if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) { con->http_status = 400; - + /* a field was missing */ - + return HANDLER_FINISHED; } } } else { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "unknown authentification type:", http_authorization); } } } - + if (!auth_satisfied) { data_string *method, *realm; method = (data_string *)array_get_element(req, "method"); realm = (data_string *)array_get_element(req, "realm"); - + con->http_status = 401; - + if (0 == strcmp(method->value->ptr, "basic")) { buffer_copy_string(p->tmp_buf, "Basic realm=\""); buffer_append_string_buffer(p->tmp_buf, realm->value); buffer_append_string(p->tmp_buf, "\""); - + response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf)); } else if (0 == strcmp(method->value->ptr, "digest")) { char hh[33]; http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh); - + buffer_copy_string(p->tmp_buf, "Digest realm=\""); buffer_append_string_buffer(p->tmp_buf, realm->value); buffer_append_string(p->tmp_buf, "\", nonce=\""); buffer_append_string(p->tmp_buf, hh); buffer_append_string(p->tmp_buf, "\", qop=\"auth\""); - + response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf)); } else { /* evil */ @@ -289,18 +289,18 @@ static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) { return HANDLER_FINISHED; } else { /* the REMOTE_USER header */ - + buffer_copy_string_buffer(con->authed_user, p->auth_user); } - + return HANDLER_GO_ON; } SETDEFAULTS_FUNC(mod_auth_set_defaults) { mod_auth_plugin_data *p = p_d; size_t i; - - config_values_t cv[] = { + + config_values_t cv[] = { { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, @@ -317,7 +317,7 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 13 */ { 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++) { @@ -325,14 +325,14 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { size_t n; data_array *da; array *ca; - + s = calloc(1, sizeof(mod_auth_plugin_config)); s->auth_plain_groupfile = buffer_init(); s->auth_plain_userfile = buffer_init(); s->auth_htdigest_userfile = buffer_init(); s->auth_htpasswd_userfile = buffer_init(); s->auth_backend_conf = buffer_init(); - + s->auth_ldap_hostname = buffer_init(); s->auth_ldap_basedn = buffer_init(); s->auth_ldap_binddn = buffer_init(); @@ -341,15 +341,15 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { s->auth_ldap_cafile = buffer_init(); s->auth_ldap_starttls = 0; s->auth_debug = 0; - + s->auth_require = array_init(); - + #ifdef USE_LDAP s->ldap_filter_pre = buffer_init(); s->ldap_filter_post = buffer_init(); s->ldap = NULL; #endif - + cv[0].destination = s->auth_backend_conf; cv[1].destination = s->auth_plain_groupfile; cv[2].destination = s->auth_plain_userfile; @@ -364,14 +364,14 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { cv[11].destination = s->auth_htdigest_userfile; cv[12].destination = s->auth_htpasswd_userfile; cv[13].destination = &(s->auth_debug); - + p->config_storage[i] = s; ca = ((data_config *)srv->config_context->data[i])->value; - + if (0 != config_insert_values_global(srv, ca, cv)) { return HANDLER_ERROR; } - + if (s->auth_backend_conf->used) { if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) { s->auth_backend = AUTH_BACKEND_HTPASSWD; @@ -383,31 +383,31 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { s->auth_backend = AUTH_BACKEND_LDAP; } else { log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf); - + return HANDLER_ERROR; } } /* no auth.require for this section */ if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue; - + if (da->type != TYPE_ARRAY) continue; - + for (n = 0; n < da->value->used; n++) { size_t m; data_array *da_file = (data_array *)da->value->data[n]; const char *method, *realm, *require; - + if (da->value->data[n]->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "ss", - "auth.require should contain an array as in:", + log_error_write(srv, __FILE__, __LINE__, "ss", + "auth.require should contain an array as in:", "auth.require = ( \"...\" => ( ..., ...) )"); return HANDLER_ERROR; } - + method = realm = require = NULL; - + for (m = 0; m < da_file->value->used; m++) { if (da_file->value->data[m]->type == TYPE_STRING) { if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) { @@ -417,8 +417,8 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) { require = ((data_string *)(da_file->value->data[m]))->value->ptr; } else { - log_error_write(srv, __FILE__, __LINE__, "ssbs", - "the field is unknown in:", + log_error_write(srv, __FILE__, __LINE__, "ssbs", + "the field is unknown in:", "auth.require = ( \"...\" => ( ..., -> \"", da_file->value->data[m]->key, "\" <- => \"...\" ) )"); @@ -426,19 +426,19 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { return HANDLER_ERROR; } } else { - log_error_write(srv, __FILE__, __LINE__, "ssbs", - "a string was expected for:", + log_error_write(srv, __FILE__, __LINE__, "ssbs", + "a string was expected for:", "auth.require = ( \"...\" => ( ..., -> \"", da_file->value->data[m]->key, "\" <- => \"...\" ) )"); - + return HANDLER_ERROR; } } - + if (method == NULL) { - log_error_write(srv, __FILE__, __LINE__, "ss", - "the require field is missing in:", + log_error_write(srv, __FILE__, __LINE__, "ss", + "the require field is missing in:", "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )"); return HANDLER_ERROR; } else { @@ -450,60 +450,60 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { return HANDLER_ERROR; } } - + if (realm == NULL) { - log_error_write(srv, __FILE__, __LINE__, "ss", - "the require field is missing in:", + log_error_write(srv, __FILE__, __LINE__, "ss", + "the require field is missing in:", "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )"); return HANDLER_ERROR; } - + if (require == NULL) { - log_error_write(srv, __FILE__, __LINE__, "ss", - "the require field is missing in:", + log_error_write(srv, __FILE__, __LINE__, "ss", + "the require field is missing in:", "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )"); return HANDLER_ERROR; } - + if (method && realm && require) { data_string *ds; data_array *a; - + a = data_array_init(); buffer_copy_string_buffer(a->key, da_file->key); - + ds = data_string_init(); - + buffer_copy_string(ds->key, "method"); buffer_copy_string(ds->value, method); - + array_insert_unique(a->value, (data_unset *)ds); - + ds = data_string_init(); - + buffer_copy_string(ds->key, "realm"); buffer_copy_string(ds->value, realm); - + array_insert_unique(a->value, (data_unset *)ds); - + ds = data_string_init(); - + buffer_copy_string(ds->key, "require"); buffer_copy_string(ds->value, require); - + array_insert_unique(a->value, (data_unset *)ds); - + array_insert_unique(s->auth_require, (data_unset *)a); } } - + switch(s->auth_backend) { case AUTH_BACKEND_PLAIN: if (s->auth_plain_userfile->used) { int fd; /* try to read */ if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) { - log_error_write(srv, __FILE__, __LINE__, "sbss", + log_error_write(srv, __FILE__, __LINE__, "sbss", "opening auth.backend.plain.userfile:", s->auth_plain_userfile, "failed:", strerror(errno)); return HANDLER_ERROR; @@ -516,7 +516,7 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { int fd; /* try to read */ if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) { - log_error_write(srv, __FILE__, __LINE__, "sbss", + log_error_write(srv, __FILE__, __LINE__, "sbss", "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile, "failed:", strerror(errno)); return HANDLER_ERROR; @@ -529,7 +529,7 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { int fd; /* try to read */ if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) { - log_error_write(srv, __FILE__, __LINE__, "sbss", + log_error_write(srv, __FILE__, __LINE__, "sbss", "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile, "failed:", strerror(errno)); return HANDLER_ERROR; @@ -554,75 +554,75 @@ SETDEFAULTS_FUNC(mod_auth_set_defaults) { handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) { #ifdef USE_LDAP int ret; -#if 0 +#if 0 if (s->auth_ldap_basedn->used == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set"); - + return HANDLER_ERROR; } #endif - + if (s->auth_ldap_filter->used) { char *dollar; - + /* parse filter */ - + if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) { log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'"); - + return HANDLER_ERROR; } - + buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr); buffer_copy_string(s->ldap_filter_post, dollar+1); } - + if (s->auth_ldap_hostname->used) { if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno)); - + return HANDLER_ERROR; } - + ret = LDAP_VERSION3; if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret)); - + return HANDLER_ERROR; } if (s->auth_ldap_starttls) { - /* if no CA file is given, it is ok, as we will use encryption + /* if no CA file is given, it is ok, as we will use encryption * if the server requires a CAfile it will tell us */ if (!buffer_is_empty(s->auth_ldap_cafile)) { - if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, + if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, s->auth_ldap_cafile->ptr))) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "Loading CA certificate failed:", ldap_err2string(ret)); - + return HANDLER_ERROR; } } - + if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL, NULL))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret)); - + return HANDLER_ERROR; } } - - + + /* 1. */ if (s->auth_ldap_binddn->used) { if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret)); - + return HANDLER_ERROR; } } else { if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) { log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret)); - + return HANDLER_ERROR; } } @@ -641,8 +641,8 @@ int mod_auth_plugin_init(plugin *p) { p->set_defaults = mod_auth_set_defaults; p->handle_uri_clean = mod_auth_uri_handler; p->cleanup = mod_auth_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_cgi.c b/src/mod_cgi.c index 15aca3c..a6f8756 100644 --- a/src/mod_cgi.c +++ b/src/mod_cgi.c @@ -40,7 +40,7 @@ enum {EOL_UNSET, EOL_N, EOL_RN}; typedef struct { char **ptr; - + size_t size; size_t used; } char_array; @@ -58,23 +58,23 @@ typedef struct { typedef struct { PLUGIN_DATA; buffer_pid_t cgi_pid; - + buffer *tmp_buf; buffer *parse_response; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; typedef struct { pid_t pid; int fd; int fde_ndx; /* index into the fd-event buffer */ - + connection *remote_conn; /* dumb pointer */ plugin_data *plugin_data; /* dumb pointer */ - + buffer *response; buffer *response_header; } handler_ctx; @@ -83,17 +83,17 @@ static handler_ctx * cgi_handler_ctx_init() { handler_ctx *hctx = calloc(1, sizeof(*hctx)); assert(hctx); - + hctx->response = buffer_init(); hctx->response_header = buffer_init(); - + return hctx; } static void cgi_handler_ctx_free(handler_ctx *hctx) { buffer_free(hctx->response); buffer_free(hctx->response_header); - + free(hctx); } @@ -101,14 +101,14 @@ enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINIS INIT_FUNC(mod_cgi_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); assert(p); - + p->tmp_buf = buffer_init(); p->parse_response = buffer_init(); - + return p; } @@ -116,62 +116,62 @@ INIT_FUNC(mod_cgi_init) { FREE_FUNC(mod_cgi_free) { plugin_data *p = p_d; buffer_pid_t *r = &(p->cgi_pid); - + UNUSED(srv); - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; - + array_free(s->cgi); - + free(s); } free(p->config_storage); } - + if (r->ptr) free(r->ptr); - + buffer_free(p->tmp_buf); buffer_free(p->parse_response); - + free(p); - + return HANDLER_GO_ON; } SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET} }; if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); assert(s); - + s->cgi = array_init(); - + cv[0].destination = s->cgi; - + 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; } @@ -180,13 +180,13 @@ static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) { int m = -1; size_t i; buffer_pid_t *r = &(p->cgi_pid); - + UNUSED(srv); for (i = 0; i < r->used; i++) { if (r->ptr[i] > m) m = r->ptr[i]; } - + if (r->size == 0) { r->size = 16; r->ptr = malloc(sizeof(*r->ptr) * r->size); @@ -194,31 +194,31 @@ static int cgi_pid_add(server *srv, plugin_data *p, pid_t pid) { r->size += 16; r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size); } - + r->ptr[r->used++] = pid; - + return m; } static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) { size_t i; buffer_pid_t *r = &(p->cgi_pid); - + UNUSED(srv); for (i = 0; i < r->used; i++) { if (r->ptr[i] == pid) break; } - + if (i != r->used) { /* found */ - + if (i != r->used - 1) { r->ptr[i] = r->ptr[r->used - 1]; } r->used--; } - + return 0; } @@ -226,32 +226,32 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff char *ns; const char *s; int line = 0; - + UNUSED(srv); - + buffer_copy_string_buffer(p->parse_response, in); - - for (s = p->parse_response->ptr; - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); + + for (s = p->parse_response->ptr; + NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); s = ns + (eol == EOL_RN ? 2 : 1), line++) { const char *key, *value; int key_len; data_string *ds; - + ns[0] = '\0'; - - if (line == 0 && + + if (line == 0 && 0 == strncmp(s, "HTTP/1.", 7)) { /* non-parsed header ... we parse them anyway */ - + if ((s[7] == '1' || s[7] == '0') && s[8] == ' ') { int status; /* after the space should be a status code for us */ - + status = strtol(s+9, NULL, 10); - + if (con->http_status >= 100 && con->http_status < 1000) { /* we expected 3 digits and didn't got them */ @@ -260,27 +260,27 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff } } } else { - + key = s; if (NULL == (value = strchr(s, ':'))) { /* we expect: "<key>: <value>\r\n" */ continue; } - + key_len = value - key; value += 1; - + /* skip LWS */ while (*value == ' ' || *value == '\t') value++; - + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { ds = data_response_init(); } buffer_copy_string_len(ds->key, key, key_len); buffer_copy_string(ds->value, value); - + array_insert_unique(con->response.headers, (data_unset *)ds); - + switch(key_len) { case 4: if (0 == strncasecmp(key, "Date", key_len)) { @@ -315,13 +315,13 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff } } } - + /* CGI/1.1 rev 03 - 7.2.1.2 */ if ((con->parsed_response & HTTP_LOCATION) && !(con->parsed_response & HTTP_STATUS)) { con->http_status = 302; } - + return 0; } @@ -329,10 +329,10 @@ static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buff static int cgi_demux_response(server *srv, handler_ctx *hctx) { plugin_data *p = hctx->plugin_data; connection *con = hctx->remote_conn; - + while(1) { int n; - + buffer_prepare_copy(hctx->response, 1024); if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) { if (errno == EAGAIN || errno == EINTR) { @@ -343,125 +343,125 @@ static int cgi_demux_response(server *srv, handler_ctx *hctx) { log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd); return FDEVENT_HANDLED_ERROR; } - + if (n == 0) { /* read finished */ - + con->file_finished = 1; - + /* send final chunk */ http_chunk_append_mem(srv, con, NULL, 0); joblist_append(srv, con); - + return FDEVENT_HANDLED_FINISHED; } - + hctx->response->ptr[n] = '\0'; hctx->response->used = n+1; - + /* split header from body */ - + if (con->file_started == 0) { char *c; int in_header = 0; int header_end = 0; int cp, eol = EOL_UNSET; size_t used = 0; - + buffer_append_string_buffer(hctx->response_header, hctx->response); - + /* nph (non-parsed headers) */ if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1; - + /* search for the \r\n\r\n or \n\n in the string */ for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) { if (*c == ':') in_header = 1; else if (*c == '\n') { if (in_header == 0) { /* got a response without a response header */ - + c = NULL; header_end = 1; break; } - + if (eol == EOL_UNSET) eol = EOL_N; - + if (*(c+1) == '\n') { header_end = 1; break; } - + } else if (used > 1 && *c == '\r' && *(c+1) == '\n') { if (in_header == 0) { /* got a response without a response header */ - + c = NULL; header_end = 1; break; } - + if (eol == EOL_UNSET) eol = EOL_RN; - + if (used > 3 && - *(c+2) == '\r' && + *(c+2) == '\r' && *(c+3) == '\n') { header_end = 1; break; } - + /* skip the \n */ c++; cp++; used--; } } - + if (header_end) { if (c == NULL) { /* no header, but a body */ - + if (con->request.http_version == HTTP_VERSION_1_1) { con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; } - + http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used); joblist_append(srv, con); } else { size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2); size_t blen = hctx->response_header->used - hlen - 1; - + /* a small hack: terminate after at the second \r */ hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1); hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0'; - + /* parse the response header */ cgi_response_parse(srv, con, p, hctx->response_header, eol); - + /* enable chunked-transfer-encoding */ if (con->request.http_version == HTTP_VERSION_1_1 && !(con->parsed_response & HTTP_CONTENT_LENGTH)) { con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; } - + if ((hctx->response->used != hlen) && blen > 0) { http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1); joblist_append(srv, con); } } - + con->file_started = 1; } } else { http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used); joblist_append(srv, con); } - -#if 0 + +#if 0 log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr); #endif } - + return FDEVENT_HANDLED_NOT_FINISHED; } @@ -470,42 +470,42 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { pid_t pid; plugin_data *p; connection *con; - + if (NULL == hctx) return HANDLER_GO_ON; - + p = hctx->plugin_data; con = hctx->remote_conn; - + if (con->mode != p->id) return HANDLER_GO_ON; #ifndef __WIN32 - + /* the connection to the browser went away, but we still have a connection - * to the CGI script + * to the CGI script * * close cgi-connection */ - + if (hctx->fd != -1) { /* close connection to the cgi-script */ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); fdevent_unregister(srv->ev, hctx->fd); - + if (close(hctx->fd)) { log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno)); } - + hctx->fd = -1; hctx->fde_ndx = -1; } - + pid = hctx->pid; - + con->plugin_ctx[p->id] = NULL; - + /* is this a good idea ? */ cgi_handler_ctx_free(hctx); - + /* if waitpid hasn't been called by response.c yet, do it here */ if (pid) { /* check if the CGI-script is already gone */ @@ -519,19 +519,19 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { case -1: /* */ if (errno == EINTR) break; - - /* - * errno == ECHILD happens if _subrequest catches the process-status before + + /* + * errno == ECHILD happens if _subrequest catches the process-status before * we have read the response of the cgi process - * + * * -> catch status * -> WAIT_FOR_EVENT * -> read response * -> we get here with waitpid == ECHILD - * + * */ if (errno == ECHILD) return HANDLER_GO_ON; - + log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno)); return HANDLER_ERROR; default: @@ -541,13 +541,13 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { con->http_status = 500; con->mode = DIRECT; } - + if (WIFEXITED(status)) { #if 0 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid); #endif pid = 0; - + return HANDLER_GO_ON; } else { log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid); @@ -555,20 +555,20 @@ static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) { return HANDLER_GO_ON; } } - - + + kill(pid, SIGTERM); - + /* cgi-script is still alive, queue the PID for removal */ cgi_pid_add(srv, p, pid); } -#endif +#endif return HANDLER_GO_ON; } static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - + return cgi_connection_close(srv, con->plugin_ctx[p->id]); } @@ -577,43 +577,43 @@ static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) { server *srv = (server *)s; handler_ctx *hctx = ctx; connection *con = hctx->remote_conn; - + joblist_append(srv, con); - + if (hctx->fd == -1) { log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd"); - + return HANDLER_ERROR; } - + if (revents & FDEVENT_IN) { switch (cgi_demux_response(srv, hctx)) { case FDEVENT_HANDLED_NOT_FINISHED: break; case FDEVENT_HANDLED_FINISHED: /* we are done */ - + #if 0 log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished"); #endif cgi_connection_close(srv, hctx); - - /* if we get a IN|HUP and have read everything don't exec the close twice */ + + /* if we get a IN|HUP and have read everything don't exec the close twice */ return HANDLER_FINISHED; case FDEVENT_HANDLED_ERROR: connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); con->http_status = 500; con->mode = DIRECT; - + log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: "); break; } } - + if (revents & FDEVENT_OUT) { /* nothing to do */ } - + /* perhaps this issue is already handled */ if (revents & FDEVENT_HUP) { /* check if we still have a unfinished header package which is a body in reality */ @@ -623,54 +623,54 @@ static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) { http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used); joblist_append(srv, con); } - + if (con->file_finished == 0) { http_chunk_append_mem(srv, con, NULL, 0); joblist_append(srv, con); } - + con->file_finished = 1; - + if (chunkqueue_is_empty(con->write_queue)) { /* there is nothing left to write */ connection_set_state(srv, con, CON_STATE_RESPONSE_END); } else { /* used the write-handler to finish the request on demand */ - + } - + # if 0 log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents); # endif - + /* rtsigs didn't liked the close */ cgi_connection_close(srv, hctx); } else if (revents & FDEVENT_ERR) { con->file_finished = 1; - + /* kill all connections to the cgi process */ cgi_connection_close(srv, hctx); #if 1 log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR"); -#endif +#endif return HANDLER_ERROR; } - + return HANDLER_FINISHED; } static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) { char *dst; - + if (!key || !val) return -1; - + dst = malloc(key_len + val_len + 3); memcpy(dst, key, key_len); dst[key_len] = '='; /* add the \0 from the value */ memcpy(dst + key_len + 1, val, val_len + 1); - + if (env->size == 0) { env->size = 16; env->ptr = malloc(env->size * sizeof(*env->ptr)); @@ -678,45 +678,45 @@ static int cgi_env_add(char_array *env, const char *key, size_t key_len, const c env->size += 16; env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); } - + env->ptr[env->used++] = dst; - + return 0; } static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) { pid_t pid; - + #ifdef HAVE_IPV6 char b2[INET6_ADDRSTRLEN + 1]; #endif - + int to_cgi_fds[2]; int from_cgi_fds[2]; struct stat st; - -#ifndef __WIN32 - + +#ifndef __WIN32 + if (cgi_handler->used > 1) { /* stat the exec file */ if (-1 == (stat(cgi_handler->ptr, &st))) { - log_error_write(srv, __FILE__, __LINE__, "sbss", + log_error_write(srv, __FILE__, __LINE__, "sbss", "stat for cgi-handler", cgi_handler, "failed:", strerror(errno)); return -1; } } - + if (pipe(to_cgi_fds)) { log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno)); return -1; } - + if (pipe(from_cgi_fds)) { log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno)); return -1; } - + /* fork, execve */ switch (pid = fork()) { case 0: { @@ -730,22 +730,22 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * char *c; const char *s; server_socket *srv_sock = con->srv_socket; - + /* move stdout to from_cgi_fd[1] */ close(STDOUT_FILENO); dup2(from_cgi_fds[1], STDOUT_FILENO); close(from_cgi_fds[1]); /* not needed */ close(from_cgi_fds[0]); - + /* move the stdin to to_cgi_fd[0] */ close(STDIN_FILENO); dup2(to_cgi_fds[0], STDIN_FILENO); close(to_cgi_fds[0]); /* not needed */ close(to_cgi_fds[1]); - - /* HACK: + + /* HACK: * this is not nice, but it works * * we feed the stderr of the CGI to our errorlog, if possible @@ -754,20 +754,20 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * close(STDERR_FILENO); dup2(srv->errorlog_fd, STDERR_FILENO); } - + /* create environment */ env.ptr = NULL; env.size = 0; env.used = 0; - + cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION)); if (!buffer_is_empty(con->server_name)) { cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name)); } else { #ifdef HAVE_IPV6 - s = inet_ntop(srv_sock->addr.plain.sa_family, - srv_sock->addr.plain.sa_family == AF_INET6 ? + s = inet_ntop(srv_sock->addr.plain.sa_family, + srv_sock->addr.plain.sa_family == AF_INET6 ? (const void *) &(srv_sock->addr.ipv6.sin6_addr) : (const void *) &(srv_sock->addr.ipv4.sin_addr), b2, sizeof(b2)-1); @@ -779,10 +779,10 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")); s = get_http_version_name(con->request.http_version); - + cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)); - - ltostr(buf, + + ltostr(buf, #ifdef HAVE_IPV6 ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port) #else @@ -790,10 +790,10 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * #endif ); cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf)); - + #ifdef HAVE_IPV6 - s = inet_ntop(srv_sock->addr.plain.sa_family, - srv_sock->addr.plain.sa_family == AF_INET6 ? + s = inet_ntop(srv_sock->addr.plain.sa_family, + srv_sock->addr.plain.sa_family == AF_INET6 ? (const void *) &(srv_sock->addr.ipv6.sin6_addr) : (const void *) &(srv_sock->addr.ipv4.sin_addr), b2, sizeof(b2)-1); @@ -815,11 +815,11 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * if (!buffer_is_empty(con->request.orig_uri)) { cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); } - - + + #ifdef HAVE_IPV6 - s = inet_ntop(con->dst_addr.plain.sa_family, - con->dst_addr.plain.sa_family == AF_INET6 ? + s = inet_ntop(con->dst_addr.plain.sa_family, + con->dst_addr.plain.sa_family == AF_INET6 ? (const void *) &(con->dst_addr.ipv6.sin6_addr) : (const void *) &(con->dst_addr.ipv4.sin_addr), b2, sizeof(b2)-1); @@ -828,7 +828,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * #endif cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s)); - ltostr(buf, + ltostr(buf, #ifdef HAVE_IPV6 ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port) #else @@ -836,19 +836,19 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * #endif ); cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf)); - + if (!buffer_is_empty(con->authed_user)) { cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"), CONST_BUF_LEN(con->authed_user)); } - + /* request.content_length < SSIZE_MAX, see request.c */ ltostr(buf, con->request.content_length); cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)); cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path)); cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root)); - + /* for valgrind */ if (NULL != (s = getenv("LD_PRELOAD"))) { cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s)); @@ -863,24 +863,24 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s)); } #endif - + for (n = 0; n < con->request.headers->used; n++) { data_string *ds; - + ds = (data_string *)con->request.headers->data[n]; - + if (ds->value->used && ds->key->used) { size_t j; - + buffer_reset(p->tmp_buf); - + if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) { buffer_copy_string(p->tmp_buf, "HTTP_"); p->tmp_buf->used--; /* strip \0 after HTTP_ */ } - + buffer_prepare_append(p->tmp_buf, ds->key->used + 2); - + for (j = 0; j < ds->key->used - 1; j++) { char cr = '_'; if (light_isalpha(ds->key->ptr[j])) { @@ -893,46 +893,46 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * p->tmp_buf->ptr[p->tmp_buf->used++] = cr; } p->tmp_buf->ptr[p->tmp_buf->used++] = '\0'; - + cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value)); } } - + for (n = 0; n < con->environment->used; n++) { data_string *ds; - + ds = (data_string *)con->environment->data[n]; - + if (ds->value->used && ds->key->used) { size_t j; - + buffer_reset(p->tmp_buf); - + buffer_prepare_append(p->tmp_buf, ds->key->used + 2); - + for (j = 0; j < ds->key->used - 1; j++) { - p->tmp_buf->ptr[p->tmp_buf->used++] = - isalpha((unsigned char)ds->key->ptr[j]) ? + p->tmp_buf->ptr[p->tmp_buf->used++] = + isalpha((unsigned char)ds->key->ptr[j]) ? toupper((unsigned char)ds->key->ptr[j]) : '_'; } p->tmp_buf->ptr[p->tmp_buf->used++] = '\0'; - + cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value)); } } - + if (env.size == env.used) { env.size += 16; env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr)); } - + env.ptr[env.used] = NULL; - + /* set up args */ argc = 3; args = malloc(sizeof(*args) * argc); i = 0; - + if (cgi_handler->used > 1) { args[i++] = cgi_handler->ptr; } @@ -942,7 +942,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * /* search for the last / */ if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) { *c = '\0'; - + /* change to the physical directory */ if (-1 == chdir(con->physical.path->ptr)) { log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path); @@ -954,12 +954,12 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * for (i = 3; i < 256; i++) { if (i != srv->errorlog_fd) close(i); } - + /* exec the cgi */ execve(args[0], args, env.ptr); - + log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]); - + /* */ SEGFAULT(); break; @@ -974,11 +974,11 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * close(from_cgi_fds[1]); close(to_cgi_fds[0]); - + if (con->request.content_length) { chunkqueue *cq = con->request_content_queue; chunk *c; - + assert(chunkqueue_length(cq) == (off_t)con->request.content_length); /* there is content to send */ @@ -993,16 +993,16 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * if (-1 == c->file.fd && /* open the file if not already open */ -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); - + close(from_cgi_fds[0]); close(to_cgi_fds[1]); return -1; } c->file.mmap.length = c->file.length; - + if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) { - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ", strerror(errno), c->file.name, c->file.fd); close(from_cgi_fds[0]); @@ -1012,7 +1012,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * close(c->file.fd); c->file.fd = -1; - + /* chunk_reset() or chunk_free() will cleanup for us */ } @@ -1020,7 +1020,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * switch(errno) { case ENOSPC: con->http_status = 507; - + break; default: con->http_status = 403; @@ -1033,7 +1033,7 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * switch(errno) { case ENOSPC: con->http_status = 507; - + break; default: con->http_status = 403; @@ -1056,45 +1056,45 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * } close(to_cgi_fds[1]); - + /* register PID and wait for them asyncronously */ con->mode = p->id; buffer_reset(con->physical.path); - + hctx = cgi_handler_ctx_init(); - + hctx->remote_conn = con; hctx->plugin_data = p; hctx->pid = pid; hctx->fd = from_cgi_fds[0]; hctx->fde_ndx = -1; - + con->plugin_ctx[p->id] = hctx; - + fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx); fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); - + if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); - + fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); fdevent_unregister(srv->ev, hctx->fd); - + log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd); - + close(hctx->fd); - + cgi_handler_ctx_free(hctx); - + con->plugin_ctx[p->id] = NULL; - + return -1; } - + break; } } - + return 0; #else return -1; @@ -1106,27 +1106,27 @@ static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer * static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(cgi); - + /* 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("cgi.assign"))) { PATCH(cgi); } } } - + return 0; } #undef PATCH @@ -1135,24 +1135,24 @@ URIHANDLER_FUNC(cgi_is_handled) { size_t k, s_len; plugin_data *p = p_d; buffer *fn = con->physical.path; - + if (fn->used == 0) return HANDLER_GO_ON; - + mod_cgi_patch_connection(srv, con, p); - + s_len = fn->used - 1; - + for (k = 0; k < p->conf.cgi->used; k++) { data_string *ds = (data_string *)p->conf.cgi->data[k]; size_t ct_len = ds->key->used - 1; - + if (ds->key->used == 0) continue; if (s_len < ct_len) continue; - + if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) { if (cgi_create_env(srv, con, p, ds->value)) { con->http_status = 500; - + buffer_reset(con->physical.path); return HANDLER_FINISHED; } @@ -1160,7 +1160,7 @@ URIHANDLER_FUNC(cgi_is_handled) { break; } } - + return HANDLER_GO_ON; } @@ -1172,7 +1172,7 @@ TRIGGER_FUNC(cgi_trigger) { for (ndx = 0; ndx < p->cgi_pid.used; ndx++) { int status; - + switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) { case 0: /* not finished yet */ @@ -1182,7 +1182,7 @@ TRIGGER_FUNC(cgi_trigger) { break; case -1: log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno)); - + return HANDLER_ERROR; default: @@ -1193,16 +1193,16 @@ TRIGGER_FUNC(cgi_trigger) { } else { log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?"); } - + cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]); - /* del modified the buffer structure + /* del modified the buffer structure * and copies the last entry to the current one * -> recheck the current index */ ndx--; } } -#endif +#endif return HANDLER_GO_ON; } @@ -1210,15 +1210,15 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) { int status; plugin_data *p = p_d; handler_ctx *hctx = con->plugin_ctx[p->id]; - + if (con->mode != p->id) return HANDLER_GO_ON; if (NULL == hctx) return HANDLER_GO_ON; - + #if 0 log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid); -#endif +#endif if (hctx->pid == 0) return HANDLER_FINISHED; -#ifndef __WIN32 +#ifndef __WIN32 switch(waitpid(hctx->pid, &status, WNOHANG)) { case 0: /* we only have for events here if we don't have the header yet, @@ -1228,61 +1228,61 @@ SUBREQUEST_FUNC(mod_cgi_handle_subrequest) { return HANDLER_WAIT_FOR_EVENT; case -1: if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT; - + if (errno == ECHILD && con->file_started == 0) { /* - * second round but still not response + * second round but still not response */ - return HANDLER_WAIT_FOR_EVENT; + return HANDLER_WAIT_FOR_EVENT; } - + log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno)); con->mode = DIRECT; con->http_status = 500; - + hctx->pid = 0; - + fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); fdevent_unregister(srv->ev, hctx->fd); - + if (close(hctx->fd)) { log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno)); } - + cgi_handler_ctx_free(hctx); - + con->plugin_ctx[p->id] = NULL; - + return HANDLER_FINISHED; default: - /* cgi process exited cleanly - * - * check if we already got the response + /* cgi process exited cleanly + * + * check if we already got the response */ - + if (!con->file_started) return HANDLER_WAIT_FOR_EVENT; - + if (WIFEXITED(status)) { /* nothing */ } else { log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?"); - + con->mode = DIRECT; con->http_status = 500; - + } - + hctx->pid = 0; - + fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); fdevent_unregister(srv->ev, hctx->fd); - + if (close(hctx->fd)) { log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno)); } - + cgi_handler_ctx_free(hctx); - + con->plugin_ctx[p->id] = NULL; return HANDLER_FINISHED; } @@ -1306,8 +1306,8 @@ int mod_cgi_plugin_init(plugin *p) { p->init = mod_cgi_init; p->cleanup = mod_cgi_free; p->set_defaults = mod_fastcgi_set_defaults; - + p->data = NULL; - + return 0; } diff --git a/src/mod_cml.c b/src/mod_cml.c index f5b1768..2221368 100644 --- a/src/mod_cml.c +++ b/src/mod_cml.c @@ -20,50 +20,50 @@ /* init the plugin data */ INIT_FUNC(mod_cml_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->basedir = buffer_init(); p->baseurl = buffer_init(); p->trigger_handler = buffer_init(); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_cml_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]; - + buffer_free(s->ext); - + buffer_free(s->mc_namespace); buffer_free(s->power_magnet); array_free(s->mc_hosts); - + #if defined(HAVE_MEMCACHE_H) if (s->mc) mc_free(s->mc); #endif - + free(s); } free(p->config_storage); } - + buffer_free(p->trigger_handler); buffer_free(p->basedir); buffer_free(p->baseurl); - + free(p); - + return HANDLER_GO_ON; } @@ -72,22 +72,22 @@ FREE_FUNC(mod_cml_free) { SETDEFAULTS_FUNC(mod_cml_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "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 } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = malloc(sizeof(plugin_config)); s->ext = buffer_init(); s->mc_hosts = array_init(); @@ -96,42 +96,42 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) { #if defined(HAVE_MEMCACHE_H) s->mc = NULL; #endif - + 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; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } - + if (s->mc_hosts->used) { #if defined(HAVE_MEMCACHE_H) size_t k; s->mc = mc_new(); - + for (k = 0; k < s->mc_hosts->used; k++) { data_string *ds = (data_string *)s->mc_hosts->data[k]; - + if (0 != mc_server_add4(s->mc, ds->value->ptr)) { - log_error_write(srv, __FILE__, __LINE__, "sb", - "connection to host failed:", + log_error_write(srv, __FILE__, __LINE__, "sb", + "connection to host failed:", ds->value); - + return HANDLER_ERROR; } } #else - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "memcache support is not compiled in but cml.memcache-hosts is set, aborting"); return HANDLER_ERROR; #endif } } - + return HANDLER_GO_ON; } @@ -140,26 +140,26 @@ SETDEFAULTS_FUNC(mod_cml_set_defaults) { static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(ext); #if defined(HAVE_MEMCACHE_H) PATCH(mc); #endif PATCH(mc_namespace); PATCH(power_magnet); - + /* 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("cml.extension"))) { PATCH(ext); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) { @@ -173,7 +173,7 @@ static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p } } } - + return 0; } #undef PATCH @@ -181,63 +181,60 @@ static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) { buffer *b; char *c; - int ret; /* cleanup basedir */ b = p->baseurl; buffer_copy_string_buffer(b, con->uri.path); for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--); - + if (*c == '/') { b->used = c - b->ptr + 2; *(c+1) = '\0'; } - + b = p->basedir; buffer_copy_string_buffer(b, con->physical.path); for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--); - + if (*c == '/') { b->used = c - b->ptr + 2; *(c+1) = '\0'; } - + /* prepare variables * - cookie-based * - get-param-based */ - 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->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. + * request header as neccesary. * * First use: * if file_exists("/maintainance.html") { * output_include = ( "/maintainance.html" ) - * return CACHE_HIT + * 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)) { @@ -266,20 +263,20 @@ URIHANDLER_FUNC(mod_cml_power_magnet) { 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->trigger_handler); if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON; - + 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: @@ -311,15 +308,15 @@ URIHANDLER_FUNC(mod_cml_is_handled) { int mod_cml_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("cache"); - + p->init = mod_cml_init; p->cleanup = mod_cml_free; 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; - + return 0; } diff --git a/src/mod_cml.h b/src/mod_cml.h index 992af68..1afd708 100644 --- a/src/mod_cml.h +++ b/src/mod_cml.h @@ -16,10 +16,10 @@ typedef struct { buffer *ext; - + array *mc_hosts; buffer *mc_namespace; -#if defined(HAVE_MEMCACHE_H) +#if defined(HAVE_MEMCACHE_H) struct memcache *mc; #endif buffer *power_magnet; @@ -27,15 +27,15 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *basedir; buffer *baseurl; - + buffer *trigger_handler; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn); diff --git a/src/mod_cml_funcs.c b/src/mod_cml_funcs.c index 46a1f16..07c7673 100644 --- a/src/mod_cml_funcs.c +++ b/src/mod_cml_funcs.c @@ -30,7 +30,7 @@ typedef char HASHHEX[HASHHEXLEN+1]; #ifdef USE_OPENSSL #define IN const #else -#define IN +#define IN #endif #define OUT @@ -42,29 +42,29 @@ int f_crypto_md5(lua_State *L) { buffer b; char hex[33]; int n = lua_gettop(L); - + b.ptr = hex; b.used = 0; b.size = sizeof(hex); - + if (n != 1) { lua_pushstring(L, "md5: expected one argument"); lua_error(L); } - + if (!lua_isstring(L, 1)) { lua_pushstring(L, "md5: argument has to be a string"); lua_error(L); } - + MD5_Init(&Md5Ctx); MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1)); MD5_Final(HA1, &Md5Ctx); - + buffer_copy_string_hex(&b, (char *)HA1, 16); - + lua_pushstring(L, b.ptr); - + return 1; } @@ -72,37 +72,37 @@ int f_crypto_md5(lua_State *L) { int f_file_mtime(lua_State *L) { struct stat st; int n = lua_gettop(L); - + if (n != 1) { lua_pushstring(L, "file_mtime: expected one argument"); lua_error(L); } - + if (!lua_isstring(L, 1)) { lua_pushstring(L, "file_mtime: argument has to be a string"); lua_error(L); } - + if (-1 == stat(lua_tostring(L, 1), &st)) { lua_pushnil(L); return 1; } - + lua_pushnumber(L, st.st_mtime); - + return 1; } int f_dir_files_iter(lua_State *L) { DIR *d; struct dirent *de; - + d = lua_touserdata(L, lua_upvalueindex(1)); - + if (NULL == (de = readdir(d))) { /* EOF */ closedir(d); - + return 0; } else { lua_pushstring(L, de->d_name); @@ -113,75 +113,75 @@ int f_dir_files_iter(lua_State *L) { int f_dir_files(lua_State *L) { DIR *d; int n = lua_gettop(L); - + if (n != 1) { lua_pushstring(L, "dir_files: expected one argument"); lua_error(L); } - + if (!lua_isstring(L, 1)) { lua_pushstring(L, "dir_files: argument has to be a string"); lua_error(L); } - - /* check if there is a valid DIR handle on the stack */ + + /* check if there is a valid DIR handle on the stack */ if (NULL == (d = opendir(lua_tostring(L, 1)))) { lua_pushnil(L); return 1; } - + /* push d into registry */ lua_pushlightuserdata(L, d); lua_pushcclosure(L, f_dir_files_iter, 1); - + return 1; } int f_file_isreg(lua_State *L) { struct stat st; int n = lua_gettop(L); - + if (n != 1) { lua_pushstring(L, "file_isreg: expected one argument"); lua_error(L); } - + if (!lua_isstring(L, 1)) { lua_pushstring(L, "file_isreg: argument has to be a string"); lua_error(L); } - + if (-1 == stat(lua_tostring(L, 1), &st)) { lua_pushnil(L); return 1; } - + lua_pushnumber(L, S_ISREG(st.st_mode)); - + return 1; } int f_file_isdir(lua_State *L) { struct stat st; int n = lua_gettop(L); - + if (n != 1) { lua_pushstring(L, "file_isreg: expected one argument"); lua_error(L); } - + if (!lua_isstring(L, 1)) { lua_pushstring(L, "file_isreg: argument has to be a string"); lua_error(L); } - + if (-1 == stat(lua_tostring(L, 1), &st)) { lua_pushnil(L); return 1; } - + lua_pushnumber(L, S_ISDIR(st.st_mode)); - + return 1; } @@ -192,33 +192,33 @@ int f_memcache_exists(lua_State *L) { char *r; int n = lua_gettop(L); struct memcache *mc; - + if (!lua_islightuserdata(L, lua_upvalueindex(1))) { lua_pushstring(L, "where is my userdata ?"); lua_error(L); } - + mc = lua_touserdata(L, lua_upvalueindex(1)); - + if (n != 1) { lua_pushstring(L, "expected one argument"); lua_error(L); } - + if (!lua_isstring(L, 1)) { lua_pushstring(L, "argument has to be a string"); lua_error(L); } - - if (NULL == (r = mc_aget(mc, + + if (NULL == (r = mc_aget(mc, lua_tostring(L, 1), lua_strlen(L, 1)))) { - + lua_pushboolean(L, 0); return 1; } - + free(r); - + lua_pushboolean(L, 1); return 1; } @@ -226,74 +226,74 @@ int f_memcache_exists(lua_State *L) { int f_memcache_get_string(lua_State *L) { char *r; int n = lua_gettop(L); - + struct memcache *mc; - + if (!lua_islightuserdata(L, lua_upvalueindex(1))) { lua_pushstring(L, "where is my userdata ?"); lua_error(L); } - + mc = lua_touserdata(L, lua_upvalueindex(1)); - - + + if (n != 1) { lua_pushstring(L, "expected one argument"); lua_error(L); } - + if (!lua_isstring(L, 1)) { lua_pushstring(L, "argument has to be a string"); lua_error(L); } - - if (NULL == (r = mc_aget(mc, + + if (NULL == (r = mc_aget(mc, lua_tostring(L, 1), lua_strlen(L, 1)))) { lua_pushnil(L); return 1; } - + lua_pushstring(L, r); - + free(r); - + return 1; } int f_memcache_get_long(lua_State *L) { char *r; int n = lua_gettop(L); - + struct memcache *mc; - + if (!lua_islightuserdata(L, lua_upvalueindex(1))) { lua_pushstring(L, "where is my userdata ?"); lua_error(L); } - + mc = lua_touserdata(L, lua_upvalueindex(1)); - - + + if (n != 1) { lua_pushstring(L, "expected one argument"); lua_error(L); } - + if (!lua_isstring(L, 1)) { lua_pushstring(L, "argument has to be a string"); lua_error(L); } - - if (NULL == (r = mc_aget(mc, + + if (NULL == (r = mc_aget(mc, lua_tostring(L, 1), lua_strlen(L, 1)))) { lua_pushnil(L); return 1; } - + lua_pushnumber(L, strtol(r, NULL, 10)); - + free(r); - + return 1; } #endif diff --git a/src/mod_cml_lua.c b/src/mod_cml_lua.c index ded53b8..8bfb1ab 100644 --- a/src/mod_cml_lua.c +++ b/src/mod_cml_lua.c @@ -23,7 +23,7 @@ typedef char HASHHEX[HASHHEXLEN+1]; #ifdef USE_OPENSSL #define IN const #else -#define IN +#define IN #endif #define OUT @@ -40,11 +40,11 @@ typedef struct { static const char * load_file(lua_State *L, void *data, size_t *size) { readme *rm = data; - + UNUSED(L); - + if (rm->done) return 0; - + *size = rm->st.size; rm->done = 1; return rm->st.start; @@ -52,47 +52,47 @@ static const char * load_file(lua_State *L, void *data, size_t *size) { static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) { int curelem; - + lua_pushstring(L, varname); - + curelem = lua_gettop(L); lua_gettable(L, LUA_GLOBALSINDEX); - + /* it should be a table */ if (!lua_isstring(L, curelem)) { lua_settop(L, curelem - 1); - + return -1; } - + buffer_copy_string(b, lua_tostring(L, curelem)); - + lua_pop(L, 1); - + assert(curelem - 1 == lua_gettop(L)); - + return 0; } static int lua_to_c_is_table(lua_State *L, const char *varname) { int curelem; - + lua_pushstring(L, varname); - + curelem = lua_gettop(L); lua_gettable(L, LUA_GLOBALSINDEX); - + /* it should be a table */ if (!lua_istable(L, curelem)) { lua_settop(L, curelem - 1); - + return 0; } - + lua_settop(L, curelem - 1); - + assert(curelem - 1 == lua_gettop(L)); - + return 1; } @@ -100,7 +100,7 @@ static int c_to_lua_push(lua_State *L, int tbl, const char *key, size_t key_len, lua_pushlstring(L, key, key_len); lua_pushlstring(L, val, val_len); lua_settable(L, tbl); - + return 0; } @@ -109,21 +109,21 @@ int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) { size_t is_key = 1; size_t i; char *key = NULL, *val = NULL; - + key = qrystr->ptr; - + /* we need the \0 */ for (i = 0; i < qrystr->used; i++) { switch(qrystr->ptr[i]) { case '=': if (is_key) { val = qrystr->ptr + i + 1; - + qrystr->ptr[i] = '\0'; - + is_key = 0; } - + break; case '&': case '\0': /* fin symbol */ @@ -132,19 +132,19 @@ int cache_export_get_params(lua_State *L, int tbl, buffer *qrystr) { /* terminate the value */ qrystr->ptr[i] = '\0'; - - c_to_lua_push(L, tbl, + + c_to_lua_push(L, tbl, key, strlen(key), val, strlen(val)); } - + key = qrystr->ptr + i + 1; val = NULL; is_key = 1; break; } } - + return 0; } #if 0 @@ -152,21 +152,21 @@ int cache_export_cookie_params(server *srv, connection *con, plugin_data *p) { data_unset *d; UNUSED(srv); - + if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) { data_string *ds = (data_string *)d; size_t key = 0, value = 0; size_t is_key = 1, is_sid = 0; size_t i; - + /* found COOKIE */ if (!DATA_IS_STRING(d)) return -1; if (ds->value->used == 0) return -1; - + if (ds->value->ptr[0] == '\0' || ds->value->ptr[0] == '=' || ds->value->ptr[0] == ';') return -1; - + buffer_reset(p->session_id); for (i = 0; i < ds->value->used; i++) { switch(ds->value->ptr[i]) { @@ -177,16 +177,16 @@ int cache_export_cookie_params(server *srv, connection *con, plugin_data *p) { is_sid = 1; } value = i + 1; - + is_key = 0; } - + break; case ';': if (is_sid) { buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value); } - + is_sid = 0; key = i + 1; value = 0; @@ -205,21 +205,21 @@ int cache_export_cookie_params(server *srv, connection *con, plugin_data *p) { } } } - + return 0; } #endif int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { - lua_State *L; + lua_State *L; readme rm; int ret = -1; buffer *b = buffer_init(); int header_tbl = 0; - + rm.done = 0; stream_open(&rm.st, fn); - + /* push the lua file to the interpreter and see what happends */ L = luaL_newstate(); luaL_openlibs(L); @@ -230,18 +230,18 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { lua_register(L, "file_isreg", f_file_isreg); lua_register(L, "file_isdir", f_file_isreg); lua_register(L, "dir_files", f_dir_files); - + #ifdef HAVE_MEMCACHE_H lua_pushliteral(L, "memcache_get_long"); lua_pushlightuserdata(L, p->conf.mc); lua_pushcclosure(L, f_memcache_get_long, 1); lua_settable(L, LUA_GLOBALSINDEX); - + lua_pushliteral(L, "memcache_get_string"); lua_pushlightuserdata(L, p->conf.mc); lua_pushcclosure(L, f_memcache_get_string, 1); lua_settable(L, LUA_GLOBALSINDEX); - + lua_pushliteral(L, "memcache_exists"); lua_pushlightuserdata(L, p->conf.mc); lua_pushcclosure(L, f_memcache_exists, 1); @@ -251,11 +251,11 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { lua_pushliteral(L, "request"); lua_newtable(L); lua_settable(L, LUA_GLOBALSINDEX); - + lua_pushliteral(L, "request"); header_tbl = lua_gettop(L); lua_gettable(L, LUA_GLOBALSINDEX); - + c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri)); c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path)); @@ -263,84 +263,84 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { if (!buffer_is_empty(con->request.pathinfo)) { c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); } - + c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir)); c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl)); - + /* register GET parameter */ lua_pushliteral(L, "get"); lua_newtable(L); lua_settable(L, LUA_GLOBALSINDEX); - + lua_pushliteral(L, "get"); header_tbl = lua_gettop(L); lua_gettable(L, LUA_GLOBALSINDEX); - + buffer_copy_string_buffer(b, con->uri.query); cache_export_get_params(L, header_tbl, b); buffer_reset(b); - /* 2 default constants */ + /* 2 default constants */ lua_pushliteral(L, "CACHE_HIT"); lua_pushboolean(L, 0); lua_settable(L, LUA_GLOBALSINDEX); - + lua_pushliteral(L, "CACHE_MISS"); lua_pushboolean(L, 1); lua_settable(L, LUA_GLOBALSINDEX); - + /* load lua program */ if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) { log_error_write(srv, __FILE__, __LINE__, "s", lua_tostring(L,-1)); - + goto error; } - + /* get return value */ ret = (int)lua_tonumber(L, -1); lua_pop(L, 1); - - /* fetch the data from lua */ + + /* fetch the data from lua */ lua_to_c_get_string(L, "trigger_handler", p->trigger_handler); - + if (0 == lua_to_c_get_string(L, "output_contenttype", b)) { response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b)); } - + 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"); - + curelem = lua_gettop(L); lua_gettable(L, LUA_GLOBALSINDEX); /* HOW-TO build a etag ? - * as we don't just have one file we have to take the stat() + * as we don't just have one file we have to take the stat() * from all base files, merge them and build the etag from * it later. - * + * * The mtime of the content is the mtime of the freshest base file - * + * * */ - + lua_pushnil(L); /* first key */ while (lua_next(L, curelem) != 0) { stat_cache_entry *sce = NULL; /* key' is at index -2 and value' at index -1 */ - + if (lua_isstring(L, -1)) { const char *s = lua_tostring(L, -1); @@ -360,18 +360,18 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { /* a file is missing, call the handler to generate it */ if (!buffer_is_empty(p->trigger_handler)) { ret = 1; /* cache-miss */ - + log_error_write(srv, __FILE__, __LINE__, "s", "a file is missing, calling handler"); - + break; } else { /* handler not set -> 500 */ ret = -1; - + log_error_write(srv, __FILE__, __LINE__, "s", "a file missing and no handler set"); - + break; } break; @@ -389,12 +389,12 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { "not a string"); break; } - + lua_pop(L, 1); /* removes value'; keeps key' for next iteration */ } - + lua_settop(L, curelem - 1); - + if (ret == 0) { data_string *ds; char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; @@ -406,9 +406,9 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { /* no Last-Modified specified */ if ((mtime) && (NULL == ds)) { - + strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime)); - + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1); @@ -424,9 +424,9 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { tbuf.used = 0; tbuf.ptr = NULL; } - + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) { - /* ok, the client already has our content, + /* ok, the client already has our content, * no need to send it again */ chunkqueue_reset(con->write_queue); @@ -436,28 +436,32 @@ int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { chunkqueue_reset(con->write_queue); } } - + 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); - + buffer_copy_string_buffer(con->physical.path, p->basedir); buffer_append_string_buffer(con->physical.path, p->trigger_handler); - + chunkqueue_reset(con->write_queue); } - + error: lua_close(L); - + stream_close(&rm.st); buffer_free(b); - + return ret /* cache-error */; } #else int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) { + UNUSED(srv); + UNUSED(con); + UNUSED(p); + UNUSED(fn); /* error */ return -1; } diff --git a/src/mod_compress.c b/src/mod_compress.c index fc78220..b528ebf 100644 --- a/src/mod_compress.c +++ b/src/mod_compress.c @@ -55,97 +55,97 @@ typedef struct { PLUGIN_DATA; buffer *ofn; buffer *b; - + plugin_config **config_storage; - plugin_config conf; + plugin_config conf; } plugin_data; INIT_FUNC(mod_compress_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->ofn = buffer_init(); p->b = buffer_init(); - + return p; } FREE_FUNC(mod_compress_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + buffer_free(p->ofn); buffer_free(p->b); - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + array_free(s->compress); buffer_free(s->compress_cache_dir); - + free(s); } free(p->config_storage); } - - + + free(p); - + return HANDLER_GO_ON; } SETDEFAULTS_FUNC(mod_compress_setdefaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "compress.cache-dir", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { "compress.filetype", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, { "compress.max-filesize", 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->compress_cache_dir = buffer_init(); s->compress = array_init(); s->compress_max_filesize = 0; - + cv[0].destination = s->compress_cache_dir; cv[1].destination = s->compress; cv[2].destination = &(s->compress_max_filesize); - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } - + if (!buffer_is_empty(s->compress_cache_dir)) { struct stat st; if (0 != stat(s->compress_cache_dir->ptr, &st)) { - log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir", s->compress_cache_dir, strerror(errno)); - + return HANDLER_ERROR; } } } - + return HANDLER_GO_ON; - + } #ifdef USE_ZLIB @@ -153,32 +153,32 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data unsigned char *c; unsigned long crc; z_stream z; - + UNUSED(srv); UNUSED(con); z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; - - if (Z_OK != deflateInit2(&z, + + if (Z_OK != deflateInit2(&z, Z_DEFAULT_COMPRESSION, - Z_DEFLATED, + Z_DEFLATED, -MAX_WBITS, /* supress zlib-header */ 8, Z_DEFAULT_STRATEGY)) { return -1; } - + z.next_in = (unsigned char *)start; z.avail_in = st_size; z.total_in = 0; - - + + buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18); - + /* write gzip header */ - + c = (unsigned char *)p->b->ptr; c[0] = 0x1f; c[1] = 0x8b; @@ -190,24 +190,24 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data c[7] = (mtime >> 24) & 0xff; c[8] = 0x00; /* extra flags */ c[9] = 0x03; /* UNIX */ - + p->b->used = 10; z.next_out = (unsigned char *)p->b->ptr + p->b->used; z.avail_out = p->b->size - p->b->used - 8; z.total_out = 0; - + if (Z_STREAM_END != deflate(&z, Z_FINISH)) { deflateEnd(&z); return -1; } - + /* trailer */ p->b->used += z.total_out; - + crc = generate_crc32c(start, st_size); - + c = (unsigned char *)p->b->ptr + p->b->used; - + c[0] = (crc >> 0) & 0xff; c[1] = (crc >> 8) & 0xff; c[2] = (crc >> 16) & 0xff; @@ -221,51 +221,51 @@ static int deflate_file_to_buffer_gzip(server *srv, connection *con, plugin_data if (Z_OK != deflateEnd(&z)) { return -1; } - + return 0; } static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) { z_stream z; - + UNUSED(srv); UNUSED(con); z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; - - if (Z_OK != deflateInit2(&z, + + if (Z_OK != deflateInit2(&z, Z_DEFAULT_COMPRESSION, - Z_DEFLATED, + Z_DEFLATED, -MAX_WBITS, /* supress zlib-header */ 8, Z_DEFAULT_STRATEGY)) { return -1; } - + z.next_in = start; z.avail_in = st_size; z.total_in = 0; - + buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12); - + z.next_out = (unsigned char *)p->b->ptr; z.avail_out = p->b->size; z.total_out = 0; - + if (Z_STREAM_END != deflate(&z, Z_FINISH)) { deflateEnd(&z); return -1; } - + /* trailer */ p->b->used += z.total_out; - + if (Z_OK != deflateEnd(&z)) { return -1; } - + return 0; } @@ -274,48 +274,48 @@ static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_d #ifdef USE_BZ2LIB static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) { bz_stream bz; - + UNUSED(srv); UNUSED(con); bz.bzalloc = NULL; bz.bzfree = NULL; bz.opaque = NULL; - - if (BZ_OK != BZ2_bzCompressInit(&bz, + + if (BZ_OK != BZ2_bzCompressInit(&bz, 9, /* blocksize = 900k */ 0, /* no output */ 0)) { /* workFactor: default */ return -1; } - + bz.next_in = (char *)start; bz.avail_in = st_size; bz.total_in_lo32 = 0; bz.total_in_hi32 = 0; - + buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12); - + bz.next_out = p->b->ptr; bz.avail_out = p->b->size; bz.total_out_lo32 = 0; bz.total_out_hi32 = 0; - + if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) { BZ2_bzCompressEnd(&bz); return -1; } - + /* file is too large for now */ if (bz.total_out_hi32) return -1; - + /* trailer */ p->b->used = bz.total_out_lo32; - + if (BZ_OK != BZ2_bzCompressEnd(&bz)) { return -1; } - + return 0; } #endif @@ -326,47 +326,47 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu void *start; const char *filename = fn->ptr; ssize_t r; - + /* overflow */ if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1; - - /* don't mmap files > 128Mb - * + + /* don't mmap files > 128Mb + * * we could use a sliding window, but currently there is no need for it */ - + if (sce->st.st_size > 128 * 1024 * 1024) return -1; - + buffer_reset(p->ofn); buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir); BUFFER_APPEND_SLASH(p->ofn); - + if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) { size_t offset = p->ofn->used - 1; char *dir, *nextdir; - + buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1); - + buffer_copy_string_buffer(p->b, p->ofn); - + /* mkdir -p ... */ for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) { *nextdir = '\0'; - + if (-1 == mkdir(p->b->ptr, 0700)) { if (errno != EEXIST) { log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno)); - + return -1; } } - + *nextdir = '/'; } } else { buffer_append_string_buffer(p->ofn, con->uri.path); } - + switch(type) { case HTTP_ACCEPT_ENCODING_GZIP: buffer_append_string(p->ofn, "-gzip-"); @@ -381,9 +381,9 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type); return -1; } - + buffer_append_string_buffer(p->ofn, sce->etag); - + if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) { if (errno == EEXIST) { /* cache-entry exists */ @@ -391,45 +391,45 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit"); #endif buffer_copy_string_buffer(con->physical.path, p->ofn); - + return 0; } - + log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno)); - + return -1; } #if 0 log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss"); -#endif +#endif if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) { log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno)); - + close(ofd); - + return -1; } - - + + if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) { log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno)); - + close(ofd); close(ifd); return -1; } - + switch(type) { #ifdef USE_ZLIB - case HTTP_ACCEPT_ENCODING_GZIP: + case HTTP_ACCEPT_ENCODING_GZIP: ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime); break; - case HTTP_ACCEPT_ENCODING_DEFLATE: + case HTTP_ACCEPT_ENCODING_DEFLATE: ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size); break; #endif #ifdef USE_BZ2LIB - case HTTP_ACCEPT_ENCODING_BZIP2: + case HTTP_ACCEPT_ENCODING_BZIP2: ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size); break; #endif @@ -437,26 +437,26 @@ static int deflate_file_to_file(server *srv, connection *con, plugin_data *p, bu ret = -1; break; } - + if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) { - munmap(start, sce->st.st_size); + munmap(start, sce->st.st_size); close(ofd); close(ifd); return -1; } - + if ((size_t)r != p->b->used) { - + } - + munmap(start, sce->st.st_size); close(ofd); close(ifd); - + if (ret != 0) return -1; - + buffer_copy_string_buffer(con->physical.path, p->ofn); - + return 0; } @@ -465,43 +465,43 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p, int ret = -1; void *start; buffer *b; - + /* overflow */ if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1; - + /* don't mmap files > 128M - * + * * we could use a sliding window, but currently there is no need for it */ - + if (sce->st.st_size > 128 * 1024 * 1024) return -1; - - + + if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) { log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno)); - + return -1; } - - + + if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) { log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno)); - + close(ifd); return -1; } - + switch(type) { #ifdef USE_ZLIB - case HTTP_ACCEPT_ENCODING_GZIP: + case HTTP_ACCEPT_ENCODING_GZIP: ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime); break; - case HTTP_ACCEPT_ENCODING_DEFLATE: + case HTTP_ACCEPT_ENCODING_DEFLATE: ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size); break; #endif #ifdef USE_BZ2LIB - case HTTP_ACCEPT_ENCODING_BZIP2: + case HTTP_ACCEPT_ENCODING_BZIP2: ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size); break; #endif @@ -509,21 +509,21 @@ static int deflate_file_to_buffer(server *srv, connection *con, plugin_data *p, ret = -1; break; } - + munmap(start, sce->st.st_size); close(ifd); - + if (ret != 0) return -1; - + chunkqueue_reset(con->write_queue); b = chunkqueue_get_append_buffer(con->write_queue); buffer_copy_memory(b, p->b->ptr, p->b->used + 1); - + buffer_reset(con->physical.path); - + con->file_finished = 1; con->file_started = 1; - + return 0; } @@ -537,19 +537,19 @@ static int mod_compress_patch_connection(server *srv, connection *con, plugin_da PATCH(compress_cache_dir); PATCH(compress); PATCH(compress_max_filesize); - + /* 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("compress.cache-dir"))) { PATCH(compress_cache_dir); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) { @@ -559,7 +559,7 @@ static int mod_compress_patch_connection(server *srv, connection *con, plugin_da } } } - + return 0; } #undef PATCH @@ -569,9 +569,9 @@ PHYSICALPATH_FUNC(mod_compress_physical) { size_t m; off_t max_fsize; stat_cache_entry *sce = NULL; - + /* only GET and POST can get compressed */ - if (con->request.http_method != HTTP_METHOD_GET && + if (con->request.http_method != HTTP_METHOD_GET && con->request.http_method != HTTP_METHOD_POST) { return HANDLER_GO_ON; } @@ -579,46 +579,46 @@ PHYSICALPATH_FUNC(mod_compress_physical) { if (buffer_is_empty(con->physical.path)) { return HANDLER_GO_ON; } - + mod_compress_patch_connection(srv, con, p); - + max_fsize = p->conf.compress_max_filesize; stat_cache_get_entry(srv, con, con->physical.path, &sce); /* don't compress files that are too large as we need to much time to handle them */ if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON; - + /* check if mimetype is in compress-config */ for (m = 0; m < p->conf.compress->used; m++) { data_string *compress_ds = (data_string *)p->conf.compress->data[m]; - + if (!compress_ds) { log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path); - + return HANDLER_GO_ON; } - + if (buffer_is_equal(compress_ds->value, sce->content_type)) { /* mimetype found */ data_string *ds; - + /* the response might change according to Accept-Encoding */ response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding")); - + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) { int accept_encoding = 0; char *value = ds->value->ptr; int srv_encodings = 0; int matched_encodings = 0; - + /* get client side support encodings */ if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP; if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE; if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS; if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2; if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY; - + /* get server side supported ones */ #ifdef USE_BZ2LIB srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2; @@ -627,18 +627,18 @@ PHYSICALPATH_FUNC(mod_compress_physical) { srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP; srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE; #endif - + /* find matching entries */ matched_encodings = accept_encoding & srv_encodings; - + if (matched_encodings) { const char *dflt_gzip = "gzip"; const char *dflt_deflate = "deflate"; const char *dflt_bzip2 = "bzip2"; - + const char *compression_name = NULL; int compression_type = 0; - + /* select best matching encoding */ if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) { compression_type = HTTP_ACCEPT_ENCODING_BZIP2; @@ -650,15 +650,15 @@ PHYSICALPATH_FUNC(mod_compress_physical) { compression_type = HTTP_ACCEPT_ENCODING_DEFLATE; compression_name = dflt_deflate; } - + /* deflate it */ if (p->conf.compress_cache_dir->used) { if (0 == deflate_file_to_file(srv, con, p, con->physical.path, sce, compression_type)) { buffer *mtime; - + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name)); - + mtime = strftime_cache_get(srv, sce->st.st_mtime); response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime)); @@ -671,10 +671,10 @@ PHYSICALPATH_FUNC(mod_compress_physical) { } } else if (0 == deflate_file_to_buffer(srv, con, p, con->physical.path, sce, compression_type)) { - + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name)); response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type)); - + return HANDLER_FINISHED; } break; @@ -682,20 +682,20 @@ PHYSICALPATH_FUNC(mod_compress_physical) { } } } - + return HANDLER_GO_ON; } int mod_compress_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("compress"); - + p->init = mod_compress_init; p->set_defaults = mod_compress_setdefaults; p->handle_subrequest_start = mod_compress_physical; p->cleanup = mod_compress_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_dirlisting.c b/src/mod_dirlisting.c index 69eb1e9..165699b 100644 --- a/src/mod_dirlisting.c +++ b/src/mod_dirlisting.c @@ -54,7 +54,7 @@ typedef struct { unsigned short hide_readme_file; unsigned short show_header; unsigned short hide_header_file; - + excludes_buffer *excludes; buffer *external_css; @@ -63,13 +63,13 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *tmp_buf; buffer *content_charset; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; excludes_buffer *excludes_buffer_init(void) { @@ -146,44 +146,44 @@ void excludes_buffer_free(excludes_buffer *exb) { /* init the plugin data */ 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; } /* detroy the plugin data */ FREE_FUNC(mod_dirlisting_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; - + if (!s) continue; - + excludes_buffer_free(s->excludes); buffer_free(s->external_css); buffer_free(s->encoding); - + free(s); } free(p->config_storage); } - + buffer_free(p->tmp_buf); buffer_free(p->content_charset); - + free(p); - + return HANDLER_GO_ON; } @@ -215,10 +215,10 @@ static int parse_config_entry(server *srv, plugin_config *s, array *ca, const ch if (0 != excludes_buffer_append(s->excludes, ((data_string *)(da->value->data[j]))->value)) { #ifdef HAVE_PCRE_H - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value); #else - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "pcre support is missing, please install libpcre and the headers"); #endif } @@ -233,8 +233,8 @@ static int parse_config_entry(server *srv, plugin_config *s, array *ca, const ch SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + 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 */ @@ -245,18 +245,18 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) { { "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 } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; array *ca; - + s = calloc(1, sizeof(plugin_config)); s->excludes = excludes_buffer_init(); s->dir_listing = 0; @@ -267,7 +267,7 @@ SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) { s->show_header = 0; s->hide_header_file = 0; s->encoding = buffer_init(); - + cv[0].destination = s->excludes; cv[1].destination = &(s->dir_listing); cv[2].destination = &(s->hide_dot_files); @@ -307,19 +307,19 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_ PATCH(show_header); PATCH(hide_header_file); PATCH(excludes); - + /* 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("dir-listing.activate")) || buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) { PATCH(dir_listing); @@ -342,7 +342,7 @@ static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_ } } } - + return 0; } #undef PATCH @@ -432,7 +432,7 @@ static int http_list_directory_sizefmt(char *buf, off_t size) { static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); - + BUFFER_APPEND_STRING_CONST(out, "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n" @@ -492,11 +492,11 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data 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); @@ -510,7 +510,7 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data BUFFER_APPEND_STRING_CONST(out, "</h2>\n" "<div class=\"list\">\n" - "<table cellpadding=\"0\" cellspacing=\"0\">\n" + "<table summary=\"Directory Listing\" cellpadding=\"0\" cellspacing=\"0\">\n" "<thead>" "<tr>" "<th class=\"n\">Name</th>" @@ -531,21 +531,21 @@ static void http_list_directory_header(server *srv, connection *con, plugin_data static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) { UNUSED(srv); - + BUFFER_APPEND_STRING_CONST(out, "</tbody>\n" "</table>\n" "</div>\n" ); - + if (p->conf.show_readme) { stream s; /* if we have a README file, display it in <pre class="readme"></pre> */ - + buffer_copy_string_buffer(p->tmp_buf, con->physical.path); BUFFER_APPEND_SLASH(p->tmp_buf); BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt"); - + 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_MINIMAL_XML); @@ -553,7 +553,7 @@ static void http_list_directory_footer(server *srv, connection *con, plugin_data } stream_close(&s); } - + BUFFER_APPEND_STRING_CONST(out, "<div class=\"foot\">" ); @@ -595,7 +595,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf #endif if (dir->used == 0) return -1; - + i = dir->used - 1; #ifdef HAVE_PATHCONF @@ -611,14 +611,14 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf #else name_max = NAME_MAX; #endif - + path = malloc(dir->used + name_max); assert(path); strcpy(path, dir->ptr); path_file = path + i; if (NULL == (dp = opendir(path))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", + log_error_write(srv, __FILE__, __LINE__, "sbs", "opendir failed:", dir, strerror(errno)); free(path); @@ -633,7 +633,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf assert(files.ent); files.size = DIRLIST_BLOB_SIZE; files.used = 0; - + while ((dent = readdir(dp)) != NULL) { unsigned short exclude_match = 0; @@ -686,12 +686,12 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf #endif i = strlen(dent->d_name); - + /* NOTE: the manual says, d_name is never more than NAME_MAX * so this should actually not be a buffer-overflow-risk */ if (i > (size_t)name_max) continue; - + memcpy(path_file, dent->d_name, i + 1); if (stat(path, &st) != 0) continue; @@ -740,7 +740,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf #else strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime))); #endif - + 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, "/\">"); @@ -758,7 +758,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf content_type = NULL; #ifdef HAVE_XATTR - + if (con->conf.use_xattr) { memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1); attrlen = sizeof(attrval) - 1; @@ -768,7 +768,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf } } #endif - + if (content_type == NULL) { content_type = "application/octet-stream"; for (k = 0; k < con->conf.mimetypes->used; k++) { @@ -788,7 +788,7 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf } } } - + #ifdef HAVE_LOCALTIME_R localtime_r(&(tmp->mtime), &tm); strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); @@ -837,36 +837,36 @@ static int http_list_directory(server *srv, connection *con, plugin_data *p, buf URIHANDLER_FUNC(mod_dirlisting_subrequest) { plugin_data *p = p_d; stat_cache_entry *sce = NULL; - + UNUSED(srv); - + if (con->physical.path->used == 0) return HANDLER_GO_ON; if (con->uri.path->used == 0) return HANDLER_GO_ON; if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON; - + mod_dirlisting_patch_connection(srv, con, p); if (!p->conf.dir_listing) return HANDLER_GO_ON; - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing"); log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path); } - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) { fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr); SEGFAULT(); } - + if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON; - + if (http_list_directory(srv, con, p, con->physical.path)) { /* dirlisting failed */ con->http_status = 403; } - + buffer_reset(con->physical.path); - + /* not found */ return HANDLER_FINISHED; } @@ -876,13 +876,13 @@ URIHANDLER_FUNC(mod_dirlisting_subrequest) { int mod_dirlisting_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("dirlisting"); - + p->init = mod_dirlisting_init; p->handle_subrequest_start = mod_dirlisting_subrequest; p->set_defaults = mod_dirlisting_set_defaults; p->cleanup = mod_dirlisting_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_evasive.c b/src/mod_evasive.c index b9d19ca..3415953 100644 --- a/src/mod_evasive.c +++ b/src/mod_evasive.c @@ -31,68 +31,68 @@ typedef struct { typedef struct { PLUGIN_DATA; - + plugin_config **config_storage; - - plugin_config conf; + + 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[] = { + + 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; } @@ -103,25 +103,25 @@ static int mod_evasive_patch_connection(server *srv, connection *con, plugin_dat 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 @@ -132,10 +132,10 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) { 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 */ + + /* no limit set, nothing to block */ if (p->conf.max_conns == 0) return HANDLER_GO_ON; for (j = 0; j < srv->conns->used; j++) { @@ -147,7 +147,7 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) { 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)), @@ -158,7 +158,7 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) { } } } - + return HANDLER_GO_ON; } @@ -166,13 +166,13 @@ URIHANDLER_FUNC(mod_evasive_uri_handler) { 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_evhost.c b/src/mod_evhost.c index bc8adb6..daf4494 100644 --- a/src/mod_evhost.c +++ b/src/mod_evhost.c @@ -10,7 +10,7 @@ typedef struct { /* unparsed pieces */ buffer *path_pieces_raw; - + /* pieces for path creation */ size_t len; buffer **path_pieces; @@ -21,14 +21,14 @@ typedef struct { buffer *tmp_buf; plugin_config **config_storage; - plugin_config conf; + plugin_config conf; } plugin_data; INIT_FUNC(mod_evhost_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->tmp_buf = buffer_init(); return p; @@ -36,34 +36,34 @@ INIT_FUNC(mod_evhost_init) { FREE_FUNC(mod_evhost_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + if(s->path_pieces) { size_t j; for (j = 0; j < s->len; j++) { buffer_free(s->path_pieces[j]); } - + free(s->path_pieces); } - + buffer_free(s->path_pieces_raw); - + free(s); } free(p->config_storage); } - + buffer_free(p->tmp_buf); free(p); @@ -73,30 +73,30 @@ FREE_FUNC(mod_evhost_free) { static void mod_evhost_parse_pattern(plugin_config *s) { char *ptr = s->path_pieces_raw->ptr,*pos; - + s->path_pieces = NULL; - + for(pos=ptr;*ptr;ptr++) { if(*ptr == '%') { s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces)); s->path_pieces[s->len] = buffer_init(); s->path_pieces[s->len+1] = buffer_init(); - + buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos); pos = ptr + 2; - + buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2); - + s->len += 2; } } - + if(*pos != '\0') { s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces)); s->path_pieces[s->len] = buffer_init(); - + buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos); - + s->len += 1; } } @@ -104,9 +104,9 @@ static void mod_evhost_parse_pattern(plugin_config *s) { SETDEFAULTS_FUNC(mod_evhost_set_defaults) { plugin_data *p = p_d; size_t i; - + /** - * + * * # * # define a pattern for the host url finding * # %% => % sign @@ -117,39 +117,39 @@ SETDEFAULTS_FUNC(mod_evhost_set_defaults) { * # %4 => subdomain 2 name * # * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/" - * + * */ - - config_values_t cv[] = { + + config_values_t cv[] = { { "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->path_pieces_raw = buffer_init(); s->path_pieces = NULL; s->len = 0; - + cv[0].destination = s->path_pieces_raw; - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } - + if (s->path_pieces_raw->used != 0) { mod_evhost_parse_pattern(s); } } - + return HANDLER_GO_ON; } @@ -158,7 +158,7 @@ SETDEFAULTS_FUNC(mod_evhost_set_defaults) { * - %0 - full hostname (authority w/o port) * - %1 - tld * - %2 - domain.tld - * - %3 - + * - %3 - */ static int mod_evhost_parse_host(connection *con,array *host) { @@ -168,7 +168,7 @@ static int mod_evhost_parse_host(connection *con,array *host) { int first = 1; data_string *ds; int i; - + /* first, find the domain + tld */ for(;ptr > con->uri.authority->ptr;ptr--) { if(*ptr == '.') { @@ -179,18 +179,18 @@ static int mod_evhost_parse_host(connection *con,array *host) { first = 1; } } - + ds = data_string_init(); buffer_copy_string(ds->key,"%0"); - + /* if we stopped at a dot, skip the dot */ if (*ptr == '.') ptr++; buffer_copy_string_len(ds->value, ptr, colon-ptr); - + array_insert_unique(host,(data_unset *)ds); - + /* if the : is not the start of the authority, go on parsing the hostname */ - + if (colon != con->uri.authority->ptr) { for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) { if(*ptr == '.') { @@ -200,24 +200,24 @@ static int mod_evhost_parse_host(connection *con,array *host) { buffer_copy_string(ds->key,"%"); buffer_append_long(ds->key, i++); buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1); - + array_insert_unique(host,(data_unset *)ds); } colon = ptr; } } - + /* if the . is not the first charactor of the hostname */ if (colon != ptr) { ds = data_string_init(); buffer_copy_string(ds->key,"%"); buffer_append_long(ds->key, i++); buffer_copy_string_len(ds->value,ptr,colon-ptr); - + array_insert_unique(host,(data_unset *)ds); } } - + return 0; } @@ -226,29 +226,29 @@ static int mod_evhost_parse_host(connection *con,array *host) { static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(path_pieces); PATCH(len); - + /* 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("evhost.path-pattern"))) { PATCH(path_pieces); PATCH(len); } } } - + return 0; } #undef PATCH @@ -261,29 +261,29 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) register char *ptr; int not_good = 0; stat_cache_entry *sce = NULL; - + /* not authority set */ if (con->uri.authority->used == 0) return HANDLER_GO_ON; - + mod_evhost_patch_connection(srv, con, p); - + /* missing even default(global) conf */ if (0 == p->conf.len) { return HANDLER_GO_ON; } parsed_host = array_init(); - + mod_evhost_parse_host(con, parsed_host); - + /* build document-root */ buffer_reset(p->tmp_buf); - + for (i = 0; i < p->conf.len; i++) { ptr = p->conf.path_pieces[i]->ptr; if (*ptr == '%') { data_string *ds; - + if (*(ptr+1) == '%') { /* %% */ BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%"); @@ -298,11 +298,11 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]); } } - + BUFFER_APPEND_SLASH(p->tmp_buf); - + array_free(parsed_host); - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) { log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf); not_good = 1; @@ -310,11 +310,11 @@ static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf); not_good = 1; } - + if (!not_good) { buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf); } - + return HANDLER_GO_ON; } @@ -325,9 +325,9 @@ int mod_evhost_plugin_init(plugin *p) { p->set_defaults = mod_evhost_set_defaults; p->handle_docroot = mod_evhost_uri_handler; p->cleanup = mod_evhost_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_expire.c b/src/mod_expire.c index 619b542..037e21a 100644 --- a/src/mod_expire.c +++ b/src/mod_expire.c @@ -12,8 +12,8 @@ #include "stat_cache.h" /** - * this is a expire module for a lighttpd - * + * this is a expire module for a lighttpd + * * set 'Expires:' HTTP Headers on demand */ @@ -27,51 +27,51 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *expire_tstmp; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_expire_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->expire_tstmp = buffer_init(); - + buffer_prepare_copy(p->expire_tstmp, 255); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_expire_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + buffer_free(p->expire_tstmp); - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; - + array_free(s->expire_url); - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } @@ -79,25 +79,25 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in char *ts; int type = -1; int retts = 0; - + UNUSED(p); - /* + /* * parse - * + * * '(access|modification) [plus] {<num> <type>}*' - * + * * e.g. 'access 1 years' */ - + if (expire->used == 0) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "empty:"); return -1; } - + ts = expire->ptr; - + if (0 == strncmp(ts, "access ", 7)) { type = 0; ts += 7; @@ -110,39 +110,39 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in "invalid <base>:", ts); return -1; } - + if (0 == strncmp(ts, "plus ", 5)) { /* skip the optional plus */ ts += 5; } - + /* the rest is just <number> (years|months|days|hours|minutes|seconds) */ while (1) { char *space, *err; int num; - + if (NULL == (space = strchr(ts, ' '))) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "missing space after <num>:", ts); return -1; } - + num = strtol(ts, &err, 10); if (*err != ' ') { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "missing <type> after <num>:", ts); return -1; } - + ts = space + 1; - + if (NULL != (space = strchr(ts, ' '))) { int slen; /* */ - + slen = space - ts; - - if (slen == 5 && + + if (slen == 5 && 0 == strncmp(ts, "years", slen)) { num *= 60 * 60 * 24 * 30 * 12; } else if (slen == 6 && @@ -161,13 +161,13 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in 0 == strncmp(ts, "seconds", slen)) { num *= 1; } else { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "unknown type:", ts); return -1; } - + retts += num; - + ts = space + 1; } else { if (0 == strcmp(ts, "years")) { @@ -183,19 +183,19 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in } else if (0 == strcmp(ts, "seconds")) { num *= 1; } else { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "unknown type:", ts); return -1; } - + retts += num; - + break; } } - + if (offset != NULL) *offset = retts; - + return type; } @@ -205,43 +205,43 @@ static int mod_expire_get_offset(server *srv, plugin_data *p, buffer *expire, in SETDEFAULTS_FUNC(mod_expire_set_defaults) { plugin_data *p = p_d; size_t i = 0, k; - - config_values_t cv[] = { + + config_values_t cv[] = { { "expire.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->expire_url = array_init(); - + cv[0].destination = s->expire_url; - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } - + for (k = 0; k < s->expire_url->used; k++) { data_string *ds = (data_string *)s->expire_url->data[k]; - + /* parse lines */ if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "parsing expire.url failed:", ds->value); return HANDLER_ERROR; } } } - - + + return HANDLER_GO_ON; } @@ -250,27 +250,27 @@ SETDEFAULTS_FUNC(mod_expire_set_defaults) { static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(expire_url); - + /* 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("expire.url"))) { PATCH(expire_url); } } } - + return 0; } #undef PATCH @@ -279,28 +279,28 @@ URIHANDLER_FUNC(mod_expire_path_handler) { plugin_data *p = p_d; int s_len; size_t k; - + if (con->uri.path->used == 0) return HANDLER_GO_ON; - + mod_expire_patch_connection(srv, con, p); - + s_len = con->uri.path->used - 1; - + for (k = 0; k < p->conf.expire_url->used; k++) { data_string *ds = (data_string *)p->conf.expire_url->data[k]; int ct_len = ds->key->used - 1; - + if (ct_len > s_len) continue; if (ds->key->used == 0) continue; - + if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) { int ts; time_t t; size_t len; stat_cache_entry *sce = NULL; - + stat_cache_get_entry(srv, con, con->physical.path, &sce); - + switch(mod_expire_get_offset(srv, p, ds->value, &ts)) { case 0: /* access */ @@ -308,38 +308,38 @@ URIHANDLER_FUNC(mod_expire_path_handler) { break; case 1: /* modification */ - + t = (ts + sce->st.st_mtime); break; default: /* -1 is handled at parse-time */ break; } - - - if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1, + + + if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) { /* could not set expire header, out of mem */ - + return HANDLER_GO_ON; - + } - + p->expire_tstmp->used = len + 1; - - /* HTTP/1.0 */ + + /* HTTP/1.0 */ response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp)); - /* HTTP/1.1 */ + /* HTTP/1.1 */ buffer_copy_string(p->expire_tstmp, "max-age="); buffer_append_long(p->expire_tstmp, ts); - + response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp)); - + return HANDLER_GO_ON; } } - + /* not found */ return HANDLER_GO_ON; } @@ -349,13 +349,13 @@ URIHANDLER_FUNC(mod_expire_path_handler) { int mod_expire_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("expire"); - + p->init = mod_expire_init; p->handle_subrequest_start = mod_expire_path_handler; p->set_defaults = mod_expire_set_defaults; p->cleanup = mod_expire_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c index 4f7260b..bd30179 100644 --- a/src/mod_fastcgi.c +++ b/src/mod_fastcgi.c @@ -25,7 +25,15 @@ #include "stat_cache.h" #include "status_counter.h" +#ifdef HAVE_FASTCGI_FASTCGI_H +#include <fastcgi/fastcgi.h> +#else +#ifdef HAVE_FASTCGI_H #include <fastcgi.h> +#else +#include "fastcgi.h" +#endif +#endif /* HAVE_FASTCGI_FASTCGI_H */ #include <stdio.h> #ifdef HAVE_SYS_FILIO_H @@ -48,12 +56,12 @@ /* - * + * * TODO: - * + * * - add timeout for a connect to a non-fastcgi process * (use state_timestamp + state) - * + * */ typedef struct fcgi_proc { @@ -62,7 +70,7 @@ typedef struct fcgi_proc { unsigned port; /* config.port + pno */ buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */ - + pid_t pid; /* PID of the spawned process (0 if not spawned locally) */ @@ -71,20 +79,20 @@ typedef struct fcgi_proc { time_t last_used; /* see idle_timeout */ size_t requests; /* see max_requests */ struct fcgi_proc *prev, *next; /* see first */ - + time_t disabled_until; /* this proc is disabled until, use something else until than */ - + int is_local; - enum { + enum { PROC_STATE_UNSET, /* init-phase */ PROC_STATE_RUNNING, /* alive */ - PROC_STATE_OVERLOADED, /* listen-queue is full, + PROC_STATE_OVERLOADED, /* listen-queue is full, don't send something to this proc for the next 2 seconds */ PROC_STATE_DIED_WAIT_FOR_PID, /* */ PROC_STATE_DIED, /* marked as dead, should be restarted */ PROC_STATE_KILLED /* was killed as we don't have the load anymore */ - } state; + } state; } fcgi_proc; typedef struct { @@ -95,20 +103,20 @@ typedef struct { * sorted by lowest load * * whenever a job is done move it up in the list - * until it is sorted, move it down as soon as the + * until it is sorted, move it down as soon as the * job is started */ - fcgi_proc *first; - fcgi_proc *unused_procs; + fcgi_proc *first; + fcgi_proc *unused_procs; - /* + /* * spawn at least min_procs, at max_procs. * - * as soon as the load of the first entry + * as soon as the load of the first entry * is max_load_per_proc we spawn a new one - * and add it to the first entry and give it + * and add it to the first entry and give it * the load - * + * */ unsigned short min_procs; @@ -120,44 +128,44 @@ typedef struct { /* * kick the process from the list if it was not - * used for idle_timeout until min_procs is + * used for idle_timeout until min_procs is * reached. this helps to get the processlist * small again we had a small peak load. * */ - + unsigned short idle_timeout; - + /* * time after a disabled remote connection is tried to be re-enabled - * - * + * + * */ - + unsigned short disable_time; /* * same fastcgi processes get a little bit larger - * than wanted. max_requests_per_proc kills a + * than wanted. max_requests_per_proc kills a * process after a number of handled requests. * */ size_t max_requests_per_proc; - + /* config */ - /* - * host:port + /* + * host:port * - * if host is one of the local IP adresses the + * if host is one of the local IP adresses the * whole connection is local * * if tcp/ip should be used host AND port have - * to be specified - * - */ - buffer *host; + * to be specified + * + */ + buffer *host; unsigned short port; /* @@ -170,7 +178,7 @@ typedef struct { */ buffer *unixsocket; - /* if socket is local we can start the fastcgi + /* if socket is local we can start the fastcgi * process ourself * * bin-path is the path to the binary @@ -178,19 +186,19 @@ typedef struct { * check min_procs and max_procs for the number * of process to start-up */ - buffer *bin_path; - - /* bin-path is set bin-environment is taken to + buffer *bin_path; + + /* bin-path is set bin-environment is taken to * create the environement before starting the * FastCGI process - * + * */ array *bin_env; - + array *bin_env_copy; - + /* - * docroot-translation between URL->phys and the + * docroot-translation between URL->phys and the * remote host * * reasons: @@ -209,7 +217,7 @@ typedef struct { unsigned short mode; /* - * check_local tell you if the phys file is stat()ed + * check_local tell you if the phys file is stat()ed * or not. FastCGI doesn't care if the service is * remote. If the web-server side doesn't contain * the fastcgi-files we should not stat() for them @@ -219,11 +227,11 @@ typedef struct { /* * append PATH_INFO to SCRIPT_FILENAME - * + * * php needs this if cgi.fix_pathinfo is provied - * + * */ - + unsigned short break_scriptfilename_for_php; /* @@ -232,12 +240,12 @@ typedef struct { * */ unsigned short allow_xsendfile; - + ssize_t load; /* replace by host->load */ size_t max_id; /* corresponds most of the time to num_procs. - + only if a process is killed max_id waits for the process itself to die and decrements its afterwards */ @@ -246,17 +254,17 @@ typedef struct { /* * one extension can have multiple hosts assigned - * one host can spawn additional processes on the same + * one host can spawn additional processes on the same * socket (if we control it) * * ext -> host -> procs * 1:n 1:n * - * if the fastcgi process is remote that whole goes down + * if the fastcgi process is remote that whole goes down * to * * ext -> host -> procs - * 1:n 1:1 + * 1:n 1:1 * * in case of PHP and FCGI_CHILDREN we have again a procs * but we don't control it directly. @@ -269,7 +277,7 @@ typedef struct { int note_is_sent; fcgi_extension_host **hosts; - + size_t used; size_t size; } fcgi_extension; @@ -283,10 +291,10 @@ typedef struct { typedef struct { - fcgi_exts *exts; + fcgi_exts *exts; array *ext_mapping; - + int debug; } plugin_config; @@ -298,7 +306,7 @@ typedef struct { typedef struct { char **ptr; - + size_t size; size_t used; } char_array; @@ -307,44 +315,44 @@ typedef struct { typedef struct { PLUGIN_DATA; buffer_uint fcgi_request_id; - + buffer *fcgi_env; - + buffer *path; buffer *parse_response; buffer *statuskey; - + plugin_config **config_storage; - + plugin_config conf; /* this is only used as long as no handler_ctx is setup */ } plugin_data; /* connection specific data */ -typedef enum { +typedef enum { FCGI_STATE_UNSET, - FCGI_STATE_INIT, - FCGI_STATE_CONNECT_DELAYED, - FCGI_STATE_PREPARE_WRITE, - FCGI_STATE_WRITE, - FCGI_STATE_READ + 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; - + int reconnects; /* number of reconnect attempts */ - + chunkqueue *rb; /* read queue */ chunkqueue *wb; /* write queue */ - + buffer *response_header; - + size_t request_id; int fd; /* fd to the fastcgi process */ int fde_ndx; /* index into the fd-event buffer */ @@ -353,9 +361,9 @@ typedef struct { int got_proc; int send_content_body; - + plugin_config conf; - + connection *remote_conn; /* dumb pointer */ plugin_data *plugin_data; /* dumb pointer */ } handler_ctx; @@ -387,7 +395,7 @@ int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_ CLEAN(".connected"); CLEAN(".load"); -#undef CLEAN +#undef CLEAN #define CLEAN(x) \ fastcgi_status_copy_procname(b, host, NULL); \ @@ -396,33 +404,33 @@ int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_ CLEAN(".load"); -#undef CLEAN +#undef CLEAN return 0; } static handler_ctx * handler_ctx_init() { handler_ctx * hctx; - + hctx = calloc(1, sizeof(*hctx)); assert(hctx); - + hctx->fde_ndx = -1; - + hctx->response_header = buffer_init(); - + hctx->request_id = 0; hctx->state = FCGI_STATE_INIT; hctx->proc = NULL; - + hctx->fd = -1; - + hctx->reconnects = 0; hctx->send_content_body = 1; hctx->rb = chunkqueue_init(); hctx->wb = chunkqueue_init(); - + return hctx; } @@ -431,7 +439,7 @@ static void handler_ctx_free(handler_ctx *hctx) { hctx->host->load--; hctx->host = NULL; } - + buffer_free(hctx->response_header); chunkqueue_free(hctx->rb); @@ -446,21 +454,21 @@ fcgi_proc *fastcgi_process_init() { f = calloc(1, sizeof(*f)); f->unixsocket = buffer_init(); f->connection_name = buffer_init(); - + f->prev = NULL; f->next = NULL; - + return f; } void fastcgi_process_free(fcgi_proc *f) { if (!f) return; - + fastcgi_process_free(f->next); - + buffer_free(f->unixsocket); buffer_free(f->connection_name); - + free(f); } @@ -477,13 +485,13 @@ fcgi_extension_host *fastcgi_host_init() { f->bin_env = array_init(); f->bin_env_copy = array_init(); f->strip_request_uri = buffer_init(); - + return f; } void fastcgi_host_free(fcgi_extension_host *h) { if (!h) return; - + buffer_free(h->id); buffer_free(h->host); buffer_free(h->unixsocket); @@ -492,49 +500,49 @@ void fastcgi_host_free(fcgi_extension_host *h) { buffer_free(h->strip_request_uri); array_free(h->bin_env); array_free(h->bin_env_copy); - + fastcgi_process_free(h->first); fastcgi_process_free(h->unused_procs); - + free(h); - + } fcgi_exts *fastcgi_extensions_init() { fcgi_exts *f; f = calloc(1, sizeof(*f)); - + return f; } void fastcgi_extensions_free(fcgi_exts *f) { size_t i; - + if (!f) return; - + for (i = 0; i < f->used; i++) { fcgi_extension *fe; size_t j; - + fe = f->exts[i]; - + for (j = 0; j < fe->used; j++) { fcgi_extension_host *h; - + h = fe->hosts[j]; - + fastcgi_host_free(h); } - + buffer_free(fe->key); free(fe->hosts); - + free(fe); } - + free(f->exts); - + free(f); } @@ -583,24 +591,24 @@ int fastcgi_extension_insert(fcgi_exts *ext, buffer *key, fcgi_extension_host *f assert(fe->hosts); } - fe->hosts[fe->used++] = fh; + fe->hosts[fe->used++] = fh; return 0; - + } INIT_FUNC(mod_fastcgi_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->fcgi_env = buffer_init(); - + p->path = buffer_init(); p->parse_response = buffer_init(); p->statuskey = buffer_init(); - + return p; } @@ -608,81 +616,81 @@ INIT_FUNC(mod_fastcgi_init) { FREE_FUNC(mod_fastcgi_free) { plugin_data *p = p_d; buffer_uint *r = &(p->fcgi_request_id); - + UNUSED(srv); if (r->ptr) free(r->ptr); - + 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; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; fcgi_exts *exts; - + if (!s) continue; - + exts = s->exts; for (j = 0; j < exts->used; j++) { fcgi_extension *ex; - + ex = exts->exts[j]; - + for (n = 0; n < ex->used; n++) { fcgi_proc *proc; fcgi_extension_host *host; - + host = ex->hosts[n]; - + for (proc = host->first; proc; proc = proc->next) { if (proc->pid != 0) kill(proc->pid, SIGTERM); - - if (proc->is_local && + + if (proc->is_local && !buffer_is_empty(proc->unixsocket)) { unlink(proc->unixsocket->ptr); } } - + for (proc = host->unused_procs; proc; proc = proc->next) { if (proc->pid != 0) kill(proc->pid, SIGTERM); - - if (proc->is_local && + + if (proc->is_local && !buffer_is_empty(proc->unixsocket)) { unlink(proc->unixsocket->ptr); } } } } - + fastcgi_extensions_free(s->exts); array_free(s->ext_mapping); - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) { char *dst; - + if (!key || !val) return -1; - + dst = malloc(key_len + val_len + 3); memcpy(dst, key, key_len); dst[key_len] = '='; /* add the \0 from the value */ memcpy(dst + key_len + 1, val, val_len + 1); - + if (env->size == 0) { env->size = 16; env->ptr = malloc(env->size * sizeof(*env->ptr)); @@ -690,9 +698,9 @@ static int env_add(char_array *env, const char *key, size_t key_len, const char env->size += 16; env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); } - + env->ptr[env->used++] = dst; - + return 0; } @@ -711,15 +719,15 @@ static int parse_binpath(char_array *env, buffer *b) { if (env->size == 0) { env->size = 16; env->ptr = malloc(env->size * sizeof(*env->ptr)); - } else if (env->size == env->used) { + } else if (env->size == env->used) { env->size += 16; env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); } - + b->ptr[i] = '\0'; env->ptr[env->used++] = start; - + start = b->ptr + i + 1; break; default: @@ -752,7 +760,7 @@ static int parse_binpath(char_array *env, buffer *b) { return 0; } -static int fcgi_spawn_connection(server *srv, +static int fcgi_spawn_connection(server *srv, plugin_data *p, fcgi_extension_host *host, fcgi_proc *proc) { @@ -764,25 +772,25 @@ static int fcgi_spawn_connection(server *srv, #endif struct sockaddr_in fcgi_addr_in; struct sockaddr *fcgi_addr; - + socklen_t servlen; - + #ifndef HAVE_FORK return -1; #endif - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sdb", "new proc, socket:", proc->port, proc->unixsocket); } - + if (!buffer_is_empty(proc->unixsocket)) { memset(&fcgi_addr, 0, sizeof(fcgi_addr)); - + #ifdef HAVE_SYS_UN_H fcgi_addr_un.sun_family = AF_UNIX; strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr); - + #ifdef SUN_LEN servlen = SUN_LEN(&fcgi_addr_un); #else @@ -802,108 +810,108 @@ static int fcgi_spawn_connection(server *srv, #endif } else { fcgi_addr_in.sin_family = AF_INET; - + if (buffer_is_empty(host->host)) { fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); } else { struct hostent *he; - + /* set a usefull default */ fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); - - + + if (NULL == (he = gethostbyname(host->host->ptr))) { - log_error_write(srv, __FILE__, __LINE__, - "sdb", "gethostbyname failed: ", + log_error_write(srv, __FILE__, __LINE__, + "sdb", "gethostbyname failed: ", h_errno, host->host); return -1; } - + if (he->h_addrtype != AF_INET) { log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype); return -1; } - + if (he->h_length != sizeof(struct in_addr)) { log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length); return -1; } - + memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length); - + } fcgi_addr_in.sin_port = htons(proc->port); servlen = sizeof(fcgi_addr_in); - + socket_type = AF_INET; fcgi_addr = (struct sockaddr *) &fcgi_addr_in; - + buffer_copy_string(proc->connection_name, "tcp:"); buffer_append_string_buffer(proc->connection_name, host->host); buffer_append_string(proc->connection_name, ":"); buffer_append_long(proc->connection_name, proc->port); } - + if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "failed:", strerror(errno)); return -1; } - + if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { /* server is not up, spawn in */ pid_t child; int val; - - if (errno != ENOENT && + + if (errno != ENOENT && !buffer_is_empty(proc->unixsocket)) { unlink(proc->unixsocket->ptr); } - + close(fcgi_fd); - + /* reopen socket */ if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); return -1; } - + val = 1; if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno)); return -1; } - + /* create socket */ if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "bind failed for:", + log_error_write(srv, __FILE__, __LINE__, "sbs", + "bind failed for:", proc->connection_name, strerror(errno)); return -1; } - + if (-1 == listen(fcgi_fd, 1024)) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed:", strerror(errno)); return -1; } - -#ifdef HAVE_FORK + +#ifdef HAVE_FORK switch ((child = fork())) { case 0: { size_t i = 0; char *c; char_array env; char_array arg; - + /* create environment */ env.ptr = NULL; env.size = 0; env.used = 0; - + arg.ptr = NULL; arg.size = 0; arg.used = 0; @@ -913,18 +921,18 @@ static int fcgi_spawn_connection(server *srv, dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); close(fcgi_fd); } - + /* we don't need the client socket */ for (i = 3; i < 256; i++) { close(i); } - + /* build clean environment */ if (host->bin_env_copy->used) { for (i = 0; i < host->bin_env_copy->used; i++) { data_string *ds = (data_string *)host->bin_env_copy->data[i]; char *ge; - + if (NULL != (ge = getenv(ds->value->ptr))) { env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge)); } @@ -932,39 +940,39 @@ static int fcgi_spawn_connection(server *srv, } else { for (i = 0; environ[i]; i++) { char *eq; - + if (NULL != (eq = strchr(environ[i], '='))) { env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1)); } } } - + /* create environment */ for (i = 0; i < host->bin_env->used; i++) { data_string *ds = (data_string *)host->bin_env->data[i]; - + env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value)); } - + for (i = 0; i < env.used; i++) { /* search for PHP_FCGI_CHILDREN */ if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break; } - + /* not found, add a default */ if (i == env.used) { env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1")); } - + env.ptr[env.used] = NULL; 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 = '/'; @@ -976,12 +984,12 @@ static int fcgi_spawn_connection(server *srv, /* exec the cgi */ execve(arg.ptr[0], arg.ptr, env.ptr); - - log_error_write(srv, __FILE__, __LINE__, "sbs", + + log_error_write(srv, __FILE__, __LINE__, "sbs", "execve failed for:", host->bin_path, strerror(errno)); - + exit(errno); - + break; } case -1: @@ -989,17 +997,17 @@ static int fcgi_spawn_connection(server *srv, break; default: /* father */ - + /* wait */ select(0, NULL, NULL, NULL, &tv); - + switch (waitpid(child, &status, WNOHANG)) { case 0: /* child still running after timeout, good */ break; case -1: /* no PID found ? should never happen */ - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "pid not found:", strerror(errno)); return -1; default: @@ -1007,10 +1015,10 @@ static int fcgi_spawn_connection(server *srv, "the fastcgi-backend", host->bin_path, "failed to start:"); /* the child should not terminate at all */ if (WIFEXITED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sdb", - "child exited with status", + log_error_write(srv, __FILE__, __LINE__, "sdb", + "child exited with status", WEXITSTATUS(status), host->bin_path); - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n" "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' " "in the output, NOT (cgi) NOR (cli)\n" @@ -1018,8 +1026,8 @@ static int fcgi_spawn_connection(server *srv, log_error_write(srv, __FILE__, __LINE__, "s", "If this is PHP on Gentoo add fastcgi to the USE flags"); } else if (WIFSIGNALED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "terminated by signal:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "terminated by signal:", WTERMSIG(status)); if (WTERMSIG(status) == 11) { @@ -1029,8 +1037,8 @@ static int fcgi_spawn_connection(server *srv, "If this is PHP try to remove the byte-code caches for now and try again."); } } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", status); } return -1; @@ -1040,26 +1048,26 @@ static int fcgi_spawn_connection(server *srv, proc->pid = child; proc->last_used = srv->cur_ts; proc->is_local = 1; - + break; } #endif } else { proc->is_local = 0; proc->pid = 0; - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) socket is already used, won't spawn:", proc->connection_name); } } - + proc->state = PROC_STATE_RUNNING; host->active_procs++; - + close(fcgi_fd); - + return 0; } @@ -1069,93 +1077,93 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { data_unset *du; size_t i = 0; buffer *fcgi_mode = buffer_init(); - - config_values_t cv[] = { + + config_values_t cv[] = { { "fastcgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "fastcgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "fastcgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { 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; array *ca; - + s = malloc(sizeof(plugin_config)); s->exts = fastcgi_extensions_init(); s->debug = 0; s->ext_mapping = array_init(); - + cv[0].destination = s->exts; cv[1].destination = &(s->debug); cv[2].destination = s->ext_mapping; - + p->config_storage[i] = s; ca = ((data_config *)srv->config_context->data[i])->value; - + if (0 != config_insert_values_global(srv, ca, cv)) { return HANDLER_ERROR; } - - /* + + /* * <key> = ( ... ) */ - + if (NULL != (du = array_get_element(ca, "fastcgi.server"))) { size_t j; data_array *da = (data_array *)du; - + if (du->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sss", + log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", "fastcgi.server", "array of strings"); - + return HANDLER_ERROR; } - - - /* - * fastcgi.server = ( "<ext>" => ( ... ), + + + /* + * fastcgi.server = ( "<ext>" => ( ... ), * "<ext>" => ( ... ) ) */ - + for (j = 0; j < da->value->used; j++) { size_t n; data_array *da_ext = (data_array *)da->value->data[j]; - + if (da->value->data[j]->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sssbs", - "unexpected type for key: ", "fastcgi.server", + log_error_write(srv, __FILE__, __LINE__, "sssbs", + "unexpected type for key: ", "fastcgi.server", "[", da->value->data[j]->key, "](string)"); - + return HANDLER_ERROR; } - - /* - * da_ext->key == name of the extension + + /* + * da_ext->key == name of the extension */ - - /* - * fastcgi.server = ( "<ext>" => - * ( "<host>" => ( ... ), + + /* + * fastcgi.server = ( "<ext>" => + * ( "<host>" => ( ... ), * "<host>" => ( ... ) - * ), + * ), * "<ext>" => ... ) */ - + for (n = 0; n < da_ext->value->used; n++) { data_array *da_host = (data_array *)da_ext->value->data[n]; - + fcgi_extension_host *host; - - config_values_t fcv[] = { + + config_values_t fcv[] = { { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "mode", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */ - + { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */ { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */ { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */ @@ -1163,28 +1171,28 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */ { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */ { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */ - + { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */ { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */ - + { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */ { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */ { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */ - + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (da_host->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "ssSBS", - "unexpected type for key:", - "fastcgi.server", + log_error_write(srv, __FILE__, __LINE__, "ssSBS", + "unexpected type for key:", + "fastcgi.server", "[", da_host->key, "](string)"); - + return HANDLER_ERROR; } - + host = fastcgi_host_init(); - + buffer_copy_string_buffer(host->id, da_host->key); host->check_local = 1; @@ -1196,13 +1204,13 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { host->disable_time = 60; host->break_scriptfilename_for_php = 0; host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */ - + fcv[0].destination = host->host; fcv[1].destination = host->docroot; fcv[2].destination = fcgi_mode; fcv[3].destination = host->unixsocket; fcv[4].destination = host->bin_path; - + fcv[5].destination = &(host->check_local); fcv[6].destination = &(host->port); fcv[7].destination = &(host->min_procs); @@ -1210,35 +1218,35 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { fcv[9].destination = &(host->max_load_per_proc); fcv[10].destination = &(host->idle_timeout); fcv[11].destination = &(host->disable_time); - + 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(host->host) || host->port) && + + if ((!buffer_is_empty(host->host) || host->port) && !buffer_is_empty(host->unixsocket)) { - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", "either host/port or socket have to be set in:", - da->key, "= (", + da->key, "= (", da_ext->key, " => (", da_host->key, " ( ..."); return HANDLER_ERROR; } - + if (!buffer_is_empty(host->unixsocket)) { /* unix domain socket */ - + if (host->unixsocket->used > UNIX_PATH_MAX - 2) { - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", "unixsocket is too long in:", - da->key, "= (", + da->key, "= (", da_ext->key, " => (", da_host->key, " ( ..."); @@ -1246,37 +1254,37 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { } } else { /* tcp/ip */ - - if (buffer_is_empty(host->host) && + + if (buffer_is_empty(host->host) && buffer_is_empty(host->bin_path)) { - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", "host or binpath have to be set in:", - da->key, "= (", + da->key, "= (", da_ext->key, " => (", da_host->key, " ( ..."); - + return HANDLER_ERROR; } else if (host->port == 0) { - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs", "port has to be set in:", - da->key, "= (", + da->key, "= (", da_ext->key, " => (", da_host->key, " ( ..."); return HANDLER_ERROR; } } - - if (!buffer_is_empty(host->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 */ host->min_procs = host->max_procs; - + 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", @@ -1286,7 +1294,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { "\n\tmin-procs:", host->min_procs, "\n\tmax-procs:", host->max_procs); } - + for (pno = 0; pno < host->min_procs; pno++) { fcgi_proc *proc; @@ -1301,7 +1309,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { buffer_append_string(proc->unixsocket, "-"); buffer_append_long(proc->unixsocket, pno); } - + if (s->debug) { log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd", "--- fastcgi spawning", @@ -1309,7 +1317,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { "\n\tsocket", host->unixsocket, "\n\tcurrent:", pno, "/", host->min_procs); } - + if (fcgi_spawn_connection(srv, p, host, proc)) { log_error_write(srv, __FILE__, __LINE__, "s", "[ERROR]: spawning fcgi failed."); @@ -1317,35 +1325,35 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { } fastcgi_status_init(srv, p->statuskey, host, proc); - + proc->next = host->first; if (host->first) host->first->prev = proc; - + host->first = proc; } } else { fcgi_proc *proc; - + proc = fastcgi_process_init(); proc->id = host->num_procs++; host->max_id++; host->active_procs++; proc->state = PROC_STATE_RUNNING; - + if (buffer_is_empty(host->unixsocket)) { proc->port = host->port; } else { buffer_copy_string_buffer(proc->unixsocket, host->unixsocket); } - + fastcgi_status_init(srv, p->statuskey, host, proc); host->first = proc; - + host->min_procs = 1; host->max_procs = 1; } - + if (!buffer_is_empty(fcgi_mode)) { if (strcmp(fcgi_mode->ptr, "responder") == 0) { host->mode = FCGI_RESPONDER; @@ -1369,16 +1377,16 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) { } } } - + buffer_free(fcgi_mode); - + return HANDLER_GO_ON; } static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) { hctx->state = state; hctx->state_timestamp = srv->cur_ts; - + return 0; } @@ -1387,13 +1395,13 @@ static size_t fcgi_requestid_new(server *srv, plugin_data *p) { size_t m = 0; size_t i; buffer_uint *r = &(p->fcgi_request_id); - + UNUSED(srv); for (i = 0; i < r->used; i++) { if (r->ptr[i] > m) m = r->ptr[i]; } - + if (r->size == 0) { r->size = 16; r->ptr = malloc(sizeof(*r->ptr) * r->size); @@ -1401,54 +1409,54 @@ static size_t fcgi_requestid_new(server *srv, plugin_data *p) { r->size += 16; r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size); } - + r->ptr[r->used++] = ++m; - + return m; } static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) { size_t i; buffer_uint *r = &(p->fcgi_request_id); - + UNUSED(srv); for (i = 0; i < r->used; i++) { if (r->ptr[i] == request_id) break; } - + if (i != r->used) { /* found */ - + if (i != r->used - 1) { r->ptr[i] = r->ptr[r->used - 1]; } r->used--; } - + return 0; } void fcgi_connection_close(server *srv, handler_ctx *hctx) { plugin_data *p; connection *con; - + if (NULL == hctx) return; - + p = hctx->plugin_data; con = hctx->remote_conn; - + if (con->mode != p->id) { WP(); return; } - + 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--; } - + if (hctx->request_id != 0) { fcgi_requestid_del(srv, p, hctx->request_id); } @@ -1457,7 +1465,7 @@ void fcgi_connection_close(server *srv, handler_ctx *hctx) { if (hctx->got_proc) { /* 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); @@ -1467,39 +1475,39 @@ void fcgi_connection_close(server *srv, handler_ctx *hctx) { if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ssdsbsd", - "released proc:", - "pid:", hctx->proc->pid, - "socket:", hctx->proc->connection_name, + "released proc:", + "pid:", hctx->proc->pid, + "socket:", hctx->proc->connection_name, "load:", hctx->proc->load); } } } - + handler_ctx_free(hctx); - con->plugin_ctx[p->id] = NULL; + con->plugin_ctx[p->id] = NULL; } static int fcgi_reconnect(server *srv, handler_ctx *hctx) { plugin_data *p = hctx->plugin_data; - - /* child died - * - * 1. - * + + /* child died + * + * 1. + * * connect was ok, connection was accepted * but the php accept loop checks after the accept if it should die or not. - * - * if yes we can only detect it at a write() - * + * + * if yes we can only detect it at a write() + * * next step is resetting this attemp and setup a connection again - * + * * if we have more then 5 reconnects for the same request, die - * - * 2. - * + * + * 2. + * * we have a connection but the child died by some other reason - * + * */ if (hctx->fd != -1) { @@ -1509,59 +1517,59 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) { srv->cur_fds--; hctx->fd = -1; } - + fcgi_requestid_del(srv, p, hctx->request_id); - + fcgi_set_state(srv, hctx, FCGI_STATE_INIT); - + hctx->request_id = 0; hctx->reconnects++; - + if (p->conf.debug > 2) { if (hctx->proc) { log_error_write(srv, __FILE__, __LINE__, "sdb", - "release proc for reconnect:", + "release proc for reconnect:", hctx->proc->pid, hctx->proc->connection_name); } else { log_error_write(srv, __FILE__, __LINE__, "sb", - "release proc for reconnect:", + "release proc for reconnect:", hctx->host->unixsocket); } } - if (hctx->proc && hctx->got_proc) { + if (hctx->proc && hctx->got_proc) { hctx->proc->load--; } /* perhaps another host gives us more luck */ hctx->host->load--; hctx->host = NULL; - + return 0; } static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - + fcgi_connection_close(srv, con->plugin_ctx[p->id]); - + return HANDLER_GO_ON; } static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) { size_t len; - + if (!key || !val) return -1; - + len = key_len + val_len; - + len += key_len > 127 ? 4 : 1; len += val_len > 127 ? 4 : 1; - + buffer_prepare_append(env, len); - + if (key_len > 127) { env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80; env->ptr[env->used++] = (key_len >> 16) & 0xff; @@ -1570,7 +1578,7 @@ static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char } else { env->ptr[env->used++] = (key_len >> 0) & 0xff; } - + if (val_len > 127) { env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80; env->ptr[env->used++] = (val_len >> 16) & 0xff; @@ -1579,12 +1587,12 @@ static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char } else { env->ptr[env->used++] = (val_len >> 0) & 0xff; } - + memcpy(env->ptr + env->used, key, key_len); env->used += key_len; memcpy(env->ptr + env->used, val, val_len); env->used += val_len; - + return 0; } @@ -1597,11 +1605,11 @@ static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_ header->contentLengthB1 = (contentLength >> 8) & 0xff; header->paddingLength = paddingLength; header->reserved = 0; - + return 0; } /** - * + * * returns * -1 error * 0 connected @@ -1623,13 +1631,13 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h struct sockaddr_un fcgi_addr_un; #endif socklen_t servlen; - + fcgi_extension_host *host = hctx->host; fcgi_proc *proc = hctx->proc; int fcgi_fd = hctx->fd; - + memset(&fcgi_addr, 0, sizeof(fcgi_addr)); - + if (!buffer_is_empty(proc->unixsocket)) { #ifdef HAVE_SYS_UN_H /* use the unix domain socket */ @@ -1642,7 +1650,7 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family); #endif fcgi_addr = (struct sockaddr *) &fcgi_addr_un; - + if (buffer_is_empty(proc->connection_name)) { /* on remote spawing we have to set the connection-name now */ buffer_copy_string(proc->connection_name, "unix:"); @@ -1654,15 +1662,15 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h } else { fcgi_addr_in.sin_family = AF_INET; if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "converting IP-adress failed for", host->host, + log_error_write(srv, __FILE__, __LINE__, "sbs", + "converting IP-adress failed for", host->host, "\nBe sure to specify an IP address here"); - + return -1; } fcgi_addr_in.sin_port = htons(proc->port); servlen = sizeof(fcgi_addr_in); - + fcgi_addr = (struct sockaddr *) &fcgi_addr_in; if (buffer_is_empty(proc->connection_name)) { @@ -1673,20 +1681,20 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h buffer_append_long(proc->connection_name, proc->port); } } - + if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { - if (errno == EINPROGRESS || + if (errno == EINPROGRESS || errno == EALREADY || errno == EINTR) { if (hctx->conf.debug > 2) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "connect delayed, will continue later:", proc->connection_name); } - + return CONNECTION_DELAYED; } else if (errno == EAGAIN) { if (hctx->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbsd", + log_error_write(srv, __FILE__, __LINE__, "sbsd", "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", proc->connection_name, "is", proc->load); @@ -1694,8 +1702,8 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h return CONNECTION_OVERLOADED; } else { - log_error_write(srv, __FILE__, __LINE__, "sssb", - "connect failed:", + log_error_write(srv, __FILE__, __LINE__, "sssb", + "connect failed:", strerror(errno), "on", proc->connection_name); @@ -1705,7 +1713,7 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h hctx->reconnects = 0; if (hctx->conf.debug > 1) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "connect succeeded: ", fcgi_fd); } @@ -1714,21 +1722,21 @@ static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *h static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) { size_t i; - + for (i = 0; i < con->request.headers->used; i++) { data_string *ds; - + ds = (data_string *)con->request.headers->data[i]; - + if (ds->value->used && ds->key->used) { size_t j; buffer_reset(srv->tmp_buf); - + if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) { BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_"); srv->tmp_buf->used--; } - + buffer_prepare_append(srv->tmp_buf, ds->key->used + 2); for (j = 0; j < ds->key->used - 1; j++) { char c = '_'; @@ -1742,20 +1750,20 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat srv->tmp_buf->ptr[srv->tmp_buf->used++] = c; } srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0'; - + fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)); } } - + for (i = 0; i < con->environment->used; i++) { data_string *ds; - + ds = (data_string *)con->environment->data[i]; - + if (ds->value->used && ds->key->used) { size_t j; buffer_reset(srv->tmp_buf); - + buffer_prepare_append(srv->tmp_buf, ds->key->used + 2); for (j = 0; j < ds->key->used - 1; j++) { char c = '_'; @@ -1769,11 +1777,11 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat srv->tmp_buf->ptr[srv->tmp_buf->used++] = c; } srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0'; - + fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)); } } - + return 0; } @@ -1782,24 +1790,24 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { FCGI_BeginRequestRecord beginRecord; FCGI_Header header; buffer *b; - + char buf[32]; const char *s; #ifdef HAVE_IPV6 char b2[INET6_ADDRSTRLEN + 1]; #endif - + plugin_data *p = hctx->plugin_data; fcgi_extension_host *host= hctx->host; connection *con = hctx->remote_conn; server_socket *srv_sock = con->srv_socket; - + sock_addr our_addr; socklen_t our_addr_len; - + /* send FCGI_BEGIN_REQUEST */ - + fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0); beginRecord.body.roleB0 = host->mode; beginRecord.body.roleB1 = 0; @@ -1807,21 +1815,21 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved)); b = chunkqueue_get_append_buffer(hctx->wb); - + buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord)); - + /* send FCGI_PARAMS */ buffer_prepare_copy(p->fcgi_env, 1024); fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION)); - + if (con->server_name->used) { fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name)); } else { #ifdef HAVE_IPV6 - s = inet_ntop(srv_sock->addr.plain.sa_family, - srv_sock->addr.plain.sa_family == AF_INET6 ? + s = inet_ntop(srv_sock->addr.plain.sa_family, + srv_sock->addr.plain.sa_family == AF_INET6 ? (const void *) &(srv_sock->addr.ipv6.sin6_addr) : (const void *) &(srv_sock->addr.ipv4.sin_addr), b2, sizeof(b2)-1); @@ -1830,50 +1838,50 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { #endif fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s)); } - + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")); - - ltostr(buf, + + ltostr(buf, #ifdef HAVE_IPV6 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port) #else ntohs(srv_sock->addr.ipv4.sin_port) #endif ); - + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf)); - + /* get the server-side of the connection to the client */ our_addr_len = sizeof(our_addr); - + if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) { s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr)); } else { s = inet_ntop_cache_get_ip(srv, &(our_addr)); } fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)); - - ltostr(buf, + + ltostr(buf, #ifdef HAVE_IPV6 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port) #else ntohs(con->dst_addr.ipv4.sin_port) #endif ); - + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf)); - + s = inet_ntop_cache_get_ip(srv, &(con->dst_addr)); fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s)); - + if (!buffer_is_empty(con->authed_user)) { fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"), CONST_BUF_LEN(con->authed_user)); } - + if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) { /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */ - + /* request.content_length < SSIZE_MAX, see request.c */ ltostr(buf, con->request.content_length); fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)); @@ -1888,12 +1896,12 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { */ fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); - + if (!buffer_is_empty(con->request.pathinfo)) { fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); - + /* PATH_TRANSLATED is only defined if PATH_INFO is set */ - + if (!buffer_is_empty(host->docroot)) { buffer_copy_string_buffer(p->path, host->docroot); } else { @@ -1915,27 +1923,27 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { */ if (!buffer_is_empty(host->docroot)) { - /* - * rewrite SCRIPT_FILENAME - * + /* + * rewrite SCRIPT_FILENAME + * */ - + buffer_copy_string_buffer(p->path, host->docroot); buffer_append_string_buffer(p->path, con->uri.path); - + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)); fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot)); } else { buffer_copy_string_buffer(p->path, con->physical.path); - - /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself - * + + /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself + * * see src/sapi/cgi_main.c, init_request_info() */ if (host->break_scriptfilename_for_php) { buffer_append_string_buffer(p->path, con->request.pathinfo); } - + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)); fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root)); } @@ -1945,7 +1953,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { /** * /app1/index/list * - * stripping /app1 or /app1/ should lead to + * stripping /app1 or /app1/ should lead to * * /index/list * @@ -1959,7 +1967,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { 0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) { /* the left is the same */ - fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"), con->request.orig_uri->ptr + (host->strip_request_uri->used - 2), con->request.orig_uri->used - (host->strip_request_uri->used - 2)); } else { @@ -1976,26 +1984,26 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { } else { fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")); } - + s = get_http_method_name(con->request.http_method); fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)); fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */ s = get_http_version_name(con->request.http_version); fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)); - + #ifdef USE_OPENSSL if (srv_sock->is_ssl) { fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")); } #endif - - + + fcgi_env_add_request_headers(srv, con, p); - + fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0); buffer_append_memory(b, (const char *)&header, sizeof(header)); buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used); - + fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0); buffer_append_memory(b, (const char *)&header, sizeof(header)); @@ -2015,7 +2023,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { /* we announce toWrite octects * now take all the request_content chunk that we need to fill this request - * */ + * */ b = chunkqueue_get_append_buffer(hctx->wb); fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0); @@ -2038,16 +2046,16 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { if (weHave > weWant - written) weHave = weWant - written; if (p->conf.debug > 10) { - fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n", - __FILE__, __LINE__, - weHave, - req_c->offset, - req_c->file.length, + fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n", + __FILE__, __LINE__, + weHave, + req_c->offset, + req_c->file.length, req_c->file.name->ptr); } assert(weHave != 0); - + chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave); req_c->offset += weHave; @@ -2062,7 +2070,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { * - we reference the tempfile from the request-content-queue several times * if the req_c is larger than FCGI_MAX_LENGTH * - we can't simply cleanup the request-content-queue as soon as possible - * as it would remove the tempfiles + * as it would remove the tempfiles * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last * referencing chunk of the fastcgi-write-queue * @@ -2099,7 +2107,7 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { req_c->offset += weHave; req_cq->bytes_out += weHave; written += weHave; - + hctx->wb->bytes_in += weHave; if (req_c->offset == req_c->mem->used - 1) { @@ -2113,12 +2121,12 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { break; } } - + b->used++; /* add virtual \0 */ offset += weWant; } } - + b = chunkqueue_get_append_buffer(hctx->wb); /* terminate STDIN */ fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0); @@ -2133,59 +2141,59 @@ static int fcgi_create_env(server *srv, handler_ctx *hctx, size_t request_id) { if ((i+1) % 16 == 0) { size_t j; for (j = i-15; j <= i; j++) { - fprintf(stderr, "%c", + fprintf(stderr, "%c", isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.'); } fprintf(stderr, "\n"); } } #endif - + return 0; } static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) { char *s, *ns; - + handler_ctx *hctx = con->plugin_ctx[p->id]; fcgi_extension_host *host= hctx->host; - + UNUSED(srv); buffer_copy_string_buffer(p->parse_response, in); - + /* search for \n */ for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) { char *key, *value; int key_len; data_string *ds; - + /* a good day. Someone has read the specs and is sending a \r\n to us */ - + if (ns > p->parse_response->ptr && *(ns-1) == '\r') { *(ns-1) = '\0'; } - + ns[0] = '\0'; - + key = s; if (NULL == (value = strchr(s, ':'))) { /* we expect: "<key>: <value>\n" */ continue; } - + key_len = value - key; - + value++; /* strip WS */ while (*value == ' ' || *value == '\t') value++; - + if (host->mode != FCGI_AUTHORIZER || !(con->http_status == 0 || con->http_status == 200)) { /* authorizers shouldn't affect the response headers sent back to the client */ - + /* don't forward Status: */ if (0 != strncasecmp(key, "Status", key_len)) { if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { @@ -2193,11 +2201,11 @@ static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buf } buffer_copy_string_len(ds->key, key, key_len); buffer_copy_string(ds->value, value); - + array_insert_unique(con->response.headers, (data_unset *)ds); } } - + switch(key_len) { case 4: if (0 == strncasecmp(key, "Date", key_len)) { @@ -2225,7 +2233,7 @@ static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buf if (0 == strncasecmp(key, "Content-Length", key_len)) { con->response.content_length = strtol(value, NULL, 10); con->parsed_response |= HTTP_CONTENT_LENGTH; - + if (con->response.content_length < 0) con->response.content_length = 0; } break; @@ -2233,18 +2241,18 @@ static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buf break; } } - + /* CGI/1.1 rev 03 - 7.2.1.2 */ if ((con->parsed_response & HTTP_LOCATION) && !(con->parsed_response & HTTP_STATUS)) { con->http_status = 302; } - + return 0; } typedef struct { - buffer *b; + buffer *b; size_t len; int type; int padding; @@ -2285,9 +2293,9 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p return -1; } - /* we have at least a header, now check how much me have to fetch */ + /* we have at least a header, now check how much me have to fetch */ header = (FCGI_Header *)(packet->b->ptr); - + packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength; packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8)); packet->type = header->type; @@ -2306,7 +2314,7 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p size_t weHave = c->mem->used - c->offset - offset - 1; if (weHave > weWant) weHave = weWant; - + buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave); /* we only skipped the first 8 bytes as they are the fcgi header */ @@ -2338,7 +2346,7 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p } chunkqueue_remove_finished_chunks(hctx->rb); - + return 0; } @@ -2346,25 +2354,25 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { int fin = 0; int toread; ssize_t r; - + plugin_data *p = hctx->plugin_data; connection *con = hctx->remote_conn; int fcgi_fd = hctx->fd; fcgi_extension_host *host= hctx->host; fcgi_proc *proc = hctx->proc; - - /* - * check how much we have to read + + /* + * check how much we have to read */ if (ioctl(hctx->fd, FIONREAD, &toread)) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "unexpected end-of-file (perhaps the fastcgi process died):", fcgi_fd); return -1; } - + /* init read-buffer */ - + if (toread > 0) { buffer *b; @@ -2373,30 +2381,30 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { /* append to read-buffer */ if (-1 == (r = read(hctx->fd, b->ptr, toread))) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "unexpected end-of-file (perhaps the fastcgi process died):", fcgi_fd, strerror(errno)); return -1; } - + /* this should be catched by the b > 0 above */ assert(r); b->used = r + 1; /* one extra for the fake \0 */ b->ptr[b->used - 1] = '\0'; } else { - log_error_write(srv, __FILE__, __LINE__, "ssdsb", + log_error_write(srv, __FILE__, __LINE__, "ssdsb", "unexpected end-of-file (perhaps the fastcgi process died):", "pid:", proc->pid, "socket:", proc->connection_name); - + return -1; } /* * parse the fastcgi packets and forward the content to the write-queue * - */ + */ while (fin == 0) { fastcgi_response_packet packet; @@ -2415,9 +2423,9 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { char *c; size_t blen; data_string *ds; - - /* search for header terminator - * + + /* search for header terminator + * * if we start with \r\n check if last packet terminated with \r\n * if we start with \n check if last packet terminated with \n * search for \r\n\r\n @@ -2468,8 +2476,8 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { } } - - if (hctx->send_content_body && blen > 1) { + + if (hctx->send_content_body && blen > 1) { /* enable chunked-transfer-encoding */ if (con->request.http_version == HTTP_VERSION_1_1 && !(con->parsed_response & HTTP_CONTENT_LENGTH)) { @@ -2491,13 +2499,13 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { } break; case FCGI_STDERR: - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "FastCGI-stderr:", packet.b); - + break; case FCGI_END_REQUEST: con->file_finished = 1; - + if (host->mode != FCGI_AUTHORIZER || !(con->http_status == 0 || con->http_status == 200)) { @@ -2505,39 +2513,39 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) { http_chunk_append_mem(srv, con, NULL, 0); joblist_append(srv, con); } - + fin = 1; break; default: - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "FastCGI: header.type not handled: ", packet.type); break; } buffer_free(packet.b); } - + return fin; } static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) { fcgi_proc *proc; - + for (proc = host->first; proc; proc = proc->next) { int status; if (p->conf.debug > 2) { - log_error_write(srv, __FILE__, __LINE__, "sbdddd", - "proc:", + log_error_write(srv, __FILE__, __LINE__, "sbdddd", + "proc:", proc->connection_name, proc->state, proc->is_local, proc->load, proc->pid); } - - /* + + /* * if the remote side is overloaded, we check back after <n> seconds - * + * */ switch (proc->state) { case PROC_STATE_KILLED: @@ -2550,13 +2558,13 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h break; case PROC_STATE_OVERLOADED: if (srv->cur_ts <= proc->disabled_until) break; - + proc->state = PROC_STATE_RUNNING; host->active_procs++; - - log_error_write(srv, __FILE__, __LINE__, "sbdb", - "fcgi-server re-enabled:", - host->host, host->port, + + log_error_write(srv, __FILE__, __LINE__, "sbdb", + "fcgi-server re-enabled:", + host->host, host->port, host->unixsocket); break; case PROC_STATE_DIED_WAIT_FOR_PID: @@ -2564,7 +2572,7 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h if (!proc->is_local) break; /* the child should not terminate at all */ - + switch(waitpid(proc->pid, &status, WNOHANG)) { case 0: /* child is still alive */ @@ -2574,20 +2582,20 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h default: if (WIFEXITED(status)) { #if 0 - log_error_write(srv, __FILE__, __LINE__, "sdsd", + log_error_write(srv, __FILE__, __LINE__, "sdsd", "child exited, pid:", proc->pid, "status:", WEXITSTATUS(status)); #endif } else if (WIFSIGNALED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", WTERMSIG(status)); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", status); } - + proc->state = PROC_STATE_DIED; break; } @@ -2596,23 +2604,23 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h if (proc->state != PROC_STATE_DIED) break; case PROC_STATE_DIED: - /* local proc get restarted by us, + /* local proc get restarted by us, * remote ones hopefully by the admin */ - + if (proc->is_local) { /* we still have connections bound to this proc, * let them terminate first */ if (proc->load != 0) break; - + /* restart the child */ - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ssbsdsd", "--- fastcgi spawning", "\n\tsocket", proc->connection_name, "\n\tcurrent:", 1, "/", host->min_procs); } - + if (fcgi_spawn_connection(srv, p, host, proc)) { log_error_write(srv, __FILE__, __LINE__, "s", "ERROR: spawning fcgi failed."); @@ -2620,18 +2628,18 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h } } else { if (srv->cur_ts <= proc->disabled_until) break; - + proc->state = PROC_STATE_RUNNING; host->active_procs++; - - log_error_write(srv, __FILE__, __LINE__, "sb", - "fcgi-server re-enabled:", + + log_error_write(srv, __FILE__, __LINE__, "sb", + "fcgi-server re-enabled:", proc->connection_name); } break; } } - + return 0; } @@ -2640,19 +2648,19 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { fcgi_extension_host *host= hctx->host; connection *con = hctx->remote_conn; fcgi_proc *proc; - + int ret; - /* sanity check */ + /* sanity check */ if (!host || ((!host->host->used || !host->port) && !host->unixsocket->used)) { - log_error_write(srv, __FILE__, __LINE__, "sxddd", + log_error_write(srv, __FILE__, __LINE__, "sxddd", "write-req: error", host, host->host->used, host->port, host->unixsocket->used); - + hctx->proc->disabled_until = srv->cur_ts + 10; hctx->proc->state = PROC_STATE_DIED; @@ -2663,12 +2671,12 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { 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", + log_error_write(srv, __FILE__, __LINE__, "ss", "getsockopt failed:", strerror(errno)); - + hctx->proc->disabled_until = srv->cur_ts + 10; hctx->proc->state = PROC_STATE_DIED; @@ -2677,12 +2685,12 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { if (socket_error != 0) { if (!hctx->proc->is_local || p->conf.debug) { /* local procs get restarted */ - + log_error_write(srv, __FILE__, __LINE__, "sssb", - "establishing connection failed:", strerror(socket_error), + "establishing connection failed:", strerror(socket_error), "socket:", hctx->proc->connection_name); } - + hctx->proc->disabled_until = srv->cur_ts + 5; if (hctx->proc->is_local) { @@ -2690,17 +2698,17 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { } else { hctx->proc->state = PROC_STATE_DIED; } - + hctx->proc->state = PROC_STATE_DIED; - + 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 */ + /* go on with preparing the request */ hctx->state = FCGI_STATE_PREPARE_WRITE; } @@ -2713,14 +2721,14 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { /* do we have a running process for this host (max-procs) ? */ hctx->proc = NULL; - for (proc = hctx->host->first; - proc && proc->state != PROC_STATE_RUNNING; + for (proc = hctx->host->first; + proc && proc->state != PROC_STATE_RUNNING; proc = proc->next); - + /* all childs are dead */ if (proc == NULL) { hctx->fde_ndx = -1; - + return HANDLER_ERROR; } @@ -2733,50 +2741,50 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { } ret = host->unixsocket->used ? AF_UNIX : AF_INET; - + if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) { if (errno == EMFILE || errno == EINTR) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "wait for fd at connection:", con->fd); - + return HANDLER_WAIT_FOR_FD; } - - log_error_write(srv, __FILE__, __LINE__, "ssdd", + + log_error_write(srv, __FILE__, __LINE__, "ssdd", "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds); return HANDLER_ERROR; } hctx->fde_ndx = -1; - + srv->cur_fds++; - + fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx); - + if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno)); - + return HANDLER_ERROR; } - + if (hctx->proc->is_local) { hctx->pid = hctx->proc->pid; } - + 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 */ - log_error_write(srv, __FILE__, __LINE__, "ssdsd", + log_error_write(srv, __FILE__, __LINE__, "ssdsd", "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:", "reconnects:", hctx->reconnects, "load:", host->load); @@ -2789,7 +2797,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { buffer_append_string(p->statuskey, ".overloaded"); status_counter_inc(srv, CONST_BUF_LEN(p->statuskey)); - + return HANDLER_ERROR; case CONNECTION_DEAD: /* we got a hard error from the backend like @@ -2798,19 +2806,19 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { * * for check if the host is back in 5 seconds * */ - + hctx->proc->disabled_until = srv->cur_ts + 5; if (hctx->proc->is_local) { hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID; } else { hctx->proc->state = PROC_STATE_DIED; } - - log_error_write(srv, __FILE__, __LINE__, "ssdsd", + + log_error_write(srv, __FILE__, __LINE__, "ssdsd", "backend died, we disable it for a 5 seconds and send the request to another backend instead:", "reconnects:", hctx->reconnects, "load:", host->load); - + fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc); buffer_append_string(p->statuskey, ".died"); @@ -2821,19 +2829,19 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { /* 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")); @@ -2856,9 +2864,9 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ssdsbsd", - "got proc:", - "pid:", hctx->proc->pid, - "socket:", hctx->proc->connection_name, + "got proc:", + "pid:", hctx->proc->pid, + "socket:", hctx->proc->connection_name, "load:", hctx->proc->load); } @@ -2866,62 +2874,62 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { if (hctx->request_id == 0) { hctx->request_id = fcgi_requestid_new(srv, p); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "fcgi-request is already in use:", hctx->request_id); } - + /* fall through */ fcgi_create_env(srv, hctx, hctx->request_id); - + fcgi_set_state(srv, hctx, FCGI_STATE_WRITE); - + /* fall through */ case FCGI_STATE_WRITE: - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); + ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); chunkqueue_remove_finished_chunks(hctx->wb); - + if (ret < 0) { switch(errno) { case ENOTCONN: - /* the connection got dropped after accept() - * - * this is most of the time a PHP which dies + /* the connection got dropped after accept() + * + * this is most of the time a PHP which dies * after PHP_FCGI_MAX_REQUESTS - * - */ + * + */ if (hctx->wb->bytes_out == 0 && hctx->reconnects < 5) { - usleep(10000); /* take away the load of the webserver - * to let the php a chance to restart + usleep(10000); /* take away the load of the webserver + * to let the php a chance to restart */ - + fcgi_reconnect(srv, hctx); - + return HANDLER_WAIT_FOR_FD; } - + /* not reconnected ... why - * + * * far@#lighttpd report this for FreeBSD - * + * */ - - log_error_write(srv, __FILE__, __LINE__, "ssdsd", + + log_error_write(srv, __FILE__, __LINE__, "ssdsd", "[REPORT ME] connection was dropped after accept(). reconnect() denied:", "write-offset:", hctx->wb->bytes_out, "reconnect attempts:", hctx->reconnects); - + return HANDLER_ERROR; case EAGAIN: case EINTR: fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - + return HANDLER_WAIT_FOR_EVENT; default: - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno); - + return HANDLER_ERROR; } } @@ -2933,7 +2941,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { fcgi_set_state(srv, hctx, FCGI_STATE_READ); } else { fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - + return HANDLER_WAIT_FOR_EVENT; } @@ -2945,7 +2953,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); return HANDLER_ERROR; } - + return HANDLER_WAIT_FOR_EVENT; } @@ -2954,18 +2962,18 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) { * */ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { plugin_data *p = p_d; - + handler_ctx *hctx = con->plugin_ctx[p->id]; fcgi_proc *proc; fcgi_extension_host *host; - + if (NULL == hctx) return HANDLER_GO_ON; - + /* 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 + * -> 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; @@ -2974,23 +2982,23 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { /* 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 something */ 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; @@ -2998,16 +3006,16 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { } host = hctx->ext->hosts[ndx]; - - /* - * if check-local is disabled, use the uri.path handler - * + + /* + * if check-local is disabled, use the uri.path handler + * */ - + /* init handler-context */ hctx->host = host; - /* we put a connection on this host, move the other new connections to other hosts + /* we put a connection on this host, move the other new connections to other hosts * * as soon as hctx->host is unassigned, decrease the load again */ hctx->host->load++; @@ -3021,7 +3029,7 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { case HANDLER_ERROR: proc = hctx->proc; host = hctx->host; - + if (hctx->state == FCGI_STATE_INIT || hctx->state == FCGI_STATE_CONNECT_DELAYED) { if (proc) host->active_procs--; @@ -3036,7 +3044,7 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { return HANDLER_WAIT_FOR_FD; } else { fcgi_connection_close(srv, hctx); - + buffer_reset(con->physical.path); con->mode = DIRECT; con->http_status = 500; @@ -3046,12 +3054,12 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) { } } else { fcgi_connection_close(srv, hctx); - + buffer_reset(con->physical.path); con->mode = DIRECT; con->http_status = 503; joblist_append(srv, con); /* really ? */ - + return HANDLER_FINISHED; } case HANDLER_WAIT_FOR_EVENT: @@ -3073,7 +3081,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { handler_ctx *hctx = ctx; connection *con = hctx->remote_conn; plugin_data *p = hctx->plugin_data; - + fcgi_proc *proc = hctx->proc; fcgi_extension_host *host= hctx->host; @@ -3083,8 +3091,8 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { case 0: break; case 1: - - if (host->mode == FCGI_AUTHORIZER && + + if (host->mode == FCGI_AUTHORIZER && (con->http_status == 200 || con->http_status == 0)) { /* @@ -3094,26 +3102,26 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { */ buffer_copy_string_buffer(con->physical.doc_root, host->docroot); - + buffer_copy_string_buffer(con->physical.path, host->docroot); buffer_append_string_buffer(con->physical.path, con->uri.path); fcgi_connection_close(srv, hctx); - + con->mode = DIRECT; con->file_started = 1; /* fcgi_extension won't touch the request afterwards */ } else { /* we are done */ fcgi_connection_close(srv, hctx); } - + joblist_append(srv, con); return HANDLER_FINISHED; case -1: if (proc->pid && proc->state != PROC_STATE_DIED) { int status; - + /* only fetch the zombie if it is not already done */ - + switch(waitpid(proc->pid, &status, WNOHANG)) { case 0: /* child is still alive */ @@ -3123,60 +3131,60 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { default: /* the child should not terminate at all */ if (WIFEXITED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sdsd", + log_error_write(srv, __FILE__, __LINE__, "sdsd", "child exited, pid:", proc->pid, "status:", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", WTERMSIG(status)); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", status); } - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ssbsdsd", "--- fastcgi spawning", "\n\tsocket", proc->connection_name, "\n\tcurrent:", 1, "/", host->min_procs); } - + if (fcgi_spawn_connection(srv, p, host, proc)) { /* respawning failed, retry later */ proc->state = PROC_STATE_DIED; - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "respawning failed, will retry later"); } - + break; } } if (con->file_started == 0) { /* nothing has been send out yet, try to use another child */ - + if (hctx->wb->bytes_out == 0 && hctx->reconnects < 5) { fcgi_reconnect(srv, hctx); - - log_error_write(srv, __FILE__, __LINE__, "ssbsbs", + + log_error_write(srv, __FILE__, __LINE__, "ssbsbs", "response not received, request not sent", - "on socket:", proc->connection_name, + "on socket:", proc->connection_name, "for", con->uri.path, ", reconnecting"); - + return HANDLER_WAIT_FOR_FD; } - - log_error_write(srv, __FILE__, __LINE__, "sosbsbs", + + log_error_write(srv, __FILE__, __LINE__, "sosbsbs", "response not received, request sent:", hctx->wb->bytes_out, - "on socket:", proc->connection_name, + "on socket:", proc->connection_name, "for", con->uri.path, ", closing connection"); - + fcgi_connection_close(srv, hctx); - + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); buffer_reset(con->physical.path); con->http_status = 500; @@ -3184,76 +3192,76 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { } else { /* response might have been already started, kill the connection */ fcgi_connection_close(srv, hctx); - - log_error_write(srv, __FILE__, __LINE__, "ssbsbs", + + log_error_write(srv, __FILE__, __LINE__, "ssbsbs", "response already sent out, but backend returned error", - "on socket:", proc->connection_name, + "on socket:", proc->connection_name, "for", con->uri.path, ", terminating connection"); - + connection_set_state(srv, con, CON_STATE_ERROR); } /* */ - - + + joblist_append(srv, con); return HANDLER_FINISHED; } } - + if (revents & FDEVENT_OUT) { if (hctx->state == FCGI_STATE_CONNECT_DELAYED || hctx->state == FCGI_STATE_WRITE) { /* we are allowed to send something out - * + * * 1. in a unfinished connect() call * 2. in a unfinished write() call (long POST request) */ return mod_fastcgi_handle_subrequest(srv, con, p); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "got a FDEVENT_OUT and didn't know why:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "got a FDEVENT_OUT and didn't know why:", hctx->state); } } - + /* perhaps this issue is already handled */ if (revents & FDEVENT_HUP) { if (hctx->state == FCGI_STATE_CONNECT_DELAYED) { /* getoptsock will catch this one (right ?) - * - * if we are in connect we might get a EINPROGRESS - * in the first call and a FDEVENT_HUP in the + * + * if we are in connect we might get a EINPROGRESS + * in the first call and a FDEVENT_HUP in the * second round - * + * * FIXME: as it is a bit ugly. - * + * */ return mod_fastcgi_handle_subrequest(srv, con, p); } else if (hctx->state == FCGI_STATE_READ && hctx->proc->port == 0) { /* FIXME: - * + * * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket * even if the FCGI_FIN packet is not received yet */ } else { - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", - "error: unexpected close of fastcgi connection for", + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", + "error: unexpected close of fastcgi connection for", con->uri.path, - "(no fastcgi process on host:", + "(no fastcgi process on host:", host->host, - ", port: ", + ", port: ", host->port, " ?)", hctx->state); - + connection_set_state(srv, con, CON_STATE_ERROR); fcgi_connection_close(srv, hctx); joblist_append(srv, con); } } else if (revents & FDEVENT_ERR) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "fcgi: got a FDEVENT_ERR. Don't know why."); /* kill all connections to the fastcgi process */ @@ -3262,7 +3270,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { fcgi_connection_close(srv, hctx); joblist_append(srv, con); } - + return HANDLER_FINISHED; } #define PATCH(x) \ @@ -3270,23 +3278,23 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) { static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(exts); PATCH(debug); PATCH(ext_mapping); - + /* 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("fastcgi.server"))) { PATCH(exts); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) { @@ -3296,7 +3304,7 @@ static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) { } } } - + return 0; } #undef PATCH @@ -3309,16 +3317,16 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i 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 = uri_path_handler ? con->uri.path : con->physical.path; if (buffer_is_empty(fn)) return HANDLER_GO_ON; - + s_len = fn->used - 1; - + fcgi_patch_connection(srv, con, p); /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries @@ -3326,24 +3334,24 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i * fastcgi.map-extensions = ( ".php3" => ".php" ) * * fastcgi.server = ( ".php" => ... ) - * + * * */ /* check if extension-mapping matches */ for (k = 0; k < p->conf.ext_mapping->used; k++) { data_string *ds = (data_string *)p->conf.ext_mapping->data[k]; size_t ct_len; /* length of the config entry */ - + if (ds->key->used == 0) continue; - + ct_len = ds->key->used - 1; - + if (s_len < ct_len) continue; - + /* found a mapping */ if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) { /* check if we know the extension */ - + /* we can reuse k here */ for (k = 0; k < p->conf.exts->used; k++) { extension = p->conf.exts->exts[k]; @@ -3365,15 +3373,15 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i /* check if extension matches */ for (k = 0; k < p->conf.exts->used; k++) { size_t ct_len; /* length of the config entry */ - + extension = p->conf.exts->exts[k]; - + if (extension->key->used == 0) continue; - + ct_len = extension->key->used - 1; - + if (s_len < ct_len) continue; - + /* check extension in the form "/fcgi_pattern" */ if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { break; @@ -3399,10 +3407,10 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i continue; } - /* we found one host that is alive */ + /* we found one host that is alive */ break; } - + if (!host) { /* sorry, we don't have a server alive for this ext */ buffer_reset(con->physical.path); @@ -3417,72 +3425,72 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i "on", extension->key, "are down."); } - + return HANDLER_FINISHED; } /* a note about no handler is not sent yey */ extension->note_is_sent = 0; - /* - * if check-local is disabled, use the uri.path handler - * + /* + * 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->proc = NULL; hctx->ext = extension; - + 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", + log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi"); } - - /* the prefix is the SCRIPT_NAME, + + /* 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 */ - + /* 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'; } @@ -3490,19 +3498,19 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i } else { handler_ctx *hctx; hctx = handler_ctx_init(); - + hctx->remote_conn = con; hctx->plugin_data = p; hctx->proc = NULL; hctx->ext = extension; - + 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"); } @@ -3524,19 +3532,19 @@ static handler_t fcgi_check_extension_2(server *srv, connection *con, void *p_d) JOBLIST_FUNC(mod_fastcgi_handle_joblist) { plugin_data *p = p_d; handler_ctx *hctx = con->plugin_ctx[p->id]; - + if (hctx == NULL) return HANDLER_GO_ON; if (hctx->fd != -1) { switch (hctx->state) { case FCGI_STATE_READ: fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); - + break; case FCGI_STATE_CONNECT_DELAYED: case FCGI_STATE_WRITE: fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - + break; case FCGI_STATE_INIT: /* at reconnect */ @@ -3553,7 +3561,7 @@ JOBLIST_FUNC(mod_fastcgi_handle_joblist) { static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - + fcgi_connection_close(srv, con->plugin_ctx[p->id]); return HANDLER_GO_ON; @@ -3562,14 +3570,14 @@ static handler_t fcgi_connection_close_callback(server *srv, connection *con, vo TRIGGER_FUNC(mod_fastcgi_handle_trigger) { plugin_data *p = p_d; size_t i, j, n; - - + + /* perhaps we should kill a connect attempt after 10-15 seconds - * + * * currently we wait for the TCP timeout which is on Linux 180 seconds - * - * - * + * + * + * */ /* check all childs if they are still up */ @@ -3586,45 +3594,45 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { fcgi_extension *ex; ex = exts->exts[j]; - + for (n = 0; n < ex->used; n++) { - + fcgi_proc *proc; unsigned long sum_load = 0; fcgi_extension_host *host; - + host = ex->hosts[n]; - + fcgi_restart_dead_procs(srv, p, host); - + for (proc = host->first; proc; proc = proc->next) { sum_load += proc->load; } - + if (host->num_procs && host->num_procs < host->max_procs && (sum_load / host->num_procs) > host->max_load_per_proc) { /* overload, spawn new child */ if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "overload detected, spawning a new child"); } - + for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next); - + if (proc) { if (proc == host->unused_procs) host->unused_procs = proc->next; - + if (proc->next) proc->next->prev = NULL; - + host->max_id++; } else { proc = fastcgi_process_init(); proc->id = host->max_id++; } - + host->num_procs++; - + if (buffer_is_empty(host->unixsocket)) { proc->port = host->port + proc->id; } else { @@ -3632,13 +3640,13 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { buffer_append_string(proc->unixsocket, "-"); buffer_append_long(proc->unixsocket, proc->id); } - + if (fcgi_spawn_connection(srv, p, host, proc)) { log_error_write(srv, __FILE__, __LINE__, "s", "ERROR: spawning fcgi failed."); return HANDLER_ERROR; } - + proc->prev = NULL; proc->next = host->first; if (host->first) { @@ -3646,56 +3654,56 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { } host->first = proc; } - + for (proc = host->first; proc; proc = proc->next) { if (proc->load != 0) break; if (host->num_procs <= host->min_procs) break; if (proc->pid == 0) continue; - + if (srv->cur_ts - proc->last_used > host->idle_timeout) { /* a proc is idling for a long time now, * terminated it */ - + if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "ssbsd", - "idle-timeout reached, terminating child:", - "socket:", proc->connection_name, + log_error_write(srv, __FILE__, __LINE__, "ssbsd", + "idle-timeout reached, terminating child:", + "socket:", proc->connection_name, "pid", proc->pid); } - - + + if (proc->next) proc->next->prev = proc->prev; if (proc->prev) proc->prev->next = proc->next; - + if (proc->prev == NULL) host->first = proc->next; - + proc->prev = NULL; proc->next = host->unused_procs; - + if (host->unused_procs) host->unused_procs->prev = proc; host->unused_procs = proc; - + kill(proc->pid, SIGTERM); - + proc->state = PROC_STATE_KILLED; - - log_error_write(srv, __FILE__, __LINE__, "ssbsd", - "killed:", - "socket:", proc->connection_name, + + log_error_write(srv, __FILE__, __LINE__, "ssbsd", + "killed:", + "socket:", proc->connection_name, "pid", proc->pid); - + host->num_procs--; - + /* proc is now in unused, let the next second handle the next process */ break; - } + } } - + for (proc = host->unused_procs; proc; proc = proc->next) { int status; - + if (proc->pid == 0) continue; - + switch (waitpid(proc->pid, &status, WNOHANG)) { case 0: /* child still running after timeout, good */ @@ -3703,10 +3711,10 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { case -1: if (errno != EINTR) { /* no PID found ? should never happen */ - log_error_write(srv, __FILE__, __LINE__, "sddss", + log_error_write(srv, __FILE__, __LINE__, "sddss", "pid ", proc->pid, proc->state, "not found:", strerror(errno)); - + #if 0 if (errno == ECHILD) { /* someone else has cleaned up for us */ @@ -3720,19 +3728,19 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) { /* the child should not terminate at all */ if (WIFEXITED(status)) { if (proc->state != PROC_STATE_KILLED) { - log_error_write(srv, __FILE__, __LINE__, "sdb", - "child exited:", + log_error_write(srv, __FILE__, __LINE__, "sdb", + "child exited:", WEXITSTATUS(status), proc->connection_name); } } else if (WIFSIGNALED(status)) { if (WTERMSIG(status) != SIGTERM) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", WTERMSIG(status)); } } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", status); } proc->pid = 0; @@ -3762,8 +3770,8 @@ int mod_fastcgi_plugin_init(plugin *p) { p->handle_subrequest = mod_fastcgi_handle_subrequest; p->handle_joblist = mod_fastcgi_handle_joblist; p->handle_trigger = mod_fastcgi_handle_trigger; - + p->data = NULL; - + return 0; } diff --git a/src/mod_flv_streaming.c b/src/mod_flv_streaming.c index d1f467a..32f2369 100644 --- a/src/mod_flv_streaming.c +++ b/src/mod_flv_streaming.c @@ -23,35 +23,35 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *query_str; array *get_params; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_flv_streaming_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->query_str = buffer_init(); p->get_params = array_init(); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_flv_streaming_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { size_t i; @@ -59,19 +59,19 @@ FREE_FUNC(mod_flv_streaming_free) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + array_free(s->extensions); - + free(s); } free(p->config_storage); } - + buffer_free(p->query_str); array_free(p->get_params); - + free(p); - + return HANDLER_GO_ON; } @@ -80,31 +80,31 @@ FREE_FUNC(mod_flv_streaming_free) { SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->extensions = array_init(); - + cv[0].destination = s->extensions; - + 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; } @@ -113,27 +113,27 @@ SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) { static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(extensions); - + /* 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("flv-streaming.extensions"))) { PATCH(extensions); } } } - + return 0; } #undef PATCH @@ -142,21 +142,21 @@ static int split_get_params(array *get_params, buffer *qrystr) { size_t is_key = 1; size_t i; char *key = NULL, *val = NULL; - + key = qrystr->ptr; - + /* we need the \0 */ for (i = 0; i < qrystr->used; i++) { switch(qrystr->ptr[i]) { case '=': if (is_key) { val = qrystr->ptr + i + 1; - + qrystr->ptr[i] = '\0'; - + is_key = 0; } - + break; case '&': case '\0': /* fin symbol */ @@ -175,14 +175,14 @@ static int split_get_params(array *get_params, buffer *qrystr) { array_insert_unique(get_params, (data_unset *)ds); } - + key = qrystr->ptr + i + 1; val = NULL; is_key = 1; break; } } - + return 0; } @@ -190,29 +190,29 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) { plugin_data *p = p_d; int s_len; size_t k; - + UNUSED(srv); if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON; - + mod_flv_streaming_patch_connection(srv, con, p); s_len = con->physical.path->used - 1; - + for (k = 0; k < p->conf.extensions->used; k++) { data_string *ds = (data_string *)p->conf.extensions->data[k]; int ct_len = ds->value->used - 1; - + if (ct_len > s_len) continue; if (ds->value->used == 0) continue; - + if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) { data_string *get_param; stat_cache_entry *sce = NULL; buffer *b; int start; char *err = NULL; - /* if there is a start=[0-9]+ in the header use it as start, + /* if there is a start=[0-9]+ in the header use it as start, * otherwise send the full file */ array_reset(p->get_params); @@ -256,7 +256,7 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) { return HANDLER_FINISHED; } } - + /* not found */ return HANDLER_GO_ON; } @@ -266,13 +266,13 @@ URIHANDLER_FUNC(mod_flv_streaming_path_handler) { int mod_flv_streaming_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("flv_streaming"); - + p->init = mod_flv_streaming_init; p->handle_physical = mod_flv_streaming_path_handler; p->set_defaults = mod_flv_streaming_set_defaults; p->cleanup = mod_flv_streaming_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_indexfile.c b/src/mod_indexfile.c index 4a784c6..d167424 100644 --- a/src/mod_indexfile.c +++ b/src/mod_indexfile.c @@ -20,51 +20,51 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *tmp_buf; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_indexfile_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->tmp_buf = buffer_init(); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_indexfile_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + array_free(s->indexfiles); - + free(s); } free(p->config_storage); } - + buffer_free(p->tmp_buf); - + free(p); - + return HANDLER_GO_ON; } @@ -73,33 +73,33 @@ FREE_FUNC(mod_indexfile_free) { SETDEFAULTS_FUNC(mod_indexfile_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->indexfiles = array_init(); - + cv[0].destination = s->indexfiles; cv[1].destination = s->indexfiles; /* old name for [0] */ - + 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; } @@ -108,21 +108,21 @@ SETDEFAULTS_FUNC(mod_indexfile_set_defaults) { static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(indexfiles); - + /* 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("server.indexfiles"))) { PATCH(indexfiles); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) { @@ -130,7 +130,7 @@ static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_d } } } - + return 0; } #undef PATCH @@ -139,65 +139,65 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) { plugin_data *p = p_d; size_t k; stat_cache_entry *sce = NULL; - + if (con->uri.path->used == 0) return HANDLER_GO_ON; if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON; - + mod_indexfile_patch_connection(srv, con, p); - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile"); log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path); } - + /* indexfile */ for (k = 0; k < p->conf.indexfiles->used; k++) { data_string *ds = (data_string *)p->conf.indexfiles->data[k]; - + if (ds->value && ds->value->ptr[0] == '/') { - /* if the index-file starts with a prefix as use this file as + /* if the index-file starts with a prefix as use this file as * index-generator */ buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root); } else { buffer_copy_string_buffer(p->tmp_buf, con->physical.path); } buffer_append_string_buffer(p->tmp_buf, ds->value); - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) { if (errno == EACCES) { con->http_status = 403; buffer_reset(con->physical.path); - + return HANDLER_FINISHED; } - + if (errno != ENOENT && errno != ENOTDIR) { /* we have no idea what happend. let's tell the user so. */ - + con->http_status = 500; - + log_error_write(srv, __FILE__, __LINE__, "ssbsb", "file not found ... or so: ", strerror(errno), con->uri.path, "->", con->physical.path); - + buffer_reset(con->physical.path); - + return HANDLER_FINISHED; } continue; } - + /* rewrite uri.path to the real path (/ -> /index.php) */ buffer_append_string_buffer(con->uri.path, ds->value); buffer_copy_string_buffer(con->physical.path, p->tmp_buf); - + /* fce is already set up a few lines above */ - + return HANDLER_GO_ON; } - + /* not found */ return HANDLER_GO_ON; } @@ -207,13 +207,13 @@ URIHANDLER_FUNC(mod_indexfile_subrequest) { int mod_indexfile_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("indexfile"); - + p->init = mod_indexfile_init; p->handle_subrequest_start = mod_indexfile_subrequest; p->set_defaults = mod_indexfile_set_defaults; p->cleanup = mod_indexfile_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_magnet.c b/src/mod_magnet.c index a2f6185..4fd0795 100644 --- a/src/mod_magnet.c +++ b/src/mod_magnet.c @@ -14,6 +14,7 @@ #include "response.h" #include "stat_cache.h" #include "status_counter.h" +#include "etag.h" #ifdef HAVE_LUA_H #include <lua.h> @@ -34,36 +35,36 @@ typedef struct { typedef struct { PLUGIN_DATA; - + script_cache *cache; buffer *encode_buf; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_magnet_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->cache = script_cache_init(); p->encode_buf = buffer_init(); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_magnet_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { size_t i; @@ -71,20 +72,20 @@ FREE_FUNC(mod_magnet_free) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + array_free(s->url_raw); array_free(s->physical_path); - + free(s); } free(p->config_storage); } - + script_cache_free(p->cache); buffer_free(p->encode_buf); - + free(p); - + return HANDLER_GO_ON; } @@ -93,34 +94,34 @@ FREE_FUNC(mod_magnet_free) { SETDEFAULTS_FUNC(mod_magnet_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { MAGNET_CONFIG_RAW_URL, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { MAGNET_CONFIG_PHYSICAL_PATH, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->url_raw = array_init(); s->physical_path = array_init(); - + cv[0].destination = s->url_raw; cv[1].destination = s->physical_path; - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } } - + return HANDLER_GO_ON; } @@ -129,22 +130,22 @@ SETDEFAULTS_FUNC(mod_magnet_set_defaults) { static int mod_magnet_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(url_raw); PATCH(physical_path); - + /* skip the first, the global context */ for (i = 1; i < srv->config_context->used; i++) { data_config *dc = (data_config *)srv->config_context->data[i]; s = p->config_storage[i]; - + /* condition didn't match */ if (!config_check_cond(srv, con, dc)) continue; - + /* merge config */ for (j = 0; j < dc->value->used; j++) { data_unset *du = dc->value->data[j]; - + if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_RAW_URL))) { PATCH(url_raw); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(MAGNET_CONFIG_PHYSICAL_PATH))) { @@ -152,7 +153,7 @@ static int mod_magnet_patch_connection(server *srv, connection *con, plugin_data } } } - + return 0; } #undef PATCH @@ -166,12 +167,106 @@ static int magnet_print(lua_State *L) { srv = lua_touserdata(L, -1); lua_pop(L, 1); - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "(lua-print)", s); return 0; } +static int magnet_stat(lua_State *L) { + const char *s = luaL_checkstring(L, 1); + server *srv; + connection *con; + buffer sb; + stat_cache_entry *sce = NULL; + + lua_pushstring(L, "lighty.srv"); + lua_gettable(L, LUA_REGISTRYINDEX); + srv = lua_touserdata(L, -1); + lua_pop(L, 1); + + lua_pushstring(L, "lighty.con"); + lua_gettable(L, LUA_REGISTRYINDEX); + con = lua_touserdata(L, -1); + lua_pop(L, 1); + + sb.ptr = (char *)s; + sb.used = sb.size = strlen(s) + 1; + + if (HANDLER_GO_ON != stat_cache_get_entry(srv, con, &sb, &sce)) { + lua_pushnil(L); + + return 1; + } + + lua_newtable(L); + + lua_pushboolean(L, S_ISREG(sce->st.st_mode)); + lua_setfield(L, -2, "is_file"); + + lua_pushboolean(L, S_ISDIR(sce->st.st_mode)); + lua_setfield(L, -2, "is_dir"); + + lua_pushboolean(L, S_ISCHR(sce->st.st_mode)); + lua_setfield(L, -2, "is_char"); + + lua_pushboolean(L, S_ISBLK(sce->st.st_mode)); + lua_setfield(L, -2, "is_block"); + + lua_pushboolean(L, S_ISSOCK(sce->st.st_mode)); + lua_setfield(L, -2, "is_socket"); + + lua_pushboolean(L, S_ISLNK(sce->st.st_mode)); + lua_setfield(L, -2, "is_link"); + + lua_pushboolean(L, S_ISFIFO(sce->st.st_mode)); + lua_setfield(L, -2, "is_fifo"); + + lua_pushinteger(L, sce->st.st_mtime); + lua_setfield(L, -2, "st_mtime"); + + lua_pushinteger(L, sce->st.st_ctime); + lua_setfield(L, -2, "st_ctime"); + + lua_pushinteger(L, sce->st.st_atime); + lua_setfield(L, -2, "st_atime"); + + lua_pushinteger(L, sce->st.st_uid); + lua_setfield(L, -2, "st_uid"); + + lua_pushinteger(L, sce->st.st_gid); + lua_setfield(L, -2, "st_gid"); + + lua_pushinteger(L, sce->st.st_size); + lua_setfield(L, -2, "st_size"); + + lua_pushinteger(L, sce->st.st_ino); + lua_setfield(L, -2, "st_ino"); + + + if (!buffer_is_empty(sce->etag)) { + /* we have to mutate the etag */ + buffer *b = buffer_init(); + etag_mutate(b, sce->etag); + + lua_pushlstring(L, b->ptr, b->used - 1); + buffer_free(b); + } else { + lua_pushnil(L); + } + lua_setfield(L, -2, "etag"); + + if (!buffer_is_empty(sce->content_type)) { + lua_pushlstring(L, sce->content_type->ptr, sce->content_type->used - 1); + } else { + lua_pushnil(L); + } + lua_setfield(L, -2, "content-type"); + + return 1; +} + + static int magnet_atpanic(lua_State *L) { const char *s = luaL_checkstring(L, 1); server *srv; @@ -181,9 +276,9 @@ static int magnet_atpanic(lua_State *L) { srv = lua_touserdata(L, -1); lua_pop(L, 1); - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "(lua-atpanic)", s); - + longjmp(exceptionjmp, 1); } @@ -254,7 +349,7 @@ static int magnet_status_set(lua_State *L) { typedef struct { const char *name; - enum { + enum { MAGNET_ENV_UNSET, MAGNET_ENV_PHYICAL_PATH, @@ -269,6 +364,7 @@ typedef struct { MAGNET_ENV_REQUEST_METHOD, MAGNET_ENV_REQUEST_URI, + MAGNET_ENV_REQUEST_ORIG_URI, MAGNET_ENV_REQUEST_PROTOCOL } type; } magnet_env_t; @@ -290,14 +386,16 @@ static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *k { "request.method", MAGNET_ENV_REQUEST_METHOD }, { "request.uri", MAGNET_ENV_REQUEST_URI }, + { "request.orig-uri", MAGNET_ENV_REQUEST_ORIG_URI }, { "request.protocol", MAGNET_ENV_REQUEST_PROTOCOL }, - + { NULL, MAGNET_ENV_UNSET } }; + UNUSED(srv); /** - * map all internal variables to lua + * map all internal variables to lua * */ @@ -318,6 +416,7 @@ static buffer *magnet_env_get_buffer(server *srv, connection *con, const char *k case MAGNET_ENV_REQUEST_METHOD: break; case MAGNET_ENV_REQUEST_URI: dest = con->request.uri; break; + case MAGNET_ENV_REQUEST_ORIG_URI: dest = con->request.orig_uri; break; case MAGNET_ENV_REQUEST_PROTOCOL: break; case MAGNET_ENV_UNSET: break; @@ -385,6 +484,7 @@ static int magnet_env_set(lua_State *L) { static int magnet_copy_response_header(server *srv, connection *con, plugin_data *p, lua_State *L) { + UNUSED(p); /** * get the environment of the function */ @@ -414,7 +514,7 @@ static int magnet_copy_response_header(server *srv, connection *con, plugin_data lua_pop(L, 1); } - } + } lua_pop(L, 1); /* pop the header-table */ lua_pop(L, 1); /* pop the lighty-env */ @@ -424,15 +524,16 @@ static int magnet_copy_response_header(server *srv, connection *con, plugin_data } /** - * walk through the content array + * walk through the content array * - * content = { "<pre>", { file = "/content" } , "</pre>" } + * content = { "<pre>", { file = "/content" } , "</pre>" } * * header["Content-Type"] = "text/html" - * + * * return 200 */ static int magnet_attach_content(server *srv, connection *con, plugin_data *p, lua_State *L) { + UNUSED(p); /** * get the environment of the function */ @@ -489,7 +590,7 @@ static int magnet_attach_content(server *srv, connection *con, plugin_data *p, l if (len < off) { return luaL_error(L, "offset > length for '%s'", fn->ptr); } - + chunkqueue_append_file(con->write_queue, fn, off, len - off); } @@ -534,7 +635,7 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu L = script_cache_get_script(srv, con, p->cache, name); if (lua_isstring(L, -1)) { - log_error_write(srv, __FILE__, __LINE__, + log_error_write(srv, __FILE__, __LINE__, "sbss", "loading script", name, @@ -542,7 +643,7 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu lua_tostring(L, -1)); lua_pop(L, 1); - + assert(lua_gettop(L) == 0); /* only the function should be on the stack */ con->http_status = 500; @@ -550,25 +651,25 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu return HANDLER_FINISHED; } - lua_pushstring(L, "lighty.srv"); + lua_pushstring(L, "lighty.srv"); lua_pushlightuserdata(L, srv); lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = srv */ - lua_pushstring(L, "lighty.con"); + lua_pushstring(L, "lighty.con"); lua_pushlightuserdata(L, con); lua_settable(L, LUA_REGISTRYINDEX); /* registery[<id>] = con */ lua_atpanic(L, magnet_atpanic); /** - * we want to create empty environment for our script - * + * we want to create empty environment for our script + * * setmetatable({}, {__index = _G}) - * - * if a function, symbol is not defined in our env, __index will lookup + * + * if a function, symbol is not defined in our env, __index will lookup * in the global env. * - * all variables created in the script-env will be thrown + * all variables created in the script-env will be thrown * away at the end of the script run. */ lua_newtable(L); /* my empty environment aka {} (sp += 1) */ @@ -578,8 +679,8 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu lua_setfield(L, -2, "print"); /* -1 is the env we want to set(sp -= 1) */ /** - * lighty.request[] has the HTTP-request headers - * lighty.content[] is a table of string/file + * lighty.request[] has the HTTP-request headers + * lighty.content[] is a table of string/file * lighty.header[] is a array to set response headers */ @@ -588,25 +689,25 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu lua_newtable(L); /* {} (sp += 1) */ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ lua_pushcfunction(L, magnet_reqhdr_get); /* (sp += 1) */ - lua_setfield(L, -2, "__index"); /* (sp -= 1) */ + lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ lua_setfield(L, -2, "request"); /* content = {} (sp -= 1) */ lua_newtable(L); /* {} (sp += 1) */ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ lua_pushcfunction(L, magnet_env_get); /* (sp += 1) */ - lua_setfield(L, -2, "__index"); /* (sp -= 1) */ + lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_env_set); /* (sp += 1) */ - lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ + lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ lua_setfield(L, -2, "env"); /* content = {} (sp -= 1) */ lua_newtable(L); /* {} (sp += 1) */ lua_newtable(L); /* the meta-table for the request-table (sp += 1) */ lua_pushcfunction(L, magnet_status_get); /* (sp += 1) */ - lua_setfield(L, -2, "__index"); /* (sp -= 1) */ + lua_setfield(L, -2, "__index"); /* (sp -= 1) */ lua_pushcfunction(L, magnet_status_set); /* (sp += 1) */ - lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ + lua_setfield(L, -2, "__newindex"); /* (sp -= 1) */ lua_setmetatable(L, -2); /* tie the metatable to request (sp -= 1) */ lua_setfield(L, -2, "status"); /* content = {} (sp -= 1) */ @@ -620,19 +721,22 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu lua_pushinteger(L, MAGNET_RESTART_REQUEST); lua_setfield(L, -2, "RESTART_REQUEST"); + lua_pushcfunction(L, magnet_stat); /* (sp += 1) */ + lua_setfield(L, -2, "stat"); /* -1 is the env we want to set (sp -= 1) */ + lua_setfield(L, -2, "lighty"); /* lighty.* (sp -= 1) */ - + lua_newtable(L); /* the meta-table for the new env (sp += 1) */ lua_pushvalue(L, LUA_GLOBALSINDEX); /* (sp += 1) */ lua_setfield(L, -2, "__index"); /* { __index = _G } (sp -= 1) */ lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) (sp -= 1) */ - + lua_setfenv(L, -2); /* on the stack should be a modified env (sp -= 1) */ if (lua_pcall(L, 0, 1, 0)) { - log_error_write(srv, __FILE__, __LINE__, - "ss", + log_error_write(srv, __FILE__, __LINE__, + "ss", "lua_pcall():", lua_tostring(L, -1)); lua_pop(L, 1); /* remove the error-msg and the function copy from the stack */ @@ -658,7 +762,7 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu if (lua_return_value > 99) { con->http_status = lua_return_value; con->file_finished = 1; - + /* try { ...*/ if (0 == setjmp(exceptionjmp)) { magnet_attach_content(srv, con, p, L); @@ -666,7 +770,7 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu /* } catch () { */ con->http_status = 500; } - + assert(lua_gettop(L) == 1); /* only the function should be on the stack */ /* we are finished */ @@ -677,7 +781,7 @@ static handler_t magnet_attract(server *srv, connection *con, plugin_data *p, bu return HANDLER_COMEBACK; } else { assert(lua_gettop(L) == 1); /* only the function should be on the stack */ - + return HANDLER_GO_ON; } } @@ -696,7 +800,7 @@ static handler_t magnet_attract_array(server *srv, connection *con, plugin_data handler_t ret; if (buffer_is_empty(ds->value)) continue; - + ret = magnet_attract(srv, con, p, ds->value); if (ret != HANDLER_GO_ON) return ret; @@ -707,7 +811,7 @@ static handler_t magnet_attract_array(server *srv, connection *con, plugin_data URIHANDLER_FUNC(mod_magnet_uri_handler) { plugin_data *p = p_d; - + mod_magnet_patch_connection(srv, con, p); return magnet_attract_array(srv, con, p, p->conf.url_raw); @@ -715,7 +819,7 @@ URIHANDLER_FUNC(mod_magnet_uri_handler) { URIHANDLER_FUNC(mod_magnet_physical) { plugin_data *p = p_d; - + mod_magnet_patch_connection(srv, con, p); return magnet_attract_array(srv, con, p, p->conf.physical_path); @@ -727,20 +831,21 @@ URIHANDLER_FUNC(mod_magnet_physical) { int mod_magnet_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("magnet"); - + p->init = mod_magnet_init; p->handle_uri_clean = mod_magnet_uri_handler; p->handle_physical = mod_magnet_physical; p->set_defaults = mod_magnet_set_defaults; p->cleanup = mod_magnet_free; - + p->data = NULL; - + return 0; } #else int mod_magnet_plugin_init(plugin *p) { + UNUSED(p); return -1; } #endif diff --git a/src/mod_magnet_cache.c b/src/mod_magnet_cache.c index e2f5d84..3756bd1 100644 --- a/src/mod_magnet_cache.c +++ b/src/mod_magnet_cache.c @@ -34,7 +34,7 @@ void script_free(script *sc) { script_cache *script_cache_init() { script_cache *p; - + p = calloc(1, sizeof(*p)); return p; @@ -89,7 +89,7 @@ lua_State *script_cache_get_script(server *srv, connection *con, script_cache *c sc = NULL; } - /* if the script was script already loaded but either got changed or + /* if the script was script already loaded but either got changed or * failed to load last time */ if (sc == NULL) { sc = script_init(); @@ -103,7 +103,7 @@ lua_State *script_cache_get_script(server *srv, connection *con, script_cache *c } cache->ptr[cache->used++] = sc; - + buffer_copy_string_buffer(sc->name, name); sc->L = luaL_newstate(); diff --git a/src/mod_mysql_vhost.c b/src/mod_mysql_vhost.c index 524071e..a33eecb 100644 --- a/src/mod_mysql_vhost.c +++ b/src/mod_mysql_vhost.c @@ -21,12 +21,12 @@ #endif /* - * Plugin for lighttpd to use MySQL + * Plugin for lighttpd to use MySQL * for domain to directory lookups, * i.e virtual hosts (vhosts). - * - * Optionally sets fcgi_offset and fcgi_arg - * in preparation for fcgi.c to handle + * + * Optionally sets fcgi_offset and fcgi_arg + * in preparation for fcgi.c to handle * per-user fcgi chroot jails. * * /ada@riksnet.se 2004-12-06 @@ -35,15 +35,15 @@ #ifdef HAVE_MYSQL typedef struct { MYSQL *mysql; - + buffer *mydb; buffer *myuser; buffer *mypass; buffer *mysock; - + buffer *hostname; unsigned short port; - + buffer *mysql_pre; buffer *mysql_post; } plugin_config; @@ -51,12 +51,12 @@ typedef struct { /* global plugin data */ typedef struct { PLUGIN_DATA; - + buffer *tmp_buf; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* per connection plugin data */ @@ -70,7 +70,7 @@ typedef struct { /* init the plugin data */ INIT_FUNC(mod_mysql_vhost_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); p->tmp_buf = buffer_init(); @@ -83,22 +83,22 @@ SERVER_FUNC(mod_mysql_vhost_cleanup) { plugin_data *p = p_d; UNUSED(srv); - + #ifdef DEBUG - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "mod_mysql_vhost_cleanup", p ? "yes" : "NO"); #endif if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + mysql_close(s->mysql); - + buffer_free(s->mydb); buffer_free(s->myuser); buffer_free(s->mypass); @@ -106,13 +106,13 @@ SERVER_FUNC(mod_mysql_vhost_cleanup) { buffer_free(s->mysql_pre); buffer_free(s->mysql_post); buffer_free(s->hostname); - + free(s); } free(p->config_storage); } buffer_free(p->tmp_buf); - + free(p); return HANDLER_GO_ON; @@ -127,7 +127,7 @@ static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void UNUSED(srv); #ifdef DEBUG - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "mod_mysql_connection_data", c ? "old" : "NEW"); #endif @@ -150,10 +150,10 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) { UNUSED(srv); #ifdef DEBUG - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO"); #endif - + if (!c) return HANDLER_GO_ON; buffer_free(c->server_name); @@ -184,14 +184,14 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) { { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, { 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; buffer *sel; - - + + s = calloc(1, sizeof(plugin_config)); s->mydb = buffer_init(); s->myuser = buffer_init(); @@ -201,10 +201,10 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) { s->port = 0; /* default port for mysql */ sel = buffer_init(); s->mysql = NULL; - + s->mysql_pre = buffer_init(); s->mysql_post = buffer_init(); - + cv[0].destination = s->mydb; cv[1].destination = s->myuser; cv[2].destination = s->mypass; @@ -212,16 +212,16 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) { cv[4].destination = sel; cv[5].destination = s->hostname; cv[6].destination = &(s->port); - + p->config_storage[i] = s; - - if (config_insert_values_global(srv, + + if (config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) return HANDLER_ERROR; - + s->mysql_pre = buffer_init(); s->mysql_post = buffer_init(); - + if (sel->used && (qmark = index(sel->ptr, '?'))) { *qmark = '\0'; buffer_copy_string(s->mysql_pre, sel->ptr); @@ -229,35 +229,35 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) { } else { buffer_copy_string_buffer(s->mysql_pre, sel); } - + /* required: * - username - * - database - * + * - database + * * optional: * - password, default: empty * - socket, default: mysql default * - hostname, if set overrides socket * - port, default: 3306 */ - + /* all have to be set */ if (!(buffer_is_empty(s->myuser) || buffer_is_empty(s->mydb))) { int fd; - + if (NULL == (s->mysql = mysql_init(NULL))) { log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting..."); - + return HANDLER_ERROR; } #define FOO(x) (s->x->used ? s->x->ptr : NULL) - - if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass), + + if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass), FOO(mydb), s->port, FOO(mysock), 0)) { log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql)); - + return HANDLER_ERROR; } #undef FOO @@ -266,12 +266,12 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) { /* otherwise we cannot be sure that mysql is fd i-1 */ if (-1 == (fd = open("/dev/null", 0))) { close(fd); - fcntl(fd-1, F_SETFD, FD_CLOEXEC); + fcntl(fd-1, F_SETFD, FD_CLOEXEC); } } } - - + + return HANDLER_GO_ON; } @@ -281,36 +281,36 @@ SERVER_FUNC(mod_mysql_vhost_set_defaults) { static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(mysql_pre); PATCH(mysql_post); #ifdef HAVE_MYSQL PATCH(mysql); #endif - + /* 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("mysql-vhost.sql"))) { PATCH(mysql_pre); PATCH(mysql_post); } } - + if (s->mysql) { PATCH(mysql); } } - + return 0; } #undef PATCH @@ -379,7 +379,7 @@ CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) { /* fcgi_offset and fcgi_arg are optional */ if (cols > 1 && row[1]) { c->fcgi_offset = atoi(row[1]); - + if (cols > 2 && row[2]) { buffer_copy_string(c->fcgi_arg, row[2]); } else { @@ -395,12 +395,12 @@ GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name); buffer_copy_string_buffer(con->physical.doc_root, c->document_root); #ifdef DEBUG - log_error_write(srv, __FILE__, __LINE__, "sbbdb", - result ? "NOT CACHED" : "cached", + log_error_write(srv, __FILE__, __LINE__, "sbbdb", + result ? "NOT CACHED" : "cached", con->server_name, con->physical.doc_root, c->fcgi_offset, c->fcgi_arg); #endif - return HANDLER_GO_ON; + return HANDLER_GO_ON; ERR500: if (result) mysql_free_result(result); con->http_status = 500; /* Internal Error */ @@ -418,7 +418,7 @@ int mod_mysql_vhost_plugin_init(plugin *p) { p->set_defaults = mod_mysql_vhost_set_defaults; p->handle_docroot = mod_mysql_vhost_handle_docroot; - + return 0; } #else diff --git a/src/mod_proxy.c b/src/mod_proxy.c index 572de62..9a28f4f 100644 --- a/src/mod_proxy.c +++ b/src/mod_proxy.c @@ -38,16 +38,16 @@ #define PROXY_RETRY_TIMEOUT 60 /** - * - * the proxy module is based on the fastcgi module - * + * + * the proxy module is based on the fastcgi module + * * 28.06.2004 Jan Kneschke The first release * 01.07.2004 Evgeny Rodichev Several bugfixes and cleanups * - co-ordinate up- and downstream flows correctly (proxy_demux_response * and proxy_handle_fdevent) * - correctly transfer upstream http_response_status; * - some unused structures removed. - * + * * TODO: - delay upstream read if write_queue is too large * (to prevent memory eating, like in apache). Shoud be * configurable). @@ -70,22 +70,22 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *parse_response; buffer *balance_buf; - + plugin_config **config_storage; - + plugin_config conf; } plugin_data; -typedef enum { - PROXY_STATE_INIT, - PROXY_STATE_CONNECT, - PROXY_STATE_PREPARE_WRITE, - PROXY_STATE_WRITE, - PROXY_STATE_READ, - PROXY_STATE_ERROR +typedef enum { + PROXY_STATE_INIT, + PROXY_STATE_CONNECT, + PROXY_STATE_PREPARE_WRITE, + PROXY_STATE_WRITE, + PROXY_STATE_READ, + PROXY_STATE_ERROR } proxy_connection_state_t; enum { PROXY_STDOUT, PROXY_END_REQUEST }; @@ -93,19 +93,19 @@ enum { PROXY_STDOUT, PROXY_END_REQUEST }; typedef struct { proxy_connection_state_t state; time_t state_timestamp; - + data_proxy *host; - + buffer *response; buffer *response_header; chunkqueue *wb; - + int fd; /* fd to the proxy process */ int fde_ndx; /* index into the fd-event buffer */ size_t path_info_offset; /* start of path_info in uri.path */ - + connection *remote_conn; /* dump pointer */ plugin_data *plugin_data; /* dump pointer */ } handler_ctx; @@ -116,13 +116,13 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents); static handler_ctx * handler_ctx_init() { handler_ctx * hctx; - + hctx = calloc(1, sizeof(*hctx)); - + hctx->state = PROXY_STATE_INIT; hctx->host = NULL; - + hctx->response = buffer_init(); hctx->response_header = buffer_init(); @@ -130,7 +130,7 @@ static handler_ctx * handler_ctx_init() { hctx->fd = -1; hctx->fde_ndx = -1; - + return hctx; } @@ -138,47 +138,47 @@ static void handler_ctx_free(handler_ctx *hctx) { buffer_free(hctx->response); buffer_free(hctx->response_header); chunkqueue_free(hctx->wb); - + free(hctx); } INIT_FUNC(mod_proxy_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->parse_response = buffer_init(); p->balance_buf = buffer_init(); - + return p; } FREE_FUNC(mod_proxy_free) { plugin_data *p = p_d; - + UNUSED(srv); buffer_free(p->parse_response); buffer_free(p->balance_buf); - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; - + if (s) { - + array_free(s->extensions); - + free(s); } } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } @@ -186,37 +186,37 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) { plugin_data *p = p_d; data_unset *du; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { 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; array *ca; - + s = malloc(sizeof(plugin_config)); s->extensions = array_init(); s->debug = 0; - + cv[0].destination = s->extensions; cv[1].destination = &(s->debug); cv[2].destination = p->balance_buf; buffer_reset(p->balance_buf); - + p->config_storage[i] = s; ca = ((data_config *)srv->config_context->data[i])->value; - + if (0 != config_insert_values_global(srv, ca, cv)) { return HANDLER_ERROR; } - + if (buffer_is_empty(p->balance_buf)) { s->balance = PROXY_BALANCE_FAIR; } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) { @@ -226,7 +226,7 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) { } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) { s->balance = PROXY_BALANCE_HASH; } else { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf); return HANDLER_ERROR; } @@ -234,91 +234,91 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) { if (NULL != (du = array_get_element(ca, "proxy.server"))) { size_t j; data_array *da = (data_array *)du; - + if (du->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sss", + log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", "proxy.server", "array of strings"); - + return HANDLER_ERROR; } - - /* + + /* * proxy.server = ( "<ext>" => ..., * "<ext>" => ... ) */ - + for (j = 0; j < da->value->used; j++) { data_array *da_ext = (data_array *)da->value->data[j]; size_t n; - + if (da_ext->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sssbs", - "unexpected type for key: ", "proxy.server", + log_error_write(srv, __FILE__, __LINE__, "sssbs", + "unexpected type for key: ", "proxy.server", "[", da->value->data[j]->key, "](string)"); - + return HANDLER_ERROR; } - - /* - * proxy.server = ( "<ext>" => - * ( "<host>" => ( ... ), + + /* + * proxy.server = ( "<ext>" => + * ( "<host>" => ( ... ), * "<host>" => ( ... ) - * ), + * ), * "<ext>" => ... ) */ - + for (n = 0; n < da_ext->value->used; n++) { data_array *da_host = (data_array *)da_ext->value->data[n]; - + data_proxy *df; data_array *dfa; - - config_values_t pcv[] = { + + config_values_t pcv[] = { { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (da_host->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "ssSBS", - "unexpected type for key:", - "proxy.server", + log_error_write(srv, __FILE__, __LINE__, "ssSBS", + "unexpected type for key:", + "proxy.server", "[", da_ext->value->data[n]->key, "](string)"); - + return HANDLER_ERROR; } - + df = data_proxy_init(); - + df->port = 80; - + buffer_copy_string_buffer(df->key, da_host->key); - + pcv[0].destination = df->host; pcv[1].destination = &(df->port); - + if (0 != config_insert_values_internal(srv, da_host->value, pcv)) { return HANDLER_ERROR; } - + if (buffer_is_empty(df->host)) { - log_error_write(srv, __FILE__, __LINE__, "sbbbs", - "missing key (string):", + log_error_write(srv, __FILE__, __LINE__, "sbbbs", + "missing key (string):", da->key, da_ext->key, da_host->key, "host"); - + return HANDLER_ERROR; } - + /* if extension already exists, take it */ - + if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) { dfa = data_array_init(); - + buffer_copy_string_buffer(dfa->key, da_ext->key); - + array_insert_unique(dfa->value, (data_unset *)df); array_insert_unique(s->extensions, (data_unset *)dfa); } else { @@ -328,19 +328,19 @@ SETDEFAULTS_FUNC(mod_proxy_set_defaults) { } } } - + return HANDLER_GO_ON; } void proxy_connection_close(server *srv, handler_ctx *hctx) { plugin_data *p; connection *con; - + if (NULL == hctx) return; - + p = hctx->plugin_data; con = hctx->remote_conn; - + if (hctx->fd != -1) { fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); fdevent_unregister(srv->ev, hctx->fd); @@ -348,47 +348,47 @@ void proxy_connection_close(server *srv, handler_ctx *hctx) { close(hctx->fd); srv->cur_fds--; } - + handler_ctx_free(hctx); - con->plugin_ctx[p->id] = NULL; + con->plugin_ctx[p->id] = NULL; } static int proxy_establish_connection(server *srv, handler_ctx *hctx) { struct sockaddr *proxy_addr; struct sockaddr_in proxy_addr_in; socklen_t servlen; - + plugin_data *p = hctx->plugin_data; data_proxy *host= hctx->host; int proxy_fd = hctx->fd; - + memset(&proxy_addr, 0, sizeof(proxy_addr)); - + proxy_addr_in.sin_family = AF_INET; proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr); proxy_addr_in.sin_port = htons(host->port); servlen = sizeof(proxy_addr_in); - + proxy_addr = (struct sockaddr *) &proxy_addr_in; - + if (-1 == connect(proxy_fd, proxy_addr, servlen)) { if (errno == EINPROGRESS || errno == EALREADY) { if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "connect delayed:", proxy_fd); } - + return 1; } else { - - log_error_write(srv, __FILE__, __LINE__, "sdsd", + + log_error_write(srv, __FILE__, __LINE__, "sdsd", "connect failed:", proxy_fd, strerror(errno), errno); - + return -1; } } if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "connect succeeded: ", proxy_fd); } @@ -422,25 +422,25 @@ void proxy_append_header(connection *con, const char *key, const char *value) { static int proxy_create_env(server *srv, handler_ctx *hctx) { size_t i; - + connection *con = hctx->remote_conn; buffer *b; - + /* build header */ b = chunkqueue_get_append_buffer(hctx->wb); - + /* request line */ buffer_copy_string(b, get_http_method_name(con->request.http_method)); BUFFER_APPEND_STRING_CONST(b, " "); - + buffer_append_string_buffer(b, con->request.uri); 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))); - /* http_host is NOT is just a pointer to a buffer + /* http_host is NOT is just a pointer to a buffer * which is NULL if it is not set */ - if (con->request.http_host && + if (con->request.http_host && !buffer_is_empty(con->request.http_host)) { proxy_set_header(con, "X-Host", con->request.http_host->ptr); } @@ -449,24 +449,24 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) { /* request header */ for (i = 0; i < con->request.headers->used; i++) { data_string *ds; - + ds = (data_string *)con->request.headers->data[i]; - + if (ds->value->used && ds->key->used) { if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue; - + buffer_append_string_buffer(b, ds->key); BUFFER_APPEND_STRING_CONST(b, ": "); buffer_append_string_buffer(b, ds->value); BUFFER_APPEND_STRING_CONST(b, "\r\n"); } } - + BUFFER_APPEND_STRING_CONST(b, "\r\n"); - + hctx->wb->bytes_in += b->used - 1; /* body */ - + if (con->request.content_length) { chunkqueue *req_cq = con->request_content_queue; chunk *req_c; @@ -479,7 +479,7 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) { /* we announce toWrite octects * now take all the request_content chunk that we need to fill this request - * */ + * */ switch (req_c->type) { case FILE_CHUNK: @@ -507,26 +507,26 @@ static int proxy_create_env(server *srv, handler_ctx *hctx) { req_c->offset += weHave; req_cq->bytes_out += weHave; - + hctx->wb->bytes_in += weHave; break; default: break; } - + offset += weHave; } } - + return 0; } static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) { hctx->state = state; hctx->state_timestamp = srv->cur_ts; - + return 0; } @@ -534,19 +534,19 @@ static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_stat static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) { char *s, *ns; int http_response_status = -1; - + UNUSED(srv); /* \r\n -> \0\0 */ - + buffer_copy_string_buffer(p->parse_response, in); - + for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) { char *key, *value; int key_len; data_string *ds; int copy_header; - + ns[0] = '\0'; ns[1] = '\0'; @@ -566,7 +566,7 @@ static int proxy_response_parse(server *srv, connection *con, plugin_data *p, bu con->parsed_response |= HTTP_STATUS; continue; } - + if (NULL == (value = strchr(s, ':'))) { /* now we expect: "<key>: <value>\n" */ @@ -575,13 +575,13 @@ static int proxy_response_parse(server *srv, connection *con, plugin_data *p, bu key = s; key_len = value - key; - + value++; /* strip WS */ while (*value == ' ' || *value == '\t') value++; - + copy_header = 1; - + switch(key_len) { case 4: if (0 == strncasecmp(key, "Date", key_len)) { @@ -614,11 +614,11 @@ static int proxy_response_parse(server *srv, connection *con, plugin_data *p, bu } buffer_copy_string_len(ds->key, key, key_len); buffer_copy_string(ds->value, value); - + array_insert_unique(con->response.headers, (data_unset *)ds); } } - + return 0; } @@ -627,14 +627,14 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) { int fin = 0; int b; ssize_t r; - + plugin_data *p = hctx->plugin_data; connection *con = hctx->remote_conn; int proxy_fd = hctx->fd; - + /* check how much we have to read */ if (ioctl(hctx->fd, FIONREAD, &b)) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "ioctl failed: ", proxy_fd); return -1; @@ -654,22 +654,22 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) { } else { buffer_prepare_append(hctx->response, hctx->response->used + b); } - + if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) { - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "unexpected end-of-file (perhaps the proxy process died):", proxy_fd, strerror(errno)); return -1; } - + /* this should be catched by the b > 0 above */ assert(r); - + hctx->response->used += r; hctx->response->ptr[hctx->response->used - 1] = '\0'; #if 0 - log_error_write(srv, __FILE__, __LINE__, "sdsbs", + log_error_write(srv, __FILE__, __LINE__, "sdsbs", "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":"); #endif @@ -677,29 +677,29 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) { con->got_response = 1; buffer_prepare_copy(hctx->response_header, 128); } - + if (0 == con->file_started) { char *c; - + /* search for the \r\n\r\n in the string */ if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) { size_t hlen = c - hctx->response->ptr + 4; size_t blen = hctx->response->used - hlen - 1; /* found */ - + buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4); #if 0 log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header); #endif /* parse the response header */ proxy_response_parse(srv, con, p, hctx->response_header); - + /* enable chunked-transfer-encoding */ if (con->request.http_version == HTTP_VERSION_1_1 && !(con->parsed_response & HTTP_CONTENT_LENGTH)) { con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; } - + con->file_started = 1; if (blen) { http_chunk_append_mem(srv, con, c + 4, blen + 1); @@ -712,17 +712,17 @@ static int proxy_demux_response(server *srv, handler_ctx *hctx) { joblist_append(srv, con); hctx->response->used = 0; } - + } else { /* reading from upstream done */ con->file_finished = 1; - + http_chunk_append_mem(srv, con, NULL, 0); joblist_append(srv, con); - + fin = 1; } - + return fin; } @@ -731,12 +731,12 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { data_proxy *host= hctx->host; plugin_data *p = hctx->plugin_data; connection *con = hctx->remote_conn; - + int ret; - - if (!host || + + if (!host || (!host->host->used || !host->port)) return -1; - + switch(hctx->state) { case PROXY_STATE_INIT: if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) { @@ -744,19 +744,19 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { return HANDLER_ERROR; } hctx->fde_ndx = -1; - + srv->cur_fds++; - + fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx); - + if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) { log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); - + return HANDLER_ERROR; } - + /* fall through */ - + case PROXY_STATE_CONNECT: /* try to finish the connect() */ if (hctx->state == PROXY_STATE_INIT) { @@ -764,16 +764,16 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { switch (proxy_establish_connection(srv, hctx)) { case 1: proxy_set_state(srv, hctx, PROXY_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); - + return HANDLER_WAIT_FOR_EVENT; case -1: /* if ECONNREFUSED choose another connection -> FIXME */ hctx->fde_ndx = -1; - + return HANDLER_ERROR; default: /* everything is ok, go on */ @@ -782,39 +782,39 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { } else { int socket_error; socklen_t socket_error_len = sizeof(socket_error); - - /* we don't need it anymore */ + + /* we don't need it anymore */ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); /* 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", + log_error_write(srv, __FILE__, __LINE__, "ss", "getsockopt failed:", strerror(errno)); - + return HANDLER_ERROR; } if (socket_error != 0) { log_error_write(srv, __FILE__, __LINE__, "ss", - "establishing connection failed:", strerror(socket_error), + "establishing connection failed:", strerror(socket_error), "port:", hctx->host->port); - + return HANDLER_ERROR; } if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success"); + log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success"); } } - + proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE); /* fall through */ case PROXY_STATE_PREPARE_WRITE: proxy_create_env(srv, hctx); - + proxy_set_state(srv, hctx, PROXY_STATE_WRITE); - + /* fall through */ case PROXY_STATE_WRITE:; - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); + ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); chunkqueue_remove_finished_chunks(hctx->wb); @@ -822,7 +822,7 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { if (errno != EAGAIN && errno != EINTR) { log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno); - + return HANDLER_ERROR; } else { fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); @@ -838,10 +838,10 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); } else { fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - + return HANDLER_WAIT_FOR_EVENT; } - + return HANDLER_WAIT_FOR_EVENT; case PROXY_STATE_READ: /* waiting for a response */ @@ -850,7 +850,7 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); return HANDLER_ERROR; } - + return HANDLER_GO_ON; } @@ -859,23 +859,23 @@ static handler_t proxy_write_request(server *srv, handler_ctx *hctx) { static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(extensions); PATCH(debug); PATCH(balance); - + /* 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("proxy.server"))) { PATCH(extensions); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) { @@ -885,49 +885,49 @@ static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data } } } - + return 0; } #undef PATCH SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { plugin_data *p = p_d; - + handler_ctx *hctx = con->plugin_ctx[p->id]; data_proxy *host; - + if (NULL == hctx) return HANDLER_GO_ON; mod_proxy_patch_connection(srv, con, p); - + host = hctx->host; - + /* not my job */ if (con->mode != p->id) return HANDLER_GO_ON; - + /* ok, create the request */ switch(proxy_write_request(srv, hctx)) { case HANDLER_ERROR: - log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:", + log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:", host->host, host->port, hctx->fd); - + /* disable this server */ host->is_disabled = 1; host->disable_ts = srv->cur_ts; - + proxy_connection_close(srv, hctx); - - /* reset the enviroment and restart the sub-request */ + + /* reset the enviroment and restart the sub-request */ buffer_reset(con->physical.path); con->mode = DIRECT; joblist_append(srv, con); - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop - * and hope that the childs will be restarted - * + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop + * and hope that the childs will be restarted + * */ return HANDLER_WAIT_FOR_FD; @@ -938,7 +938,7 @@ SUBREQUEST_FUNC(mod_proxy_handle_subrequest) { default: break; } - + if (con->file_started == 1) { return HANDLER_FINISHED; } else { @@ -951,13 +951,13 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) { handler_ctx *hctx = ctx; connection *con = hctx->remote_conn; plugin_data *p = hctx->plugin_data; - - + + if ((revents & FDEVENT_IN) && hctx->state == PROXY_STATE_READ) { if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "proxy: fdevent-in", hctx->state); } @@ -966,10 +966,10 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) { break; case 1: hctx->host->usage--; - + /* we are done */ proxy_connection_close(srv, hctx); - + joblist_append(srv, con); return HANDLER_FINISHED; case -1: @@ -982,53 +982,53 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) { /* response might have been already started, kill the connection */ connection_set_state(srv, con, CON_STATE_ERROR); } - + joblist_append(srv, con); return HANDLER_FINISHED; } } - + if (revents & FDEVENT_OUT) { if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "proxy: fdevent-out", hctx->state); } if (hctx->state == PROXY_STATE_CONNECT || hctx->state == PROXY_STATE_WRITE) { /* we are allowed to send something out - * + * * 1. in a unfinished connect() call * 2. in a unfinished write() call (long POST request) */ return mod_proxy_handle_subrequest(srv, con, p); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "proxy: out", hctx->state); } } - + /* perhaps this issue is already handled */ if (revents & FDEVENT_HUP) { if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "proxy: fdevent-hup", hctx->state); } - + if (hctx->state == PROXY_STATE_CONNECT) { /* connect() -> EINPROGRESS -> HUP */ - + /** - * what is proxy is doing if it can't reach the next hop ? - * + * what is proxy is doing if it can't reach the next hop ? + * */ - + proxy_connection_close(srv, hctx); joblist_append(srv, con); - + con->http_status = 503; con->mode = DIRECT; - + return HANDLER_FINISHED; } @@ -1038,13 +1038,13 @@ static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) { joblist_append(srv, con); } else if (revents & FDEVENT_ERR) { /* kill all connections to the proxy process */ - + log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents); joblist_append(srv, con); proxy_connection_close(srv, hctx); } - + return HANDLER_FINISHED; } @@ -1058,44 +1058,44 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p buffer *fn; data_array *extension = NULL; size_t path_info_offset; - + /* Possibly, we processed already this request */ if (con->file_started == 1) return HANDLER_GO_ON; - + mod_proxy_patch_connection(srv, con, p); - + fn = con->uri.path; if (fn->used == 0) { return HANDLER_ERROR; } - + s_len = fn->used - 1; - - + + path_info_offset = 0; - if (p->conf.debug) { + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - start"); } /* check if extension matches */ for (k = 0; k < p->conf.extensions->used; k++) { size_t ct_len; - + extension = (data_array *)p->conf.extensions->data[k]; - + if (extension->key->used == 0) continue; - + ct_len = extension->key->used - 1; - + if (s_len < ct_len) continue; - + /* check extension in the form "/proxy_pattern" */ if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { if (s_len > ct_len + 1) { char *pi_offset; - + if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) { path_info_offset = pi_offset - fn->ptr; } @@ -1106,12 +1106,12 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p break; } } - + if (k == p->conf.extensions->used) { return HANDLER_GO_ON; } - if (p->conf.debug) { + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "s", "proxy - ext found"); } @@ -1120,7 +1120,7 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p /* hash balancing */ if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "proxy - used hash balancing, hosts:", extension->value->used); } @@ -1129,13 +1129,13 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p unsigned long cur_max; if (host->is_disabled) continue; - + cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) + generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */ generate_crc32c(CONST_BUF_LEN(con->uri.authority)); - + if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbbbd", + log_error_write(srv, __FILE__, __LINE__, "sbbbd", "proxy - election:", con->uri.path, host->host, @@ -1155,18 +1155,18 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p case PROXY_BALANCE_FAIR: /* fair balancing */ if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "proxy - used fair balancing"); } for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) { data_proxy *host = (data_proxy *)extension->value->data[k]; - + if (host->is_disabled) continue; if (host->usage < max_usage) { max_usage = host->usage; - + ndx = k; } } @@ -1175,16 +1175,16 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p case PROXY_BALANCE_RR: /* round robin */ if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "proxy - used round-robin balancing"); } /* just to be sure */ assert(extension->value->used < INT_MAX); - + for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) { data_proxy *host = (data_proxy *)extension->value->data[k]; - + if (host->is_disabled) continue; /* first usable ndx */ @@ -1200,7 +1200,7 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p break; } } - + /* didn't found a higher id, wrap to the start */ if (ndx != -1 && max_usage != INT_MAX) { ndx = max_usage; @@ -1210,33 +1210,33 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p default: break; } - + /* found a server */ if (ndx != -1) { data_proxy *host = (data_proxy *)extension->value->data[ndx]; - - /* - * if check-local is disabled, use the uri.path handler - * + + /* + * if check-local is disabled, use the uri.path handler + * */ - + /* init handler-context */ handler_ctx *hctx; hctx = handler_ctx_init(); - + hctx->path_info_offset = path_info_offset; hctx->remote_conn = con; hctx->plugin_data = p; hctx->host = host; - + con->plugin_ctx[p->id] = hctx; - + host->usage++; - + con->mode = p->id; - + if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbd", + log_error_write(srv, __FILE__, __LINE__, "sbd", "proxy - found a host", host->host, host->port); } @@ -1245,11 +1245,11 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p } else { /* no handler found */ con->http_status = 500; - - log_error_write(srv, __FILE__, __LINE__, "sb", - "no proxy-handler found for:", + + log_error_write(srv, __FILE__, __LINE__, "sb", + "no proxy-handler found for:", fn); - + return HANDLER_FINISHED; } return HANDLER_GO_ON; @@ -1257,7 +1257,7 @@ static handler_t mod_proxy_check_extension(server *srv, connection *con, void *p static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - + proxy_connection_close(srv, con->plugin_ctx[p->id]); return HANDLER_GO_ON; @@ -1276,11 +1276,11 @@ TRIGGER_FUNC(mod_proxy_trigger) { size_t i, n, k; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; - - if (!s) continue; + + if (!s) continue; /* get the extensions for all configs */ - + for (k = 0; k < s->extensions->used; k++) { data_array *extension = (data_array *)s->extensions->data[k]; @@ -1290,8 +1290,8 @@ TRIGGER_FUNC(mod_proxy_trigger) { if (!host->is_disabled || srv->cur_ts - host->disable_ts < 5) continue; - - log_error_write(srv, __FILE__, __LINE__, "sbd", + + log_error_write(srv, __FILE__, __LINE__, "sbd", "proxy - re-enabled:", host->host, host->port); @@ -1317,8 +1317,8 @@ int mod_proxy_plugin_init(plugin *p) { p->handle_uri_clean = mod_proxy_check_extension; p->handle_subrequest = mod_proxy_handle_subrequest; p->handle_trigger = mod_proxy_trigger; - + p->data = NULL; - + return 0; } diff --git a/src/mod_redirect.c b/src/mod_redirect.c index 079e756..7a4f3eb 100644 --- a/src/mod_redirect.c +++ b/src/mod_redirect.c @@ -22,35 +22,35 @@ typedef struct { PLUGIN_DATA; buffer *match_buf; buffer *location; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; INIT_FUNC(mod_redirect_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->match_buf = buffer_init(); p->location = buffer_init(); - + return p; } FREE_FUNC(mod_redirect_free) { plugin_data *p = p_d; - + 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]; - + pcre_keyvalue_buffer_free(s->redirect); - + free(s); } free(p->config_storage); @@ -59,9 +59,9 @@ FREE_FUNC(mod_redirect_free) { buffer_free(p->match_buf); buffer_free(p->location); - + free(p); - + return HANDLER_GO_ON; } @@ -69,97 +69,97 @@ SETDEFAULTS_FUNC(mod_redirect_set_defaults) { plugin_data *p = p_d; data_unset *du; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + /* 0 */ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; size_t j; array *ca; data_array *da = (data_array *)du; - + s = calloc(1, sizeof(plugin_config)); s->redirect = pcre_keyvalue_buffer_init(); - + cv[0].destination = s->redirect; - + p->config_storage[i] = s; ca = ((data_config *)srv->config_context->data[i])->value; - + if (0 != config_insert_values_global(srv, ca, cv)) { return HANDLER_ERROR; } - + if (NULL == (du = array_get_element(ca, "url.redirect"))) { /* no url.redirect defined */ continue; } - + if (du->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sss", + log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", "url.redirect", "array of strings"); - + return HANDLER_ERROR; } - + da = (data_array *)du; - + for (j = 0; j < da->value->used; j++) { if (da->value->data[j]->type != TYPE_STRING) { - log_error_write(srv, __FILE__, __LINE__, "sssbs", - "unexpected type for key: ", - "url.redirect", + log_error_write(srv, __FILE__, __LINE__, "sssbs", + "unexpected type for key: ", + "url.redirect", "[", da->value->data[j]->key, "](string)"); - + return HANDLER_ERROR; } - - if (0 != pcre_keyvalue_buffer_append(s->redirect, + + if (0 != pcre_keyvalue_buffer_append(s->redirect, ((data_string *)(da->value->data[j]))->key->ptr, ((data_string *)(da->value->data[j]))->value->ptr)) { - - log_error_write(srv, __FILE__, __LINE__, "sb", + + log_error_write(srv, __FILE__, __LINE__, "sb", "pcre-compile failed for", da->value->data[j]->key); } } } - + return HANDLER_GO_ON; } #ifdef HAVE_PCRE_H static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + p->conf.redirect = s->redirect; - + /* 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 (0 == strcmp(du->key->ptr, "url.redirect")) { p->conf.redirect = s->redirect; p->conf.context = dc; } } } - + return 0; } #endif @@ -168,17 +168,17 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_ plugin_data *p = p_data; size_t i; - /* + /* * REWRITE URL - * + * * e.g. redirect /base/ to /index.php?section=base - * + * */ - + mod_redirect_patch_connection(srv, con, p); - + buffer_copy_string_buffer(p->match_buf, con->request.uri); - + for (i = 0; i < p->conf.redirect->used; i++) { pcre *match; pcre_extra *extra; @@ -188,12 +188,12 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_ pcre_keyvalue *kv = p->conf.redirect->kv[i]; # define N 10 int ovec[N * 3]; - + match = kv->key; extra = kv->key_extra; pattern = kv->value->ptr; pattern_len = kv->value->used - 1; - + if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { log_error_write(srv, __FILE__, __LINE__, "sd", @@ -204,26 +204,26 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_ const char **list; size_t start, end; size_t k; - + /* it matched */ pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list); - + /* search for $[0-9] */ - + buffer_reset(p->location); - + start = 0; end = pattern_len; for (k = 0; k < pattern_len; k++) { if ((pattern[k] == '$' || pattern[k] == '%') && isdigit((unsigned char)pattern[k + 1])) { /* got one */ - + size_t num = pattern[k + 1] - '0'; - + end = k; - + buffer_append_string_len(p->location, pattern + start, end - start); - + if (pattern[k] == '$') { /* n is always > 0 */ if (num < (size_t)n) { @@ -232,32 +232,32 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_ } else { config_append_cond_match_buffer(con, p->conf.context, p->location, num); } - + k++; start = k + 1; - } + } } - + buffer_append_string_len(p->location, pattern + start, pattern_len - start); - + pcre_free(list); - + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location)); - + con->http_status = 301; con->file_finished = 1; - + return HANDLER_FINISHED; } } #undef N - + #else UNUSED(srv); UNUSED(con); UNUSED(p_data); #endif - + return HANDLER_GO_ON; } @@ -265,13 +265,13 @@ static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_ int mod_redirect_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("redirect"); - + p->init = mod_redirect_init; p->handle_uri_clean = mod_redirect_uri_handler; p->set_defaults = mod_redirect_set_defaults; p->cleanup = mod_redirect_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_rewrite.c b/src/mod_rewrite.c index ff152a9..4a9d3ea 100644 --- a/src/mod_rewrite.c +++ b/src/mod_rewrite.c @@ -16,15 +16,15 @@ typedef struct { #ifdef HAVE_PCRE_H pcre *key; #endif - + buffer *value; - + int once; } rewrite_rule; typedef struct { rewrite_rule **ptr; - + size_t used; size_t size; } rewrite_rule_buffer; @@ -42,20 +42,20 @@ typedef struct { typedef struct { PLUGIN_DATA; buffer *match_buf; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; static handler_ctx * handler_ctx_init() { handler_ctx * hctx; - + hctx = calloc(1, sizeof(*hctx)); - + hctx->state = REWRITE_STATE_UNSET; hctx->loops = 0; - + return hctx; } @@ -65,9 +65,9 @@ static void handler_ctx_free(handler_ctx *hctx) { rewrite_rule_buffer *rewrite_rule_buffer_init(void) { rewrite_rule_buffer *kvb; - + kvb = calloc(1, sizeof(*kvb)); - + return kvb; } @@ -76,40 +76,40 @@ int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *va size_t i; const char *errptr; int erroff; - + if (!key) return -1; if (kvb->size == 0) { kvb->size = 4; kvb->used = 0; - + kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr)); - + for(i = 0; i < kvb->size; i++) { kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr)); } } else if (kvb->used == kvb->size) { kvb->size += 4; - + kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr)); - + for(i = kvb->used; i < kvb->size; i++) { kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr)); } } - + if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr, 0, &errptr, &erroff, NULL))) { - + return -1; } - + kvb->ptr[kvb->used]->value = buffer_init(); buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value); kvb->ptr[kvb->used]->once = once; - + kvb->used++; - + return 0; #else UNUSED(kvb); @@ -130,140 +130,140 @@ void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) { if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value); free(kvb->ptr[i]); } - + if (kvb->ptr) free(kvb->ptr); #endif - + free(kvb); } INIT_FUNC(mod_rewrite_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->match_buf = buffer_init(); - + return p; } FREE_FUNC(mod_rewrite_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + buffer_free(p->match_buf); if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; rewrite_rule_buffer_free(s->rewrite); - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) { data_unset *du; - + if (NULL != (du = array_get_element(ca, option))) { data_array *da = (data_array *)du; size_t j; - + if (du->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sss", + log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", option, "array of strings"); - + return HANDLER_ERROR; } - + da = (data_array *)du; - + for (j = 0; j < da->value->used; j++) { if (da->value->data[j]->type != TYPE_STRING) { - log_error_write(srv, __FILE__, __LINE__, "sssbs", - "unexpected type for key: ", - option, + log_error_write(srv, __FILE__, __LINE__, "sssbs", + "unexpected type for key: ", + option, "[", da->value->data[j]->key, "](string)"); - + return HANDLER_ERROR; } - - if (0 != rewrite_rule_buffer_append(s->rewrite, + + if (0 != rewrite_rule_buffer_append(s->rewrite, ((data_string *)(da->value->data[j]))->key, ((data_string *)(da->value->data[j]))->value, once)) { #ifdef HAVE_PCRE_H - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "pcre-compile failed for", da->value->data[j]->key); #else - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "pcre support is missing, please install libpcre and the headers"); #endif } } } - + return 0; } SETDEFAULTS_FUNC(mod_rewrite_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "url.rewrite-repeat", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "url.rewrite-once", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ - - /* old names, still supported - * + + /* old names, still supported + * * url.rewrite remapped to url.rewrite-once * url.rewrite-final is url.rewrite-once - * + * */ { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + /* 0 */ p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; array *ca; - + s = calloc(1, sizeof(plugin_config)); s->rewrite = rewrite_rule_buffer_init(); - + cv[0].destination = s->rewrite; cv[1].destination = s->rewrite; cv[2].destination = s->rewrite; - + p->config_storage[i] = s; ca = ((data_config *)srv->config_context->data[i])->value; - + if (0 != config_insert_values_global(srv, ca, cv)) { return HANDLER_ERROR; } - + parse_config_entry(srv, s, ca, "url.rewrite-once", 1); parse_config_entry(srv, s, ca, "url.rewrite-final", 1); parse_config_entry(srv, s, ca, "url.rewrite", 1); parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0); } - + return HANDLER_GO_ON; } #ifdef HAVE_PCRE_H @@ -271,21 +271,21 @@ static int mod_rewrite_patch_connection(server *srv, connection *con, plugin_dat size_t i, j; plugin_config *s = p->config_storage[0]; p->conf.rewrite = s->rewrite; - + /* 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]; - + if (COMP_HTTP_URL == dc->comp) continue; - + /* 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("url.rewrite"))) { p->conf.rewrite = s->rewrite; p->conf.context = dc; @@ -301,20 +301,20 @@ static int mod_rewrite_patch_connection(server *srv, connection *con, plugin_dat } } } - + return 0; } #endif URIHANDLER_FUNC(mod_rewrite_con_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; } @@ -324,32 +324,32 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) { size_t i; handler_ctx *hctx; - /* + /* * REWRITE URL - * + * * e.g. rewrite /base/ to /index.php?section=base - * + * */ - + if (con->plugin_ctx[p->id]) { hctx = con->plugin_ctx[p->id]; - + if (hctx->loops++ > 100) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat"); - + return HANDLER_ERROR; } - + if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON; } - + mod_rewrite_patch_connection(srv, con, p); if (!p->conf.rewrite) return HANDLER_GO_ON; - + buffer_copy_string_buffer(p->match_buf, con->request.uri); - + for (i = 0; i < p->conf.rewrite->used; i++) { pcre *match; const char *pattern; @@ -358,11 +358,11 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) { rewrite_rule *rule = p->conf.rewrite->ptr[i]; # define N 10 int ovec[N * 3]; - + match = rule->key; pattern = rule->value->ptr; pattern_len = rule->value->used - 1; - + if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { log_error_write(srv, __FILE__, __LINE__, "sd", @@ -373,26 +373,26 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) { const char **list; size_t start, end; size_t k; - + /* it matched */ pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list); - + /* search for $[0-9] */ - + buffer_reset(con->request.uri); - + start = 0; end = pattern_len; for (k = 0; k < pattern_len; k++) { if ((pattern[k] == '$' || pattern[k] == '%') && isdigit((unsigned char)pattern[k + 1])) { /* got one */ - + size_t num = pattern[k + 1] - '0'; - + end = k; - + buffer_append_string_len(con->request.uri, pattern + start, end - start); - + if (pattern[k] == '$') { /* n is always > 0 */ if (num < (size_t)n) { @@ -401,27 +401,27 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) { } else { config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num); } - + k++; start = k + 1; - } + } } - + buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start); - + pcre_free(list); - + hctx = handler_ctx_init(); - + con->plugin_ctx[p->id] = hctx; - + if (rule->once) hctx->state = REWRITE_STATE_FINISHED; - + return HANDLER_COMEBACK; } } #undef N - + #else UNUSED(srv); UNUSED(con); @@ -434,17 +434,17 @@ URIHANDLER_FUNC(mod_rewrite_uri_handler) { int mod_rewrite_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("rewrite"); - + p->init = mod_rewrite_init; /* it has to stay _raw as we are matching on uri + querystring */ - + p->handle_uri_raw = mod_rewrite_uri_handler; p->set_defaults = mod_rewrite_set_defaults; p->cleanup = mod_rewrite_free; p->connection_reset = mod_rewrite_con_reset; - + p->data = NULL; - + return 0; } diff --git a/src/mod_rrdtool.c b/src/mod_rrdtool.c index c7b897a..28003c4 100644 --- a/src/mod_rrdtool.c +++ b/src/mod_rrdtool.c @@ -23,7 +23,7 @@ typedef struct { buffer *path_rrdtool_bin; buffer *path_rrd; - + double requests, *requests_ptr; double bytes_written, *bytes_written_ptr; double bytes_read, *bytes_read_ptr; @@ -31,84 +31,84 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *cmd; buffer *resp; - + int read_fd, write_fd; pid_t rrdtool_pid; - + int rrdtool_running; - + plugin_config **config_storage; plugin_config conf; } plugin_data; INIT_FUNC(mod_rrd_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->resp = buffer_init(); p->cmd = buffer_init(); - + return p; } FREE_FUNC(mod_rrd_free) { plugin_data *p = p_d; size_t i; - + if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; - + buffer_free(s->path_rrdtool_bin); buffer_free(s->path_rrd); - + free(s); } } buffer_free(p->cmd); buffer_free(p->resp); - + free(p->config_storage); - + if (p->rrdtool_pid) { int status; close(p->read_fd); close(p->write_fd); -#ifdef HAVE_FORK +#ifdef HAVE_FORK /* collect status */ waitpid(p->rrdtool_pid, &status, 0); #endif } - + free(p); - + return HANDLER_GO_ON; } int mod_rrd_create_pipe(server *srv, plugin_data *p) { pid_t pid; - + int to_rrdtool_fds[2]; int from_rrdtool_fds[2]; -#ifdef HAVE_FORK +#ifdef HAVE_FORK if (pipe(to_rrdtool_fds)) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno)); return -1; } - + if (pipe(from_rrdtool_fds)) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno)); return -1; } - + /* fork, execve */ switch (pid = fork()) { case 0: { @@ -117,33 +117,33 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { int argc; int i = 0; char *dash = "-"; - + /* move stdout to from_rrdtool_fd[1] */ close(STDOUT_FILENO); dup2(from_rrdtool_fds[1], STDOUT_FILENO); close(from_rrdtool_fds[1]); /* not needed */ close(from_rrdtool_fds[0]); - + /* move the stdin to to_rrdtool_fd[0] */ close(STDIN_FILENO); dup2(to_rrdtool_fds[0], STDIN_FILENO); close(to_rrdtool_fds[0]); /* not needed */ close(to_rrdtool_fds[1]); - + close(STDERR_FILENO); - + if (srv->errorlog_mode == ERRORLOG_FILE) { dup2(srv->errorlog_fd, STDERR_FILENO); close(srv->errorlog_fd); } - + /* set up args */ argc = 3; args = malloc(sizeof(*args) * argc); i = 0; - + args[i++] = p->conf.path_rrdtool_bin->ptr; args[i++] = dash; args[i++] = NULL; @@ -152,12 +152,12 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { for (i = 3; i < 256; i++) { close(i); } - + /* exec the cgi */ execv(args[0], args); - + log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]); - + /* */ SEGFAULT(); break; @@ -168,19 +168,19 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { break; default: { /* father */ - + close(from_rrdtool_fds[1]); close(to_rrdtool_fds[0]); - + /* register PID and wait for them asyncronously */ p->write_fd = to_rrdtool_fds[1]; p->read_fd = from_rrdtool_fds[0]; p->rrdtool_pid = pid; - + break; } } - + return 0; #else return -1; @@ -189,19 +189,19 @@ int mod_rrd_create_pipe(server *srv, plugin_data *p) { static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) { struct stat st; - + /* check if DB already exists */ if (0 == stat(s->path_rrd->ptr, &st)) { /* check if it is plain file */ if (!S_ISREG(st.st_mode)) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "not a regular file:", s->path_rrd); return HANDLER_ERROR; } } else { int r ; /* create a new one */ - + BUFFER_COPY_STRING_CONST(p->cmd, "create "); buffer_append_string_buffer(p->cmd, s->path_rrd); buffer_append_string(p->cmd, " --step 60 "); @@ -220,33 +220,33 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 "); buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 "); buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n"); - + if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "rrdtool-write: failed", strerror(errno)); - + return HANDLER_ERROR; } - + buffer_prepare_copy(p->resp, 4096); if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "rrdtool-read: failed", strerror(errno)); - + return HANDLER_ERROR; } - + p->resp->used = r; - + if (p->resp->ptr[0] != 'O' || p->resp->ptr[1] != 'K') { - log_error_write(srv, __FILE__, __LINE__, "sbb", + log_error_write(srv, __FILE__, __LINE__, "sbb", "rrdtool-response:", p->cmd, p->resp); - + return HANDLER_ERROR; } } - + return HANDLER_GO_ON; } @@ -255,37 +255,37 @@ static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(path_rrdtool_bin); PATCH(path_rrd); - + p->conf.bytes_written_ptr = &(s->bytes_written); p->conf.bytes_read_ptr = &(s->bytes_read); p->conf.requests_ptr = &(s->requests); - + /* 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("rrdtool.db-name"))) { PATCH(path_rrd); /* get pointers to double values */ - + p->conf.bytes_written_ptr = &(s->bytes_written); p->conf.bytes_read_ptr = &(s->bytes_read); p->conf.requests_ptr = &(s->requests); } } } - + return 0; } #undef PATCH @@ -293,85 +293,85 @@ static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p SETDEFAULTS_FUNC(mod_rrd_set_defaults) { plugin_data *p = p_d; size_t i; - - config_values_t cv[] = { + + config_values_t cv[] = { { "rrdtool.binary", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, { "rrdtool.db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->path_rrdtool_bin = buffer_init(); s->path_rrd = buffer_init(); s->requests = 0; s->bytes_written = 0; s->bytes_read = 0; - + cv[0].destination = s->path_rrdtool_bin; cv[1].destination = s->path_rrd; - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } - + if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) { /* path_rrdtool_bin is a global option */ - - log_error_write(srv, __FILE__, __LINE__, "s", + + log_error_write(srv, __FILE__, __LINE__, "s", "rrdtool.binary can only be set as a global option."); - + return HANDLER_ERROR; } - + } - + p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin; p->rrdtool_running = 0; - + /* check for dir */ - + if (buffer_is_empty(p->conf.path_rrdtool_bin)) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "rrdtool.binary has to be set"); return HANDLER_ERROR; } - + /* open the pipe to rrdtool */ if (mod_rrd_create_pipe(srv, p)) { return HANDLER_ERROR; } - + p->rrdtool_running = 1; - + return HANDLER_GO_ON; } TRIGGER_FUNC(mod_rrd_trigger) { plugin_data *p = p_d; size_t i; - + if (!p->rrdtool_running) return HANDLER_GO_ON; if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON; - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; int r; - + if (buffer_is_empty(s->path_rrd)) continue; - + /* write the data down every minute */ - + if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR; - + BUFFER_COPY_STRING_CONST(p->cmd, "update "); buffer_append_string_buffer(p->cmd, s->path_rrd); BUFFER_APPEND_STRING_CONST(p->cmd, " N:"); @@ -381,69 +381,69 @@ TRIGGER_FUNC(mod_rrd_trigger) { BUFFER_APPEND_STRING_CONST(p->cmd, ":"); buffer_append_long(p->cmd, s->requests); BUFFER_APPEND_STRING_CONST(p->cmd, "\n"); - + if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) { p->rrdtool_running = 0; - - log_error_write(srv, __FILE__, __LINE__, "ss", + + log_error_write(srv, __FILE__, __LINE__, "ss", "rrdtool-write: failed", strerror(errno)); - + return HANDLER_ERROR; } - + buffer_prepare_copy(p->resp, 4096); if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) { p->rrdtool_running = 0; - - log_error_write(srv, __FILE__, __LINE__, "ss", + + log_error_write(srv, __FILE__, __LINE__, "ss", "rrdtool-read: failed", strerror(errno)); - + return HANDLER_ERROR; } - + p->resp->used = r; - + if (p->resp->ptr[0] != 'O' || p->resp->ptr[1] != 'K') { p->rrdtool_running = 0; - - log_error_write(srv, __FILE__, __LINE__, "sbb", + + log_error_write(srv, __FILE__, __LINE__, "sbb", "rrdtool-response:", p->cmd, p->resp); - + return HANDLER_ERROR; } s->requests = 0; s->bytes_written = 0; s->bytes_read = 0; } - + return HANDLER_GO_ON; } REQUESTDONE_FUNC(mod_rrd_account) { plugin_data *p = p_d; - + mod_rrd_patch_connection(srv, con, p); - + *(p->conf.requests_ptr) += 1; *(p->conf.bytes_written_ptr) += con->bytes_written; *(p->conf.bytes_read_ptr) += con->bytes_read; - + return HANDLER_GO_ON; } int mod_rrdtool_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("rrd"); - + p->init = mod_rrd_init; p->cleanup = mod_rrd_free; p->set_defaults= mod_rrd_set_defaults; - + p->handle_trigger = mod_rrd_trigger; p->handle_request_done = mod_rrd_account; - + p->data = NULL; - + return 0; } diff --git a/src/mod_scgi.c b/src/mod_scgi.c index 88c80eb..2db0308 100644 --- a/src/mod_scgi.c +++ b/src/mod_scgi.c @@ -46,19 +46,19 @@ enum {EOL_UNSET, EOL_N, EOL_RN}; /* - * + * * TODO: - * + * * - add timeout for a connect to a non-scgi process * (use state_timestamp + state) - * + * */ typedef struct scgi_proc { size_t id; /* id will be between 1 and max_procs */ buffer *socket; /* config.socket + "-" + id */ unsigned port; /* config.port + pno */ - + pid_t pid; /* PID of the spawned process (0 if not spawned locally) */ @@ -67,9 +67,9 @@ typedef struct scgi_proc { time_t last_used; /* see idle_timeout */ size_t requests; /* see max_requests */ struct scgi_proc *prev, *next; /* see first */ - + time_t disable_ts; /* replace by host->something */ - + int is_local; enum { PROC_STATE_UNSET, /* init-phase */ @@ -78,7 +78,7 @@ typedef struct scgi_proc { 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; + } state; } scgi_proc; typedef struct { @@ -86,20 +86,20 @@ typedef struct { * sorted by lowest load * * whenever a job is done move it up in the list - * until it is sorted, move it down as soon as the + * until it is sorted, move it down as soon as the * job is started */ - scgi_proc *first; - scgi_proc *unused_procs; + scgi_proc *first; + scgi_proc *unused_procs; - /* + /* * spawn at least min_procs, at max_procs. * - * as soon as the load of the first entry + * as soon as the load of the first entry * is max_load_per_proc we spawn a new one - * and add it to the first entry and give it + * and add it to the first entry and give it * the load - * + * */ unsigned short min_procs; @@ -111,44 +111,44 @@ typedef struct { /* * kick the process from the list if it was not - * used for idle_timeout until min_procs is + * used for idle_timeout until min_procs is * reached. this helps to get the processlist * small again we had a small peak load. * */ - + unsigned short idle_timeout; - + /* * time after a disabled remote connection is tried to be re-enabled - * - * + * + * */ - + unsigned short disable_time; /* * same scgi processes get a little bit larger - * than wanted. max_requests_per_proc kills a + * than wanted. max_requests_per_proc kills a * process after a number of handled requests. * */ size_t max_requests_per_proc; - + /* config */ - /* - * host:port + /* + * host:port * - * if host is one of the local IP adresses the + * if host is one of the local IP adresses the * whole connection is local * * if tcp/ip should be used host AND port have - * to be specified - * - */ - buffer *host; + * to be specified + * + */ + buffer *host; unsigned short port; /* @@ -161,7 +161,7 @@ typedef struct { */ buffer *unixsocket; - /* if socket is local we can start the scgi + /* if socket is local we can start the scgi * process ourself * * bin-path is the path to the binary @@ -169,19 +169,19 @@ typedef struct { * check min_procs and max_procs for the number * of process to start-up */ - buffer *bin_path; - - /* bin-path is set bin-environment is taken to + buffer *bin_path; + + /* bin-path is set bin-environment is taken to * create the environement before starting the * FastCGI process - * + * */ array *bin_env; - + array *bin_env_copy; - + /* - * docroot-translation between URL->phys and the + * docroot-translation between URL->phys and the * remote host * * reasons: @@ -192,7 +192,7 @@ typedef struct { buffer *docroot; /* - * check_local tell you if the phys file is stat()ed + * check_local tell you if the phys file is stat()ed * or not. FastCGI doesn't care if the service is * remote. If the web-server side doesn't contain * the scgi-files we should not stat() for them @@ -202,33 +202,33 @@ typedef struct { /* * append PATH_INFO to SCRIPT_FILENAME - * + * * php needs this if cgi.fix_pathinfo is provied - * + * */ - + ssize_t load; /* replace by host->load */ size_t max_id; /* corresponds most of the time to num_procs. - + only if a process is killed max_id waits for the process itself to die and decrements its afterwards */ } scgi_extension_host; /* * one extension can have multiple hosts assigned - * one host can spawn additional processes on the same + * one host can spawn additional processes on the same * socket (if we control it) * * ext -> host -> procs * 1:n 1:n * - * if the scgi process is remote that whole goes down + * if the scgi process is remote that whole goes down * to * * ext -> host -> procs - * 1:n 1:1 + * 1:n 1:1 * * in case of PHP and FCGI_CHILDREN we have again a procs * but we don't control it directly. @@ -239,7 +239,7 @@ typedef struct { buffer *key; /* like .php */ scgi_extension_host **hosts; - + size_t used; size_t size; } scgi_extension; @@ -253,14 +253,14 @@ typedef struct { typedef struct { - scgi_exts *exts; - + scgi_exts *exts; + int debug; } plugin_config; typedef struct { char **ptr; - + size_t size; size_t used; } char_array; @@ -268,52 +268,52 @@ typedef struct { /* generic plugin data, shared between all connections */ typedef struct { PLUGIN_DATA; - + buffer *scgi_env; - + buffer *path; buffer *parse_response; - + plugin_config **config_storage; - + plugin_config conf; /* this is only used as long as no handler_ctx is setup */ } 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_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE, + FCGI_STATE_WRITE, FCGI_STATE_READ } scgi_connection_state_t; typedef struct { - buffer *response; + buffer *response; size_t response_len; int response_type; int response_padding; - + scgi_proc *proc; scgi_extension_host *host; - + scgi_connection_state_t state; time_t state_timestamp; - + int reconnects; /* number of reconnect attempts */ - + read_buffer *rb; chunkqueue *wb; - + buffer *response_header; - + int delayed; /* flag to mark that the connect() is delayed */ - + size_t request_id; int fd; /* fd to the scgi process */ int fde_ndx; /* index into the fd-event buffer */ pid_t pid; int got_proc; - + plugin_config conf; - + connection *remote_conn; /* dumb pointer */ plugin_data *plugin_data; /* dumb pointer */ } handler_ctx; @@ -328,28 +328,28 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p static handler_ctx * handler_ctx_init() { handler_ctx * hctx; - + hctx = calloc(1, sizeof(*hctx)); assert(hctx); - + hctx->fde_ndx = -1; - + hctx->response = buffer_init(); hctx->response_header = buffer_init(); - + hctx->request_id = 0; hctx->state = FCGI_STATE_INIT; hctx->proc = NULL; - + hctx->response_len = 0; hctx->response_type = 0; hctx->response_padding = 0; hctx->fd = -1; - + hctx->reconnects = 0; hctx->wb = chunkqueue_init(); - + return hctx; } @@ -358,12 +358,12 @@ static void handler_ctx_free(handler_ctx *hctx) { buffer_free(hctx->response_header); chunkqueue_free(hctx->wb); - + if (hctx->rb) { if (hctx->rb->ptr) free(hctx->rb->ptr); free(hctx->rb); } - + free(hctx); } @@ -372,20 +372,20 @@ scgi_proc *scgi_process_init() { f = calloc(1, sizeof(*f)); f->socket = buffer_init(); - + f->prev = NULL; f->next = NULL; - + return f; } void scgi_process_free(scgi_proc *f) { if (!f) return; - + scgi_process_free(f->next); - + buffer_free(f->socket); - + free(f); } @@ -400,62 +400,62 @@ scgi_extension_host *scgi_host_init() { f->bin_path = buffer_init(); f->bin_env = array_init(); f->bin_env_copy = array_init(); - + return f; } void scgi_host_free(scgi_extension_host *h) { if (!h) return; - + buffer_free(h->host); buffer_free(h->unixsocket); buffer_free(h->docroot); buffer_free(h->bin_path); array_free(h->bin_env); array_free(h->bin_env_copy); - + scgi_process_free(h->first); scgi_process_free(h->unused_procs); - + free(h); - + } scgi_exts *scgi_extensions_init() { scgi_exts *f; f = calloc(1, sizeof(*f)); - + return f; } void scgi_extensions_free(scgi_exts *f) { size_t i; - + if (!f) return; - + for (i = 0; i < f->used; i++) { scgi_extension *fe; size_t j; - + fe = f->exts[i]; - + for (j = 0; j < fe->used; j++) { scgi_extension_host *h; - + h = fe->hosts[j]; - + scgi_host_free(h); } - + buffer_free(fe->key); free(fe->hosts); - + free(fe); } - + free(f->exts); - + free(f); } @@ -504,99 +504,99 @@ int scgi_extension_insert(scgi_exts *ext, buffer *key, scgi_extension_host *fh) assert(fe->hosts); } - fe->hosts[fe->used++] = fh; + fe->hosts[fe->used++] = fh; return 0; - + } INIT_FUNC(mod_scgi_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->scgi_env = buffer_init(); - + p->path = buffer_init(); p->parse_response = buffer_init(); - + return p; } FREE_FUNC(mod_scgi_free) { plugin_data *p = p_d; - + UNUSED(srv); buffer_free(p->scgi_env); buffer_free(p->path); buffer_free(p->parse_response); - + if (p->config_storage) { size_t i, j, n; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; scgi_exts *exts; - + if (!s) continue; - + exts = s->exts; for (j = 0; j < exts->used; j++) { scgi_extension *ex; - + ex = exts->exts[j]; - + for (n = 0; n < ex->used; n++) { scgi_proc *proc; scgi_extension_host *host; - + host = ex->hosts[n]; - + for (proc = host->first; proc; proc = proc->next) { if (proc->pid != 0) kill(proc->pid, SIGTERM); - - if (proc->is_local && + + if (proc->is_local && !buffer_is_empty(proc->socket)) { unlink(proc->socket->ptr); } } - + for (proc = host->unused_procs; proc; proc = proc->next) { if (proc->pid != 0) kill(proc->pid, SIGTERM); - - if (proc->is_local && + + if (proc->is_local && !buffer_is_empty(proc->socket)) { unlink(proc->socket->ptr); } } } } - + scgi_extensions_free(s->exts); - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) { char *dst; - + if (!key || !val) return -1; - + dst = malloc(key_len + val_len + 3); memcpy(dst, key, key_len); dst[key_len] = '='; /* add the \0 from the value */ memcpy(dst + key_len + 1, val, val_len + 1); - + if (env->size == 0) { env->size = 16; env->ptr = malloc(env->size * sizeof(*env->ptr)); @@ -604,13 +604,13 @@ static int env_add(char_array *env, const char *key, size_t key_len, const char env->size += 16; env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr)); } - + env->ptr[env->used++] = dst; - + return 0; } -static int scgi_spawn_connection(server *srv, +static int scgi_spawn_connection(server *srv, plugin_data *p, scgi_extension_host *host, scgi_proc *proc) { @@ -622,25 +622,25 @@ static int scgi_spawn_connection(server *srv, #endif struct sockaddr_in scgi_addr_in; struct sockaddr *scgi_addr; - + socklen_t servlen; - + #ifndef HAVE_FORK return -1; #endif - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sdb", "new proc, socket:", proc->port, proc->socket); } - + if (!buffer_is_empty(proc->socket)) { memset(&scgi_addr, 0, sizeof(scgi_addr)); - + #ifdef HAVE_SYS_UN_H scgi_addr_un.sun_family = AF_UNIX; strcpy(scgi_addr_un.sun_path, proc->socket->ptr); - + #ifdef SUN_LEN servlen = SUN_LEN(&scgi_addr_un); #else @@ -656,115 +656,115 @@ static int scgi_spawn_connection(server *srv, #endif } else { scgi_addr_in.sin_family = AF_INET; - + if (buffer_is_empty(host->host)) { scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); } else { struct hostent *he; - + /* set a usefull default */ scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); - - + + if (NULL == (he = gethostbyname(host->host->ptr))) { - log_error_write(srv, __FILE__, __LINE__, - "sdb", "gethostbyname failed: ", + log_error_write(srv, __FILE__, __LINE__, + "sdb", "gethostbyname failed: ", h_errno, host->host); return -1; } - + if (he->h_addrtype != AF_INET) { log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype); return -1; } - + if (he->h_length != sizeof(struct in_addr)) { log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length); return -1; } - + memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length); - + } scgi_addr_in.sin_port = htons(proc->port); servlen = sizeof(scgi_addr_in); - + socket_type = AF_INET; scgi_addr = (struct sockaddr *) &scgi_addr_in; } - + if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "failed:", strerror(errno)); return -1; } - + if (-1 == connect(scgi_fd, scgi_addr, servlen)) { /* server is not up, spawn in */ pid_t child; int val; - + if (!buffer_is_empty(proc->socket)) { unlink(proc->socket->ptr); } - + close(scgi_fd); - + /* reopen socket */ if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); return -1; } - + val = 1; if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno)); return -1; } - + /* create socket */ if (-1 == bind(scgi_fd, scgi_addr, servlen)) { - log_error_write(srv, __FILE__, __LINE__, "sbds", - "bind failed for:", - proc->socket, - proc->port, + log_error_write(srv, __FILE__, __LINE__, "sbds", + "bind failed for:", + proc->socket, + proc->port, strerror(errno)); return -1; } - + if (-1 == listen(scgi_fd, 1024)) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed:", strerror(errno)); return -1; } - -#ifdef HAVE_FORK + +#ifdef HAVE_FORK switch ((child = fork())) { case 0: { buffer *b; size_t i = 0; int fd = 0; char_array env; - - + + /* create environment */ env.ptr = NULL; env.size = 0; env.used = 0; - + /* we don't need the client socket */ for (fd = 3; fd < 256; fd++) { if (fd != 2 && fd != scgi_fd) close(fd); } - + /* build clean environment */ if (host->bin_env_copy->used) { for (i = 0; i < host->bin_env_copy->used; i++) { data_string *ds = (data_string *)host->bin_env_copy->data[i]; char *ge; - + if (NULL != (ge = getenv(ds->value->ptr))) { env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge)); } @@ -772,44 +772,44 @@ static int scgi_spawn_connection(server *srv, } else { for (i = 0; environ[i]; i++) { char *eq; - + if (NULL != (eq = strchr(environ[i], '='))) { env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1)); } } } - + /* create environment */ for (i = 0; i < host->bin_env->used; i++) { data_string *ds = (data_string *)host->bin_env->data[i]; - + env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value)); } - + for (i = 0; i < env.used; i++) { /* search for PHP_FCGI_CHILDREN */ if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break; } - + /* not found, add a default */ if (i == env.used) { env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1")); } - + env.ptr[env.used] = NULL; - + b = buffer_init(); buffer_copy_string(b, "exec "); buffer_append_string_buffer(b, host->bin_path); - + /* exec the cgi */ execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr); - - log_error_write(srv, __FILE__, __LINE__, "sbs", + + log_error_write(srv, __FILE__, __LINE__, "sbs", "execl failed for:", host->bin_path, strerror(errno)); - + exit(errno); - + break; } case -1: @@ -817,32 +817,32 @@ static int scgi_spawn_connection(server *srv, break; default: /* father */ - + /* wait */ select(0, NULL, NULL, NULL, &tv); - + switch (waitpid(child, &status, WNOHANG)) { case 0: /* child still running after timeout, good */ break; case -1: /* no PID found ? should never happen */ - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "pid not found:", strerror(errno)); return -1; default: /* the child should not terminate at all */ if (WIFEXITED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child exited (is this a SCGI binary ?):", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child exited (is this a SCGI binary ?):", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", WTERMSIG(status)); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", status); } return -1; @@ -852,26 +852,26 @@ static int scgi_spawn_connection(server *srv, proc->pid = child; proc->last_used = srv->cur_ts; proc->is_local = 1; - + break; } #endif } else { proc->is_local = 0; proc->pid = 0; - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) socket is already used, won't spawn:", proc->socket); } } - + proc->state = PROC_STATE_RUNNING; host->active_procs++; - + close(scgi_fd); - + return 0; } @@ -880,89 +880,89 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { plugin_data *p = p_d; data_unset *du; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "scgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "scgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { 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; array *ca; - + s = malloc(sizeof(plugin_config)); s->exts = scgi_extensions_init(); s->debug = 0; - + cv[0].destination = s->exts; cv[1].destination = &(s->debug); - + p->config_storage[i] = s; ca = ((data_config *)srv->config_context->data[i])->value; - + if (0 != config_insert_values_global(srv, ca, cv)) { return HANDLER_ERROR; } - - /* + + /* * <key> = ( ... ) */ - + if (NULL != (du = array_get_element(ca, "scgi.server"))) { size_t j; data_array *da = (data_array *)du; - + if (du->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sss", + log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", "scgi.server", "array of strings"); - + return HANDLER_ERROR; } - - - /* - * scgi.server = ( "<ext>" => ( ... ), + + + /* + * scgi.server = ( "<ext>" => ( ... ), * "<ext>" => ( ... ) ) */ - + for (j = 0; j < da->value->used; j++) { size_t n; data_array *da_ext = (data_array *)da->value->data[j]; - + if (da->value->data[j]->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "sssbs", - "unexpected type for key: ", "scgi.server", + log_error_write(srv, __FILE__, __LINE__, "sssbs", + "unexpected type for key: ", "scgi.server", "[", da->value->data[j]->key, "](string)"); - + return HANDLER_ERROR; } - - /* - * da_ext->key == name of the extension + + /* + * da_ext->key == name of the extension */ - - /* - * scgi.server = ( "<ext>" => - * ( "<host>" => ( ... ), + + /* + * scgi.server = ( "<ext>" => + * ( "<host>" => ( ... ), * "<host>" => ( ... ) - * ), + * ), * "<ext>" => ... ) */ - + for (n = 0; n < da_ext->value->used; n++) { data_array *da_host = (data_array *)da_ext->value->data[n]; - + scgi_extension_host *df; - - config_values_t fcv[] = { + + config_values_t fcv[] = { { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ - + { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */ { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */ { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */ @@ -970,37 +970,37 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */ { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */ { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */ - + { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 11 */ { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */ - - + + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (da_host->type != TYPE_ARRAY) { - log_error_write(srv, __FILE__, __LINE__, "ssSBS", - "unexpected type for key:", - "scgi.server", + log_error_write(srv, __FILE__, __LINE__, "ssSBS", + "unexpected type for key:", + "scgi.server", "[", da_host->key, "](string)"); - + return HANDLER_ERROR; } - + df = scgi_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->disable_time = 60; - + fcv[0].destination = df->host; fcv[1].destination = df->docroot; fcv[2].destination = df->unixsocket; fcv[3].destination = df->bin_path; - + fcv[4].destination = &(df->check_local); fcv[5].destination = &(df->port); fcv[6].destination = &(df->min_procs); @@ -1008,47 +1008,47 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { fcv[8].destination = &(df->max_load_per_proc); fcv[9].destination = &(df->idle_timeout); fcv[10].destination = &(df->disable_time); - + fcv[11].destination = df->bin_env; fcv[12].destination = df->bin_env_copy; - - + + if (0 != config_insert_values_internal(srv, da_host->value, fcv)) { return HANDLER_ERROR; } - - if ((!buffer_is_empty(df->host) || df->port) && + + if ((!buffer_is_empty(df->host) || df->port) && !buffer_is_empty(df->unixsocket)) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "either host+port or socket"); - + return HANDLER_ERROR; } - + if (!buffer_is_empty(df->unixsocket)) { /* unix domain socket */ - + if (df->unixsocket->used > UNIX_PATH_MAX - 2) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "path of the unixdomain socket is too large"); return HANDLER_ERROR; } } else { /* tcp/ip */ - - if (buffer_is_empty(df->host) && + + if (buffer_is_empty(df->host) && buffer_is_empty(df->bin_path)) { - log_error_write(srv, __FILE__, __LINE__, "sbbbs", - "missing key (string):", + log_error_write(srv, __FILE__, __LINE__, "sbbbs", + "missing key (string):", da->key, da_ext->key, da_host->key, "host"); - + return HANDLER_ERROR; } else if (df->port == 0) { - log_error_write(srv, __FILE__, __LINE__, "sbbbs", - "missing key (short):", + log_error_write(srv, __FILE__, __LINE__, "sbbbs", + "missing key (short):", da->key, da_ext->key, da_host->key, @@ -1056,14 +1056,14 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { return HANDLER_ERROR; } } - - if (!buffer_is_empty(df->bin_path)) { + + if (!buffer_is_empty(df->bin_path)) { /* a local socket + self spawning */ size_t pno; - + 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 (s->debug) { log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd", "--- scgi spawning local", @@ -1073,7 +1073,7 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { "\n\tmin-procs:", df->min_procs, "\n\tmax-procs:", df->max_procs); } - + for (pno = 0; pno < df->min_procs; pno++) { scgi_proc *proc; @@ -1088,7 +1088,7 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { buffer_append_string(proc->socket, "-"); buffer_append_long(proc->socket, pno); } - + if (s->debug) { log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd", "--- scgi spawning", @@ -1096,53 +1096,53 @@ SETDEFAULTS_FUNC(mod_scgi_set_defaults) { "\n\tsocket", df->unixsocket, "\n\tcurrent:", pno, "/", df->min_procs); } - + if (scgi_spawn_connection(srv, p, df, proc)) { log_error_write(srv, __FILE__, __LINE__, "s", "[ERROR]: spawning fcgi failed."); return HANDLER_ERROR; } - + proc->next = df->first; if (df->first) df->first->prev = proc; - + df->first = proc; } } else { scgi_proc *fp; - + fp = scgi_process_init(); fp->id = df->num_procs++; df->max_id++; df->active_procs++; fp->state = PROC_STATE_RUNNING; - + if (buffer_is_empty(df->unixsocket)) { fp->port = df->port; } else { buffer_copy_string_buffer(fp->socket, df->unixsocket); } - + df->first = fp; - + df->min_procs = 1; df->max_procs = 1; } - + /* if extension already exists, take it */ scgi_extension_insert(s->exts, da_ext->key, df); } } } } - + return HANDLER_GO_ON; } static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) { hctx->state = state; hctx->state_timestamp = srv->cur_ts; - + return 0; } @@ -1150,34 +1150,34 @@ static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_ void scgi_connection_cleanup(server *srv, handler_ctx *hctx) { plugin_data *p; connection *con; - + if (NULL == hctx) return; - + p = hctx->plugin_data; con = hctx->remote_conn; - + if (con->mode != p->id) { WP(); return; } - + 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--; } - + if (hctx->host && hctx->proc) { hctx->host->load--; - + if (hctx->got_proc) { /* after the connect the process gets a load */ hctx->proc->load--; - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sddb", - "release proc:", + "release proc:", hctx->fd, hctx->proc->pid, hctx->proc->socket); } @@ -1186,87 +1186,87 @@ void scgi_connection_cleanup(server *srv, handler_ctx *hctx) { scgi_proclist_sort_down(srv, hctx->host, hctx->proc); } - + handler_ctx_free(hctx); - con->plugin_ctx[p->id] = NULL; + con->plugin_ctx[p->id] = NULL; } static int scgi_reconnect(server *srv, handler_ctx *hctx) { plugin_data *p = hctx->plugin_data; - - /* child died - * - * 1. - * + + /* child died + * + * 1. + * * connect was ok, connection was accepted * but the php accept loop checks after the accept if it should die or not. - * - * if yes we can only detect it at a write() - * + * + * if yes we can only detect it at a write() + * * next step is resetting this attemp and setup a connection again - * + * * if we have more then 5 reconnects for the same request, die - * - * 2. - * + * + * 2. + * * 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--; - + scgi_set_state(srv, hctx, FCGI_STATE_INIT); - + hctx->request_id = 0; hctx->reconnects++; - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sddb", - "release proc:", + "release proc:", hctx->fd, hctx->proc->pid, hctx->proc->socket); } - + hctx->proc->load--; scgi_proclist_sort_down(srv, hctx->host, hctx->proc); - + return 0; } static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - + scgi_connection_cleanup(srv, con->plugin_ctx[p->id]); - + return HANDLER_GO_ON; } static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) { size_t len; - + if (!key || !val) return -1; - + len = key_len + val_len + 2; - + buffer_prepare_append(env, len); - /* include the NUL */ + /* include the NUL */ memcpy(env->ptr + env->used, key, key_len + 1); env->used += key_len + 1; memcpy(env->ptr + env->used, val, val_len + 1); env->used += val_len + 1; - + return 0; } /** - * + * * returns * -1 error * 0 connected @@ -1280,13 +1280,13 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) { struct sockaddr_un scgi_addr_un; #endif socklen_t servlen; - + scgi_extension_host *host = hctx->host; scgi_proc *proc = hctx->proc; int scgi_fd = hctx->fd; - + memset(&scgi_addr, 0, sizeof(scgi_addr)); - + if (!buffer_is_empty(proc->socket)) { #ifdef HAVE_SYS_UN_H /* use the unix domain socket */ @@ -1305,105 +1305,105 @@ static int scgi_establish_connection(server *srv, handler_ctx *hctx) { } else { scgi_addr_in.sin_family = AF_INET; if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", - "converting IP-adress failed for", host->host, + log_error_write(srv, __FILE__, __LINE__, "sbs", + "converting IP-adress failed for", host->host, "\nBe sure to specify an IP address here"); - + return -1; } scgi_addr_in.sin_port = htons(proc->port); servlen = sizeof(scgi_addr_in); - + scgi_addr = (struct sockaddr *) &scgi_addr_in; } - + if (-1 == connect(scgi_fd, scgi_addr, servlen)) { - if (errno == EINPROGRESS || + if (errno == EINPROGRESS || errno == EALREADY || errno == EINTR) { if (hctx->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "connect delayed, will continue later:", scgi_fd); } - + return 1; } else { - log_error_write(srv, __FILE__, __LINE__, "sdsddb", - "connect failed:", scgi_fd, + log_error_write(srv, __FILE__, __LINE__, "sdsddb", + "connect failed:", scgi_fd, strerror(errno), errno, proc->port, proc->socket); if (errno == EAGAIN) { /* this is Linux only */ - - log_error_write(srv, __FILE__, __LINE__, "s", + + log_error_write(srv, __FILE__, __LINE__, "s", "If this happend on Linux: You have been run out of local ports. " "Check the manual, section Performance how to handle this."); - } - + } + return -1; } } if (hctx->conf.debug > 1) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "connect succeeded: ", scgi_fd); } - + return 0; } static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) { size_t i; - + for (i = 0; i < con->request.headers->used; i++) { data_string *ds; - + ds = (data_string *)con->request.headers->data[i]; - + if (ds->value->used && ds->key->used) { size_t j; buffer_reset(srv->tmp_buf); - + if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) { BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_"); srv->tmp_buf->used--; } - + 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++] = - light_isalpha(ds->key->ptr[j]) ? + srv->tmp_buf->ptr[srv->tmp_buf->used++] = + light_isalpha(ds->key->ptr[j]) ? ds->key->ptr[j] & ~32 : '_'; } srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0'; - + scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)); } } - + for (i = 0; i < con->environment->used; i++) { data_string *ds; - + ds = (data_string *)con->environment->data[i]; - + if (ds->value->used && ds->key->used) { size_t j; buffer_reset(srv->tmp_buf); - + 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]) ? + srv->tmp_buf->ptr[srv->tmp_buf->used++] = + isalpha((unsigned char)ds->key->ptr[j]) ? toupper((unsigned char)ds->key->ptr[j]) : '_'; } srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0'; - + scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value)); } } - + return 0; } @@ -1415,20 +1415,20 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { char b2[INET6_ADDRSTRLEN + 1]; #endif buffer *b; - + plugin_data *p = hctx->plugin_data; scgi_extension_host *host= hctx->host; connection *con = hctx->remote_conn; server_socket *srv_sock = con->srv_socket; - + sock_addr our_addr; socklen_t our_addr_len; - + buffer_prepare_copy(p->scgi_env, 1024); /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */ - + /* request.content_length < SSIZE_MAX, see request.c */ ltostr(buf, con->request.content_length); scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf)); @@ -1436,13 +1436,13 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION)); - + if (con->server_name->used) { scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name)); } else { #ifdef HAVE_IPV6 - s = inet_ntop(srv_sock->addr.plain.sa_family, - srv_sock->addr.plain.sa_family == AF_INET6 ? + s = inet_ntop(srv_sock->addr.plain.sa_family, + srv_sock->addr.plain.sa_family == AF_INET6 ? (const void *) &(srv_sock->addr.ipv6.sin6_addr) : (const void *) &(srv_sock->addr.ipv4.sin_addr), b2, sizeof(b2)-1); @@ -1451,47 +1451,47 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { #endif scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s)); } - + scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")); - - ltostr(buf, + + ltostr(buf, #ifdef HAVE_IPV6 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port) #else ntohs(srv_sock->addr.ipv4.sin_port) #endif ); - + scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf)); - + /* get the server-side of the connection to the client */ our_addr_len = sizeof(our_addr); - + if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) { s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr)); } else { s = inet_ntop_cache_get_ip(srv, &(our_addr)); } scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s)); - - ltostr(buf, + + ltostr(buf, #ifdef HAVE_IPV6 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port) #else ntohs(con->dst_addr.ipv4.sin_port) #endif ); - + scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf)); - + s = inet_ntop_cache_get_ip(srv, &(con->dst_addr)); scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s)); - + if (!buffer_is_empty(con->authed_user)) { scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"), CONST_BUF_LEN(con->authed_user)); } - + /* * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to @@ -1500,12 +1500,12 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { */ scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path)); - + if (!buffer_is_empty(con->request.pathinfo)) { scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo)); - + /* PATH_TRANSLATED is only defined if PATH_INFO is set */ - + if (!buffer_is_empty(host->docroot)) { buffer_copy_string_buffer(p->path, host->docroot); } else { @@ -1526,19 +1526,19 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { */ if (!buffer_is_empty(host->docroot)) { - /* - * rewrite SCRIPT_FILENAME - * + /* + * rewrite SCRIPT_FILENAME + * */ - + buffer_copy_string_buffer(p->path, host->docroot); buffer_append_string_buffer(p->path, con->uri.path); - + scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)); scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot)); } else { buffer_copy_string_buffer(p->path, con->physical.path); - + scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path)); scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root)); } @@ -1551,30 +1551,30 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { } else { scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN("")); } - + s = get_http_method_name(con->request.http_method); scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s)); scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */ s = get_http_version_name(con->request.http_version); scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s)); - + #ifdef USE_OPENSSL if (srv_sock->is_ssl) { scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")); } #endif - + scgi_env_add_request_headers(srv, con, p); b = chunkqueue_get_append_buffer(hctx->wb); - + buffer_append_long(b, p->scgi_env->used); buffer_append_string_len(b, CONST_STR_LEN(":")); buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used); buffer_append_string_len(b, CONST_STR_LEN(",")); hctx->wb->bytes_in += b->used - 1; - + if (con->request.content_length) { chunkqueue *req_cq = con->request_content_queue; chunk *req_c; @@ -1587,7 +1587,7 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { /* we announce toWrite octects * now take all the request_content chunk that we need to fill this request - * */ + * */ switch (req_c->type) { case FILE_CHUNK: @@ -1615,32 +1615,32 @@ static int scgi_create_env(server *srv, handler_ctx *hctx) { req_c->offset += weHave; req_cq->bytes_out += weHave; - + hctx->wb->bytes_in += weHave; break; default: break; } - + offset += weHave; } } - + #if 0 for (i = 0; i < hctx->write_buffer->used; i++) { fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]); if ((i+1) % 16 == 0) { size_t j; for (j = i-15; j <= i; j++) { - fprintf(stderr, "%c", + fprintf(stderr, "%c", isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.'); } fprintf(stderr, "\n"); } } #endif - + return 0; } @@ -1648,32 +1648,32 @@ static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buf char *ns; const char *s; int line = 0; - + UNUSED(srv); - + buffer_copy_string_buffer(p->parse_response, in); - - for (s = p->parse_response->ptr; - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); + + for (s = p->parse_response->ptr; + NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n'))); s = ns + (eol == EOL_RN ? 2 : 1), line++) { const char *key, *value; int key_len; data_string *ds; - + ns[0] = '\0'; - - if (line == 0 && + + if (line == 0 && 0 == strncmp(s, "HTTP/1.", 7)) { /* non-parsed header ... we parse them anyway */ - + if ((s[7] == '1' || s[7] == '0') && s[8] == ' ') { int status; /* after the space should be a status code for us */ - + status = strtol(s+9, NULL, 10); - + if (con->http_status >= 100 && con->http_status < 1000) { /* we expected 3 digits and didn't got them */ @@ -1682,27 +1682,27 @@ static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buf } } } else { - + key = s; if (NULL == (value = strchr(s, ':'))) { /* we expect: "<key>: <value>\r\n" */ continue; } - + key_len = value - key; value += 1; - + /* skip LWS */ while (*value == ' ' || *value == '\t') value++; - + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { ds = data_response_init(); } buffer_copy_string_len(ds->key, key, key_len); buffer_copy_string(ds->value, value); - + array_insert_unique(con->response.headers, (data_unset *)ds); - + switch(key_len) { case 4: if (0 == strncasecmp(key, "Date", key_len)) { @@ -1737,13 +1737,13 @@ static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buf } } } - + /* CGI/1.1 rev 03 - 7.2.1.2 */ if ((con->parsed_response & HTTP_LOCATION) && !(con->parsed_response & HTTP_STATUS)) { con->http_status = 302; } - + return 0; } @@ -1751,10 +1751,10 @@ static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buf static int scgi_demux_response(server *srv, handler_ctx *hctx) { plugin_data *p = hctx->plugin_data; connection *con = hctx->remote_conn; - + while(1) { int n; - + buffer_prepare_copy(hctx->response, 1024); if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) { if (errno == EAGAIN || errno == EINTR) { @@ -1765,143 +1765,143 @@ static int scgi_demux_response(server *srv, handler_ctx *hctx) { log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd); return -1; } - + if (n == 0) { /* read finished */ - + con->file_finished = 1; - + /* send final chunk */ http_chunk_append_mem(srv, con, NULL, 0); joblist_append(srv, con); - + return 1; } - + hctx->response->ptr[n] = '\0'; hctx->response->used = n+1; - + /* split header from body */ - + if (con->file_started == 0) { char *c; int in_header = 0; int header_end = 0; int cp, eol = EOL_UNSET; size_t used = 0; - + buffer_append_string_buffer(hctx->response_header, hctx->response); - + /* nph (non-parsed headers) */ if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1; - + /* search for the \r\n\r\n or \n\n in the string */ for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) { if (*c == ':') in_header = 1; else if (*c == '\n') { if (in_header == 0) { /* got a response without a response header */ - + c = NULL; header_end = 1; break; } - + if (eol == EOL_UNSET) eol = EOL_N; - + if (*(c+1) == '\n') { header_end = 1; break; } - + } else if (used > 1 && *c == '\r' && *(c+1) == '\n') { if (in_header == 0) { /* got a response without a response header */ - + c = NULL; header_end = 1; break; } - + if (eol == EOL_UNSET) eol = EOL_RN; - + if (used > 3 && - *(c+2) == '\r' && + *(c+2) == '\r' && *(c+3) == '\n') { header_end = 1; break; } - + /* skip the \n */ c++; cp++; used--; } } - + if (header_end) { if (c == NULL) { /* no header, but a body */ - + if (con->request.http_version == HTTP_VERSION_1_1) { con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; } - + http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used); joblist_append(srv, con); } else { size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2); size_t blen = hctx->response_header->used - hlen - 1; - + /* a small hack: terminate after at the second \r */ hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1); hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0'; - + /* parse the response header */ scgi_response_parse(srv, con, p, hctx->response_header, eol); - + /* enable chunked-transfer-encoding */ if (con->request.http_version == HTTP_VERSION_1_1 && !(con->parsed_response & HTTP_CONTENT_LENGTH)) { con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; } - + if ((hctx->response->used != hlen) && blen > 0) { http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1); joblist_append(srv, con); } } - + con->file_started = 1; } } else { http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used); joblist_append(srv, con); } - -#if 0 + +#if 0 log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr); #endif } - + return 0; } int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) { scgi_proc *p; - + UNUSED(srv); - - /* we have been the smallest of the current list - * and we want to insert the node sorted as soon + + /* we have been the smallest of the current list + * and we want to insert the node sorted as soon * possible * - * 1 0 0 0 1 1 1 - * | ^ + * 1 0 0 0 1 1 1 + * | ^ * | | * +------+ - * + * */ /* nothing to sort, only one element */ @@ -1909,9 +1909,9 @@ int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *pro for (p = proc; p->next && p->next->load < proc->load; p = p->next); - /* no need to move something + /* no need to move something * - * 1 2 2 2 3 3 3 + * 1 2 2 2 3 3 3 * ^ * | * + @@ -1930,16 +1930,16 @@ int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *pro if (proc->prev) proc->prev->next = proc->next; if (proc->next) proc->next->prev = proc->prev; - + /* proc should be right of p */ - + proc->next = p->next; proc->prev = p; if (p->next) p->next->prev = proc; p->next = proc; #if 0 for(p = host->first; p; p = p->next) { - log_error_write(srv, __FILE__, __LINE__, "dd", + log_error_write(srv, __FILE__, __LINE__, "dd", p->pid, p->load); } #else @@ -1951,21 +1951,21 @@ int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *pro int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) { scgi_proc *p; - + UNUSED(srv); - - /* we have been the smallest of the current list - * and we want to insert the node sorted as soon + + /* we have been the smallest of the current list + * and we want to insert the node sorted as soon * possible * - * 0 0 0 0 1 0 1 + * 0 0 0 0 1 0 1 * ^ | * | | * +----------+ * * * the basic is idea is: - * - the last active scgi process should be still + * - the last active scgi process should be still * in ram and is not swapped out yet * - processes that are not reused will be killed * after some time by the trigger-handler @@ -1975,7 +1975,7 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p * ice-cold processes are propably unused since more * than 'unused-timeout', are swaped out and won't be * reused in the next seconds anyway. - * + * */ /* nothing to sort, only one element */ @@ -1984,16 +1984,16 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p for (p = host->first; p != proc && p->load < proc->load; p = p->next); - /* no need to move something + /* no need to move something * - * 1 2 2 2 3 3 3 + * 1 2 2 2 3 3 3 * ^ * | * + * */ if (p == proc) return 0; - + /* we have to move left. If we are already the first element * we are done */ if (host->first == proc) return 0; @@ -2009,9 +2009,9 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p p->prev = proc; if (proc->prev == NULL) host->first = proc; -#if 0 +#if 0 for(p = host->first; p; p = p->next) { - log_error_write(srv, __FILE__, __LINE__, "dd", + log_error_write(srv, __FILE__, __LINE__, "dd", p->pid, p->load); } #else @@ -2023,40 +2023,40 @@ int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *p static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) { scgi_proc *proc; - + for (proc = host->first; proc; proc = proc->next) { if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbdbdddd", - "proc:", - host->host, proc->port, + log_error_write(srv, __FILE__, __LINE__, "sbdbdddd", + "proc:", + host->host, proc->port, proc->socket, proc->state, proc->is_local, proc->load, proc->pid); } - + if (0 == proc->is_local) { - /* - * external servers might get disabled - * - * enable the server again, perhaps it is back again + /* + * external servers might get disabled + * + * enable the server again, perhaps it is back again */ - + if ((proc->state == PROC_STATE_DISABLED) && (srv->cur_ts - proc->disable_ts > host->disable_time)) { proc->state = PROC_STATE_RUNNING; host->active_procs++; - - log_error_write(srv, __FILE__, __LINE__, "sbdb", - "fcgi-server re-enabled:", - host->host, host->port, + + log_error_write(srv, __FILE__, __LINE__, "sbdb", + "fcgi-server re-enabled:", + host->host, host->port, host->unixsocket); } } else { /* the child should not terminate at all */ int status; - + if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) { switch(waitpid(proc->pid, &status, WNOHANG)) { case 0: @@ -2067,33 +2067,33 @@ static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_h default: if (WIFEXITED(status)) { #if 0 - log_error_write(srv, __FILE__, __LINE__, "sdsd", + log_error_write(srv, __FILE__, __LINE__, "sdsd", "child exited, pid:", proc->pid, "status:", WEXITSTATUS(status)); #endif } else if (WIFSIGNALED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", WTERMSIG(status)); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", status); } - + proc->state = PROC_STATE_DIED; break; } } - - /* + + /* * local servers might died, but we restart them - * + * */ if (proc->state == PROC_STATE_DIED && proc->load == 0) { /* restart the child */ - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd", "--- scgi spawning", @@ -2101,18 +2101,18 @@ static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_h "\n\tsocket", host->unixsocket, "\n\tcurrent:", 1, "/", host->min_procs); } - + if (scgi_spawn_connection(srv, p, host, proc)) { log_error_write(srv, __FILE__, __LINE__, "s", "ERROR: spawning fcgi failed."); return HANDLER_ERROR; } - + scgi_proclist_sort_down(srv, host, proc); } } } - + return 0; } @@ -2121,13 +2121,13 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) { plugin_data *p = hctx->plugin_data; scgi_extension_host *host= hctx->host; connection *con = hctx->remote_conn; - + int ret; - /* sanity check */ + /* sanity check */ if (!host || ((!host->host->used || !host->port) && !host->unixsocket->used)) { - log_error_write(srv, __FILE__, __LINE__, "sxddd", + log_error_write(srv, __FILE__, __LINE__, "sxddd", "write-req: error", host, host->host->used, @@ -2135,179 +2135,179 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) { host->unixsocket->used); return HANDLER_ERROR; } - + switch(hctx->state) { case FCGI_STATE_INIT: ret = host->unixsocket->used ? AF_UNIX : AF_INET; - + if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) { if (errno == EMFILE || errno == EINTR) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "wait for fd at connection:", con->fd); - + return HANDLER_WAIT_FOR_FD; } - - log_error_write(srv, __FILE__, __LINE__, "ssdd", + + log_error_write(srv, __FILE__, __LINE__, "ssdd", "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds); return HANDLER_ERROR; } hctx->fde_ndx = -1; - + srv->cur_fds++; - + fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx); - + if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno)); - + return HANDLER_ERROR; } - + /* fall through */ case FCGI_STATE_CONNECT: if (hctx->state == FCGI_STATE_INIT) { - for (hctx->proc = hctx->host->first; - hctx->proc && hctx->proc->state != PROC_STATE_RUNNING; + 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; } - + switch (scgi_establish_connection(srv, hctx)) { case 1: scgi_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); - + return HANDLER_WAIT_FOR_EVENT; case -1: /* if ECONNREFUSED choose another connection -> FIXME */ hctx->fde_ndx = -1; - + return HANDLER_ERROR; default: /* everything is ok, go on */ break; } - + } else { 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", + 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), + "establishing connection failed:", strerror(socket_error), "port:", hctx->proc->port); } - + return HANDLER_ERROR; } } - + /* ok, we have the connection */ - + hctx->proc->load++; hctx->proc->last_used = srv->cur_ts; hctx->got_proc = 1; - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sddbdd", - "got proc:", + "got proc:", hctx->fd, - hctx->proc->pid, - hctx->proc->socket, + hctx->proc->pid, + hctx->proc->socket, hctx->proc->port, hctx->proc->load); } /* move the proc-list entry down the list */ scgi_proclist_sort_up(srv, hctx->host, hctx->proc); - + scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE); /* fall through */ case FCGI_STATE_PREPARE_WRITE: scgi_create_env(srv, hctx); - + scgi_set_state(srv, hctx, FCGI_STATE_WRITE); - + /* fall through */ case FCGI_STATE_WRITE: - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); + ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb); chunkqueue_remove_finished_chunks(hctx->wb); - + if (-1 == ret) { if (errno == ENOTCONN) { - /* the connection got dropped after accept() - * - * this is most of the time a PHP which dies + /* the connection got dropped after accept() + * + * this is most of the time a PHP which dies * after PHP_FCGI_MAX_REQUESTS - * - */ + * + */ if (hctx->wb->bytes_out == 0 && hctx->reconnects < 5) { - usleep(10000); /* take away the load of the webserver - * to let the php a chance to restart + usleep(10000); /* take away the load of the webserver + * to let the php a chance to restart */ - + scgi_reconnect(srv, hctx); - + return HANDLER_WAIT_FOR_FD; } - + /* not reconnected ... why - * + * * far@#lighttpd report this for FreeBSD - * + * */ - - log_error_write(srv, __FILE__, __LINE__, "ssdsd", + + log_error_write(srv, __FILE__, __LINE__, "ssdsd", "[REPORT ME] connection was dropped after accept(). reconnect() denied:", "write-offset:", hctx->wb->bytes_out, "reconnect attempts:", hctx->reconnects); - + return HANDLER_ERROR; } - + if ((errno != EAGAIN) && (errno != EINTR)) { - - log_error_write(srv, __FILE__, __LINE__, "ssd", + + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno); - + return HANDLER_ERROR; } else { fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - + return HANDLER_WAIT_FOR_EVENT; } } - + if (hctx->wb->bytes_out == hctx->wb->bytes_in) { /* we don't need the out event anymore */ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd); @@ -2315,10 +2315,10 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) { scgi_set_state(srv, hctx, FCGI_STATE_READ); } else { fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - + return HANDLER_WAIT_FOR_EVENT; } - + break; case FCGI_STATE_READ: /* waiting for a response */ @@ -2327,67 +2327,67 @@ static handler_t scgi_write_request(server *srv, handler_ctx *hctx) { log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state"); return HANDLER_ERROR; } - + return HANDLER_WAIT_FOR_EVENT; } SUBREQUEST_FUNC(mod_scgi_handle_subrequest) { plugin_data *p = p_d; - + handler_ctx *hctx = con->plugin_ctx[p->id]; scgi_proc *proc; scgi_extension_host *host; - + if (NULL == hctx) return HANDLER_GO_ON; - + /* not my job */ if (con->mode != p->id) return HANDLER_GO_ON; - + /* ok, create the request */ switch(scgi_write_request(srv, hctx)) { case HANDLER_ERROR: proc = hctx->proc; host = hctx->host; - - if (proc && + + 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:", + + 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--; } - + if (hctx->state == FCGI_STATE_INIT || hctx->state == FCGI_STATE_CONNECT) { - /* connect() or getsockopt() failed, - * restart the request-handling + /* connect() or getsockopt() failed, + * restart the request-handling */ if (proc && proc->is_local) { if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:", + log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi 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) { @@ -2395,25 +2395,25 @@ SUBREQUEST_FUNC(mod_scgi_handle_subrequest) { } } scgi_restart_dead_procs(srv, p, host); - + scgi_connection_cleanup(srv, hctx); - + buffer_reset(con->physical.path); con->mode = DIRECT; joblist_append(srv, con); - - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop - * and hope that the childs will be restarted - * + + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop + * and hope that the childs will be restarted + * */ return HANDLER_WAIT_FOR_FD; } else { scgi_connection_cleanup(srv, hctx); - + buffer_reset(con->physical.path); con->mode = DIRECT; con->http_status = 503; - + return HANDLER_FINISHED; } case HANDLER_WAIT_FOR_EVENT: @@ -2433,23 +2433,23 @@ SUBREQUEST_FUNC(mod_scgi_handle_subrequest) { static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) { plugin_data *p; connection *con; - + if (NULL == hctx) return HANDLER_GO_ON; - + p = hctx->plugin_data; con = hctx->remote_conn; - + if (con->mode != p->id) return HANDLER_GO_ON; - - log_error_write(srv, __FILE__, __LINE__, "ssdsd", - "emergency exit: scgi:", + + log_error_write(srv, __FILE__, __LINE__, "ssdsd", + "emergency exit: scgi:", "connection-fd:", con->fd, "fcgi-fd:", hctx->fd); - - - + + + scgi_connection_cleanup(srv, hctx); - + return HANDLER_FINISHED; } @@ -2459,7 +2459,7 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) { handler_ctx *hctx = ctx; connection *con = hctx->remote_conn; plugin_data *p = hctx->plugin_data; - + scgi_proc *proc = hctx->proc; scgi_extension_host *host= hctx->host; @@ -2471,15 +2471,15 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) { case 1: /* we are done */ scgi_connection_cleanup(srv, hctx); - + joblist_append(srv, con); return HANDLER_FINISHED; case -1: if (proc->pid && proc->state != PROC_STATE_DIED) { int status; - + /* only fetch the zombie if it is not already done */ - + switch(waitpid(proc->pid, &status, WNOHANG)) { case 0: /* child is still alive */ @@ -2489,19 +2489,19 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) { default: /* the child should not terminate at all */ if (WIFEXITED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sdsd", + log_error_write(srv, __FILE__, __LINE__, "sdsd", "child exited, pid:", proc->pid, "status:", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", WTERMSIG(status)); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", status); } - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd", "--- scgi spawning", @@ -2509,40 +2509,40 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) { "\n\tsocket", host->unixsocket, "\n\tcurrent:", 1, "/", host->min_procs); } - + if (scgi_spawn_connection(srv, p, host, proc)) { /* child died */ proc->state = PROC_STATE_DIED; } else { scgi_proclist_sort_down(srv, host, proc); } - + break; } } if (con->file_started == 0) { /* nothing has been send out yet, try to use another child */ - + if (hctx->wb->bytes_out == 0 && hctx->reconnects < 5) { scgi_reconnect(srv, hctx); - - log_error_write(srv, __FILE__, __LINE__, "sdsdsd", + + log_error_write(srv, __FILE__, __LINE__, "sdsdsd", "response not sent, request not sent, reconnection.", "connection-fd:", con->fd, "fcgi-fd:", hctx->fd); - + return HANDLER_WAIT_FOR_FD; } - - log_error_write(srv, __FILE__, __LINE__, "sdsdsd", + + log_error_write(srv, __FILE__, __LINE__, "sdsdsd", "response not sent, request sent:", hctx->wb->bytes_out, "connection-fd:", con->fd, "fcgi-fd:", hctx->fd); - + scgi_connection_cleanup(srv, hctx); - + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST); buffer_reset(con->physical.path); con->http_status = 500; @@ -2550,76 +2550,76 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) { } else { /* response might have been already started, kill the connection */ scgi_connection_cleanup(srv, hctx); - - log_error_write(srv, __FILE__, __LINE__, "ssdsd", + + log_error_write(srv, __FILE__, __LINE__, "ssdsd", "response already sent out, termination connection", "connection-fd:", con->fd, "fcgi-fd:", hctx->fd); - + connection_set_state(srv, con, CON_STATE_ERROR); } /* */ - - + + joblist_append(srv, con); return HANDLER_FINISHED; } } - + if (revents & FDEVENT_OUT) { if (hctx->state == FCGI_STATE_CONNECT || hctx->state == FCGI_STATE_WRITE) { /* we are allowed to send something out - * + * * 1. in a unfinished connect() call * 2. in a unfinished write() call (long POST request) */ return mod_scgi_handle_subrequest(srv, con, p); } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "got a FDEVENT_OUT and didn't know why:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "got a FDEVENT_OUT and didn't know why:", hctx->state); } } - + /* perhaps this issue is already handled */ if (revents & FDEVENT_HUP) { if (hctx->state == FCGI_STATE_CONNECT) { /* getoptsock will catch this one (right ?) - * - * if we are in connect we might get a EINPROGRESS - * in the first call and a FDEVENT_HUP in the + * + * if we are in connect we might get a EINPROGRESS + * in the first call and a FDEVENT_HUP in the * second round - * + * * FIXME: as it is a bit ugly. - * + * */ return mod_scgi_handle_subrequest(srv, con, p); } else if (hctx->state == FCGI_STATE_READ && hctx->proc->port == 0) { /* FIXME: - * + * * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket * even if the FCGI_FIN packet is not received yet */ } else { - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", - "error: unexpected close of scgi connection for", + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd", + "error: unexpected close of scgi connection for", con->uri.path, - "(no scgi process on host: ", + "(no scgi process on host: ", host->host, - ", port: ", + ", port: ", host->port, " ?)", hctx->state); - + connection_set_state(srv, con, CON_STATE_ERROR); scgi_connection_close(srv, hctx); joblist_append(srv, con); } } else if (revents & FDEVENT_ERR) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "fcgi: got a FDEVENT_ERR. Don't know why."); /* kill all connections to the scgi process */ @@ -2628,7 +2628,7 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) { scgi_connection_close(srv, hctx); joblist_append(srv, con); } - + return HANDLER_FINISHED; } #define PATCH(x) \ @@ -2636,22 +2636,22 @@ static handler_t scgi_handle_fdevent(void *s, void *ctx, int revents) { static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(exts); PATCH(debug); - + /* 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("scgi.server"))) { PATCH(exts); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) { @@ -2659,7 +2659,7 @@ static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) { } } } - + return 0; } #undef PATCH @@ -2673,30 +2673,30 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i size_t k; buffer *fn; scgi_extension *extension = NULL; - + /* Possibly, we processed already this request */ if (con->file_started == 1) return HANDLER_GO_ON; - + fn = uri_path_handler ? con->uri.path : con->physical.path; if (buffer_is_empty(fn)) return HANDLER_GO_ON; s_len = fn->used - 1; - + scgi_patch_connection(srv, con, p); /* check if extension matches */ for (k = 0; k < p->conf.exts->used; k++) { size_t ct_len; - + extension = p->conf.exts->exts[k]; - + if (extension->key->used == 0) continue; - + ct_len = extension->key->used - 1; - + if (s_len < ct_len) continue; - + /* check extension in the form "/scgi_pattern" */ if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) { break; @@ -2710,17 +2710,17 @@ static handler_t scgi_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++) { scgi_extension_host *host = extension->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; } } @@ -2728,12 +2728,12 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i /* found a server */ if (ndx != -1) { scgi_extension_host *host = extension->hosts[ndx]; - - /* - * if check-local is disabled, use the uri.path handler - * + + /* + * if check-local is disabled, use the uri.path handler + * */ - + /* init handler-context */ if (uri_path_handler) { if (host->check_local == 0) { @@ -2741,7 +2741,7 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i char *pathinfo; hctx = handler_ctx_init(); - + hctx->remote_conn = con; hctx->plugin_data = p; hctx->host = host; @@ -2749,45 +2749,45 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i 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_scgi"); } - /* the prefix is the SCRIPT_NAME, + /* 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 */ - + /* 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'; } @@ -2796,21 +2796,21 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i } else { handler_ctx *hctx; hctx = handler_ctx_init(); - + hctx->remote_conn = con; hctx->plugin_data = p; hctx->host = host; hctx->proc = NULL; - + 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"); } @@ -2821,11 +2821,11 @@ static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, i /* no handler found */ buffer_reset(con->physical.path); con->http_status = 500; - - log_error_write(srv, __FILE__, __LINE__, "sb", - "no fcgi-handler found for:", + + log_error_write(srv, __FILE__, __LINE__, "sb", + "no fcgi-handler found for:", fn); - + return HANDLER_FINISHED; } return HANDLER_GO_ON; @@ -2844,19 +2844,19 @@ static handler_t scgi_check_extension_2(server *srv, connection *con, void *p_d) JOBLIST_FUNC(mod_scgi_handle_joblist) { plugin_data *p = p_d; handler_ctx *hctx = con->plugin_ctx[p->id]; - + if (hctx == NULL) return HANDLER_GO_ON; if (hctx->fd != -1) { switch (hctx->state) { case FCGI_STATE_READ: fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN); - + break; case FCGI_STATE_CONNECT: case FCGI_STATE_WRITE: fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT); - + break; case FCGI_STATE_INIT: /* at reconnect */ @@ -2873,21 +2873,21 @@ JOBLIST_FUNC(mod_scgi_handle_joblist) { static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - + return scgi_connection_close(srv, con->plugin_ctx[p->id]); } TRIGGER_FUNC(mod_scgi_handle_trigger) { plugin_data *p = p_d; size_t i, j, n; - - + + /* perhaps we should kill a connect attempt after 10-15 seconds - * + * * currently we wait for the TCP timeout which is on Linux 180 seconds - * - * - * + * + * + * */ /* check all childs if they are still up */ @@ -2904,47 +2904,47 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) { scgi_extension *ex; ex = exts->exts[j]; - + for (n = 0; n < ex->used; n++) { - + scgi_proc *proc; unsigned long sum_load = 0; scgi_extension_host *host; - + host = ex->hosts[n]; - + scgi_restart_dead_procs(srv, p, host); - + for (proc = host->first; proc; proc = proc->next) { sum_load += proc->load; } - + if (host->num_procs && host->num_procs < host->max_procs && (sum_load / host->num_procs) > host->max_load_per_proc) { /* overload, spawn new child */ scgi_proc *fp = NULL; - + if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "overload detected, spawning a new child"); } - + for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next); - + if (fp) { if (fp == host->unused_procs) host->unused_procs = fp->next; - + if (fp->next) fp->next->prev = NULL; - + host->max_id++; } else { fp = scgi_process_init(); fp->id = host->max_id++; } - + host->num_procs++; - + if (buffer_is_empty(host->unixsocket)) { fp->port = host->port + fp->id; } else { @@ -2952,13 +2952,13 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) { buffer_append_string(fp->socket, "-"); buffer_append_long(fp->socket, fp->id); } - + if (scgi_spawn_connection(srv, p, host, fp)) { log_error_write(srv, __FILE__, __LINE__, "s", "ERROR: spawning fcgi failed."); return HANDLER_ERROR; } - + fp->prev = NULL; fp->next = host->first; if (host->first) { @@ -2966,56 +2966,56 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) { } host->first = fp; } - + for (proc = host->first; proc; proc = proc->next) { if (proc->load != 0) break; if (host->num_procs <= host->min_procs) break; if (proc->pid == 0) continue; - + if (srv->cur_ts - proc->last_used > host->idle_timeout) { /* a proc is idling for a long time now, * terminated it */ - + if (p->conf.debug) { - log_error_write(srv, __FILE__, __LINE__, "ssbsd", - "idle-timeout reached, terminating child:", - "socket:", proc->socket, + log_error_write(srv, __FILE__, __LINE__, "ssbsd", + "idle-timeout reached, terminating child:", + "socket:", proc->socket, "pid", proc->pid); } - - + + if (proc->next) proc->next->prev = proc->prev; if (proc->prev) proc->prev->next = proc->next; - + if (proc->prev == NULL) host->first = proc->next; - + proc->prev = NULL; proc->next = host->unused_procs; - + if (host->unused_procs) host->unused_procs->prev = proc; host->unused_procs = proc; - + kill(proc->pid, SIGTERM); - + proc->state = PROC_STATE_KILLED; - - log_error_write(srv, __FILE__, __LINE__, "ssbsd", - "killed:", - "socket:", proc->socket, + + log_error_write(srv, __FILE__, __LINE__, "ssbsd", + "killed:", + "socket:", proc->socket, "pid", proc->pid); - + host->num_procs--; - + /* proc is now in unused, let the next second handle the next process */ break; - } + } } - + for (proc = host->unused_procs; proc; proc = proc->next) { int status; - + if (proc->pid == 0) continue; - + switch (waitpid(proc->pid, &status, WNOHANG)) { case 0: /* child still running after timeout, good */ @@ -3023,10 +3023,10 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) { case -1: if (errno != EINTR) { /* no PID found ? should never happen */ - log_error_write(srv, __FILE__, __LINE__, "sddss", + log_error_write(srv, __FILE__, __LINE__, "sddss", "pid ", proc->pid, proc->state, "not found:", strerror(errno)); - + #if 0 if (errno == ECHILD) { /* someone else has cleaned up for us */ @@ -3040,19 +3040,19 @@ TRIGGER_FUNC(mod_scgi_handle_trigger) { /* the child should not terminate at all */ if (WIFEXITED(status)) { if (proc->state != PROC_STATE_KILLED) { - log_error_write(srv, __FILE__, __LINE__, "sdb", - "child exited:", + log_error_write(srv, __FILE__, __LINE__, "sdb", + "child exited:", WEXITSTATUS(status), proc->socket); } } else if (WIFSIGNALED(status)) { if (WTERMSIG(status) != SIGTERM) { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child signaled:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child signaled:", WTERMSIG(status)); } } else { - log_error_write(srv, __FILE__, __LINE__, "sd", - "child died somehow:", + log_error_write(srv, __FILE__, __LINE__, "sd", + "child died somehow:", status); } proc->pid = 0; @@ -3082,8 +3082,8 @@ int mod_scgi_plugin_init(plugin *p) { p->handle_subrequest = mod_scgi_handle_subrequest; p->handle_joblist = mod_scgi_handle_joblist; p->handle_trigger = mod_scgi_handle_trigger; - + p->data = NULL; - + return 0; } diff --git a/src/mod_secure_download.c b/src/mod_secure_download.c index 1ea5a50..08a0554 100644 --- a/src/mod_secure_download.c +++ b/src/mod_secure_download.c @@ -25,7 +25,7 @@ typedef char HASHHEX[HASHHEXLEN+1]; #ifdef USE_OPENSSL #define IN const #else -#define IN +#define IN #endif #define OUT @@ -36,28 +36,28 @@ typedef struct { buffer *doc_root; buffer *secret; buffer *uri_prefix; - + unsigned short timeout; } plugin_config; typedef struct { PLUGIN_DATA; - + buffer *md5; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_secdownload_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->md5 = buffer_init(); - + return p; } @@ -65,27 +65,27 @@ INIT_FUNC(mod_secdownload_init) { FREE_FUNC(mod_secdownload_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]; - + buffer_free(s->secret); buffer_free(s->doc_root); buffer_free(s->uri_prefix); - + free(s); } free(p->config_storage); } - + buffer_free(p->md5); - + free(p); - + return HANDLER_GO_ON; } @@ -94,65 +94,65 @@ FREE_FUNC(mod_secdownload_free) { SETDEFAULTS_FUNC(mod_secdownload_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "secdownload.secret", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "secdownload.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "secdownload.timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->secret = buffer_init(); s->doc_root = buffer_init(); s->uri_prefix = buffer_init(); s->timeout = 60; - + cv[0].destination = s->secret; cv[1].destination = s->doc_root; cv[2].destination = s->uri_prefix; cv[3].destination = &(s->timeout); - + 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; } /** * checks if the supplied string is a MD5 string - * + * * @param str a possible MD5 string * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0 */ int is_hex_len(const char *str, size_t len) { size_t i; - + if (NULL == str) return 0; - + for (i = 0; i < len && *str; i++, str++) { /* illegal characters */ if (!((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f') || - (*str >= 'A' && *str <= 'F')) + (*str >= 'A' && *str <= 'F')) ) { return 0; } } - + return i == len; } @@ -161,24 +161,24 @@ int is_hex_len(const char *str, size_t len) { static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(secret); PATCH(doc_root); PATCH(uri_prefix); PATCH(timeout); - + /* 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("secdownload.secret"))) { PATCH(secret); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) { @@ -190,7 +190,7 @@ static int mod_secdownload_patch_connection(server *srv, connection *con, plugin } } } - + return 0; } #undef PATCH @@ -203,88 +203,88 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) { const char *rel_uri, *ts_str, *md5_str; time_t ts = 0; size_t i; - + if (con->uri.path->used == 0) return HANDLER_GO_ON; - + mod_secdownload_patch_connection(srv, con, p); if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON; - + if (buffer_is_empty(p->conf.secret)) { log_error_write(srv, __FILE__, __LINE__, "s", "secdownload.secret has to be set"); return HANDLER_ERROR; } - + if (buffer_is_empty(p->conf.doc_root)) { log_error_write(srv, __FILE__, __LINE__, "s", "secdownload.document-root has to be set"); return HANDLER_ERROR; } - - /* + + /* * /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path> */ - + if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON; - + md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1; - + if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON; if (*(md5_str + 32) != '/') return HANDLER_GO_ON; - + ts_str = md5_str + 32 + 1; - + if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON; if (*(ts_str + 8) != '/') return HANDLER_GO_ON; - + for (i = 0; i < 8; i++) { ts = (ts << 4) + hex2int(*(ts_str + i)); } - + /* timed-out */ - if (srv->cur_ts - ts > p->conf.timeout || + if (srv->cur_ts - ts > p->conf.timeout || srv->cur_ts - ts < -p->conf.timeout) { con->http_status = 408; - + return HANDLER_FINISHED; } - + rel_uri = ts_str + 8; - - /* checking MD5 - * + + /* checking MD5 + * * <secret><rel-path><timestamp-hex> */ - + buffer_copy_string_buffer(p->md5, p->conf.secret); buffer_append_string(p->md5, rel_uri); buffer_append_string_len(p->md5, ts_str, 8); - + MD5_Init(&Md5Ctx); MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1); MD5_Final(HA1, &Md5Ctx); - + buffer_copy_string_hex(p->md5, (char *)HA1, 16); - + if (0 != strncmp(md5_str, p->md5->ptr, 32)) { con->http_status = 403; - - log_error_write(srv, __FILE__, __LINE__, "sss", + + log_error_write(srv, __FILE__, __LINE__, "sss", "md5 invalid:", md5_str, p->md5->ptr); - + return HANDLER_FINISHED; } - + /* starting with the last / we should have relative-path to the docroot */ - + buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root); buffer_copy_string(con->physical.rel_path, rel_uri); buffer_copy_string_buffer(con->physical.path, con->physical.doc_root); buffer_append_string_buffer(con->physical.path, con->physical.rel_path); - + return HANDLER_GO_ON; } @@ -293,13 +293,13 @@ URIHANDLER_FUNC(mod_secdownload_uri_handler) { int mod_secdownload_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("secdownload"); - + p->init = mod_secdownload_init; p->handle_physical = mod_secdownload_uri_handler; p->set_defaults = mod_secdownload_set_defaults; p->cleanup = mod_secdownload_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_setenv.c b/src/mod_setenv.c index 9501554..88ce45a 100644 --- a/src/mod_setenv.c +++ b/src/mod_setenv.c @@ -18,25 +18,25 @@ typedef struct { typedef struct { array *request_header; array *response_header; - + array *environment; } plugin_config; typedef struct { PLUGIN_DATA; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; static handler_ctx * handler_ctx_init() { handler_ctx * hctx; - + hctx = calloc(1, sizeof(*hctx)); - + hctx->handled = 0; - + return hctx; } @@ -48,36 +48,36 @@ static void handler_ctx_free(handler_ctx *hctx) { /* init the plugin data */ INIT_FUNC(mod_setenv_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_setenv_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]; - + array_free(s->request_header); array_free(s->response_header); array_free(s->environment); - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } @@ -86,37 +86,37 @@ FREE_FUNC(mod_setenv_free) { SETDEFAULTS_FUNC(mod_setenv_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->request_header = array_init(); s->response_header = array_init(); s->environment = array_init(); - + cv[0].destination = s->request_header; cv[1].destination = s->response_header; cv[2].destination = s->environment; - + 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; } @@ -125,23 +125,23 @@ SETDEFAULTS_FUNC(mod_setenv_set_defaults) { static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(request_header); PATCH(response_header); PATCH(environment); - + /* 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("setenv.add-request-header"))) { PATCH(request_header); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) { @@ -151,7 +151,7 @@ static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data } } } - + return 0; } #undef PATCH @@ -160,12 +160,12 @@ 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; } @@ -180,52 +180,52 @@ URIHANDLER_FUNC(mod_setenv_uri_handler) { for (k = 0; k < p->conf.request_header->used; k++) { data_string *ds = (data_string *)p->conf.request_header->data[k]; data_string *ds_dst; - + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { ds_dst = data_string_init(); } - + buffer_copy_string_buffer(ds_dst->key, ds->key); buffer_copy_string_buffer(ds_dst->value, ds->value); - + array_insert_unique(con->request.headers, (data_unset *)ds_dst); } - + for (k = 0; k < p->conf.environment->used; k++) { data_string *ds = (data_string *)p->conf.environment->data[k]; data_string *ds_dst; - + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) { ds_dst = data_string_init(); } - + buffer_copy_string_buffer(ds_dst->key, ds->key); buffer_copy_string_buffer(ds_dst->value, ds->value); - + array_insert_unique(con->environment, (data_unset *)ds_dst); } - + for (k = 0; k < p->conf.response_header->used; k++) { data_string *ds = (data_string *)p->conf.response_header->data[k]; - + response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value)); } - + /* not found */ 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; + return HANDLER_GO_ON; } /* this function is called at dlopen() time and inits the callbacks */ @@ -233,15 +233,15 @@ REQUESTDONE_FUNC(mod_setenv_reset) { int mod_setenv_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("setenv"); - + p->init = mod_setenv_init; p->handle_uri_clean = mod_setenv_uri_handler; 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_simple_vhost.c b/src/mod_simple_vhost.c index 8f81384..d55cfed 100644 --- a/src/mod_simple_vhost.c +++ b/src/mod_simple_vhost.c @@ -18,7 +18,7 @@ typedef struct { buffer *server_root; buffer *default_host; buffer *document_root; - + buffer *docroot_cache_key; buffer *docroot_cache_value; buffer *docroot_cache_servername; @@ -28,119 +28,119 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *doc_root; - + plugin_config **config_storage; - plugin_config conf; + plugin_config conf; } plugin_data; INIT_FUNC(mod_simple_vhost_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->doc_root = buffer_init(); - + return p; } FREE_FUNC(mod_simple_vhost_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]; - + buffer_free(s->document_root); buffer_free(s->default_host); buffer_free(s->server_root); - + buffer_free(s->docroot_cache_key); buffer_free(s->docroot_cache_value); buffer_free(s->docroot_cache_servername); - + free(s); } - + free(p->config_storage); } - + buffer_free(p->doc_root); - + free(p); - + return HANDLER_GO_ON; } SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) { plugin_data *p = p_d; size_t i; - - config_values_t cv[] = { + + config_values_t cv[] = { { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); - + s->server_root = buffer_init(); s->default_host = buffer_init(); s->document_root = buffer_init(); - + s->docroot_cache_key = buffer_init(); s->docroot_cache_value = buffer_init(); s->docroot_cache_servername = buffer_init(); s->debug = 0; - + cv[0].destination = s->server_root; cv[1].destination = s->default_host; cv[2].destination = s->document_root; cv[3].destination = &(s->debug); - - + + 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; } static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) { stat_cache_entry *sce = NULL; - + buffer_prepare_copy(out, 128); if (p->conf.server_root->used) { buffer_copy_string_buffer(out, p->conf.server_root); - + if (host->used) { /* a hostname has to start with a alpha-numerical character * and must not contain a slash "/" */ char *dp; - + BUFFER_APPEND_SLASH(out); - + if (NULL == (dp = strchr(host->ptr, ':'))) { buffer_append_string_buffer(out, host); } else { @@ -148,7 +148,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer * } } BUFFER_APPEND_SLASH(out); - + if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') { buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2); } else { @@ -159,7 +159,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer * buffer_copy_string_buffer(out, con->conf.document_root); BUFFER_APPEND_SLASH(out); } - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) { if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", @@ -169,7 +169,7 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer * } else if (!S_ISDIR(sce->st.st_mode)) { return -1; } - + return 0; } @@ -179,29 +179,29 @@ static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer * static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(server_root); PATCH(default_host); PATCH(document_root); - + PATCH(docroot_cache_key); PATCH(docroot_cache_value); PATCH(docroot_cache_servername); PATCH(debug); - + /* 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("simple-vhost.server-root"))) { PATCH(server_root); PATCH(docroot_cache_key); @@ -216,7 +216,7 @@ static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugi } } } - + return 0; } #undef PATCH @@ -227,12 +227,12 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_ /* * cache the last successfull translation from hostname (authority) to docroot * - this saves us a stat() call - * + * */ - + mod_simple_vhost_patch_connection(srv, con, p); - - if (p->conf.docroot_cache_key->used && + + if (p->conf.docroot_cache_key->used && con->uri.authority->used && buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) { /* cache hit */ @@ -243,8 +243,8 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_ if ((con->uri.authority->used == 0) || build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) { /* not found, fallback the default-host */ - if (build_doc_root(srv, con, p, - p->doc_root, + if (build_doc_root(srv, con, p, + p->doc_root, p->conf.default_host)) { return HANDLER_GO_ON; } else { @@ -253,15 +253,15 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_ } else { buffer_copy_string_buffer(con->server_name, con->uri.authority); } - + /* copy to cache */ buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority); buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root); buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name); - + buffer_copy_string_buffer(con->physical.doc_root, p->doc_root); } - + return HANDLER_GO_ON; } @@ -269,13 +269,13 @@ static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_ int mod_simple_vhost_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("simple_vhost"); - + p->init = mod_simple_vhost_init; p->set_defaults = mod_simple_vhost_set_defaults; p->handle_docroot = mod_simple_vhost_docroot; p->cleanup = mod_simple_vhost_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_skeleton.c b/src/mod_skeleton.c index a3fa186..9cea92c 100644 --- a/src/mod_skeleton.c +++ b/src/mod_skeleton.c @@ -14,13 +14,13 @@ /** * this is a skeleton for a lighttpd plugin - * + * * just replaces every occurance of 'skeleton' by your plugin name - * + * * e.g. in vim: - * + * * :%s/skeleton/myhandler/ - * + * */ @@ -33,12 +33,12 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *match_buf; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; typedef struct { @@ -47,36 +47,36 @@ typedef struct { static handler_ctx * handler_ctx_init() { handler_ctx * hctx; - + hctx = calloc(1, sizeof(*hctx)); - + return hctx; } static void handler_ctx_free(handler_ctx *hctx) { - + free(hctx); } /* init the plugin data */ INIT_FUNC(mod_skeleton_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->match_buf = buffer_init(); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_skeleton_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { size_t i; @@ -84,18 +84,18 @@ FREE_FUNC(mod_skeleton_free) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + array_free(s->match); - + free(s); } free(p->config_storage); } - + buffer_free(p->match_buf); - + free(p); - + return HANDLER_GO_ON; } @@ -104,31 +104,31 @@ FREE_FUNC(mod_skeleton_free) { SETDEFAULTS_FUNC(mod_skeleton_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->match = array_init(); - + cv[0].destination = s->match; - + 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; } @@ -137,27 +137,27 @@ SETDEFAULTS_FUNC(mod_skeleton_set_defaults) { static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(match); - + /* 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("skeleton.array"))) { PATCH(match); } } } - + return 0; } #undef PATCH @@ -166,29 +166,29 @@ URIHANDLER_FUNC(mod_skeleton_uri_handler) { plugin_data *p = p_d; int s_len; size_t k, i; - + UNUSED(srv); if (con->uri.path->used == 0) return HANDLER_GO_ON; - + mod_skeleton_patch_connection(srv, con, p); s_len = con->uri.path->used - 1; - + for (k = 0; k < p->conf.match->used; k++) { data_string *ds = (data_string *)p->conf.match->data[k]; int 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)) { con->http_status = 403; - + return HANDLER_FINISHED; } } - + /* not found */ return HANDLER_GO_ON; } @@ -198,13 +198,13 @@ URIHANDLER_FUNC(mod_skeleton_uri_handler) { int mod_skeleton_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("skeleton"); - + p->init = mod_skeleton_init; p->handle_uri_clean = mod_skeleton_uri_handler; p->set_defaults = mod_skeleton_set_defaults; p->cleanup = mod_skeleton_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_ssi.c b/src/mod_ssi.c index 4fdae2f..e66a6fc 100644 --- a/src/mod_ssi.c +++ b/src/mod_ssi.c @@ -39,15 +39,15 @@ /* init the plugin data */ INIT_FUNC(mod_ssi_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->timefmt = buffer_init(); p->stat_fn = buffer_init(); - + p->ssi_vars = array_init(); p->ssi_cgi_env = array_init(); - + return p; } @@ -55,21 +55,21 @@ INIT_FUNC(mod_ssi_init) { FREE_FUNC(mod_ssi_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]; - + array_free(s->ssi_extension); - + free(s); } free(p->config_storage); } - + array_free(p->ssi_vars); array_free(p->ssi_cgi_env); #ifdef HAVE_PCRE_H @@ -77,9 +77,9 @@ FREE_FUNC(mod_ssi_free) { #endif buffer_free(p->timefmt); buffer_free(p->stat_fn); - + free(p); - + return HANDLER_GO_ON; } @@ -92,36 +92,36 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) { const char *errptr; int erroff; #endif - - config_values_t cv[] = { + + config_values_t cv[] = { { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->ssi_extension = array_init(); - + cv[0].destination = s->ssi_extension; - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } } - + #ifdef HAVE_PCRE_H /* allow 2 params */ if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) { log_error_write(srv, __FILE__, __LINE__, "sds", - "ssi: pcre ", + "ssi: pcre ", erroff, errptr); return HANDLER_ERROR; } @@ -130,52 +130,52 @@ SETDEFAULTS_FUNC(mod_ssi_set_defaults) { "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules"); return HANDLER_ERROR; #endif - + return HANDLER_GO_ON; } int ssi_env_add(array *env, const char *key, const char *val) { data_string *ds; - + if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) { ds = data_string_init(); } buffer_copy_string(ds->key, key); buffer_copy_string(ds->value, val); - + array_insert_unique(env, (data_unset *)ds); - + return 0; } /** * * the next two functions are take from fcgi.c - * + * */ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) { size_t i; - + for (i = 0; i < con->request.headers->used; i++) { data_string *ds; - + ds = (data_string *)con->request.headers->data[i]; - + if (ds->value->used && ds->key->used) { size_t j; buffer_reset(srv->tmp_buf); - + /* don't forward the Authorization: Header */ if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) { continue; } - + if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) { buffer_copy_string(srv->tmp_buf, "HTTP_"); srv->tmp_buf->used--; } - + buffer_prepare_append(srv->tmp_buf, ds->key->used + 2); for (j = 0; j < ds->key->used - 1; j++) { char c = '_'; @@ -189,33 +189,33 @@ static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data srv->tmp_buf->ptr[srv->tmp_buf->used++] = c; } srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0'; - + ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr); } } - + return 0; } static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) { char buf[32]; - + server_socket *srv_sock = con->srv_socket; - + #ifdef HAVE_IPV6 char b2[INET6_ADDRSTRLEN + 1]; #endif #define CONST_STRING(x) \ x - + array_reset(p->ssi_cgi_env); - + ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION); ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"), #ifdef HAVE_IPV6 - inet_ntop(srv_sock->addr.plain.sa_family, - srv_sock->addr.plain.sa_family == AF_INET6 ? + inet_ntop(srv_sock->addr.plain.sa_family, + srv_sock->addr.plain.sa_family == AF_INET6 ? (const void *) &(srv_sock->addr.ipv6.sin6_addr) : (const void *) &(srv_sock->addr.ipv4.sin_addr), b2, sizeof(b2)-1) @@ -224,28 +224,28 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) { #endif ); ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1"); - - ltostr(buf, + + ltostr(buf, #ifdef HAVE_IPV6 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port) #else ntohs(srv_sock->addr.ipv4.sin_port) #endif ); - + ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf); - + ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"), inet_ntop_cache_get_ip(srv, &(con->dst_addr))); - + if (con->authed_user->used) { ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"), con->authed_user->ptr); } - + if (con->request.content_length > 0) { /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */ - + /* request.content_length < SSIZE_MAX, see request.c */ ltostr(buf, con->request.content_length); ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf); @@ -271,30 +271,30 @@ static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) { if (con->request.pathinfo->used) { ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr); } - + ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr); ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr); - + ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr); ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : ""); ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method)); ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200"); ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version)); - + ssi_env_add_request_headers(srv, con, p); - + return 0; } -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const char **l, size_t n) { size_t i, ssicmd = 0; char buf[255]; buffer *b = NULL; - - struct { + + struct { const char *var; - enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD, + enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD, SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF, SSI_ELSE, SSI_ENDIF, SSI_EXEC } type; } ssicmds[] = { @@ -310,27 +310,27 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, { "endif", SSI_ENDIF }, { "else", SSI_ELSE }, { "exec", SSI_EXEC }, - + { NULL, SSI_UNSET } }; - + for (i = 0; ssicmds[i].var; i++) { if (0 == strcmp(l[1], ssicmds[i].var)) { ssicmd = ssicmds[i].type; break; } } - + switch(ssicmd) { case SSI_ECHO: { /* echo */ int var = 0, enc = 0; const char *var_val = NULL; stat_cache_entry *sce = NULL; - - struct { + + struct { const char *var; - enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI, + enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI, SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type; } echovars[] = { { "DATE_GMT", SSI_ECHO_DATE_GMT }, @@ -339,27 +339,27 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, { "DOCUMENT_URI", SSI_ECHO_DOCUMENT_URI }, { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED }, { "USER_NAME", SSI_ECHO_USER_NAME }, - + { NULL, SSI_ECHO_UNSET } }; - - struct { + + struct { const char *var; enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type; } encvars[] = { { "url", SSI_ENC_URL }, { "none", SSI_ENC_NONE }, { "entity", SSI_ENC_ENTITY }, - + { NULL, SSI_ENC_UNSET } }; - + for (i = 2; i < n; i += 2) { if (0 == strcmp(l[i], "var")) { int j; - + var_val = l[i+1]; - + for (j = 0; echovars[j].var; j++) { if (0 == strcmp(l[i+1], echovars[j].var)) { var = echovars[j].type; @@ -368,7 +368,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } } else if (0 == strcmp(l[i], "encoding")) { int j; - + for (j = 0; encvars[j].var; j++) { if (0 == strcmp(l[i+1], encvars[j].var)) { enc = encvars[j].type; @@ -377,26 +377,26 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } } else { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: unknow attribute for ", + "ssi: unknow attribute for ", l[1], l[i]); } } - + if (p->if_is_false) break; - + if (!var_val) { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: ", + "ssi: ", l[1], "var is missing"); break; } stat_cache_get_entry(srv, con, con->physical.path, &sce); - + switch(var) { case SSI_ECHO_USER_NAME: { struct passwd *pw; - + b = chunkqueue_get_append_buffer(con->write_queue); #ifdef HAVE_PWD_H if (NULL == (pw = getpwuid(sce->st.st_uid))) { @@ -411,7 +411,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } case SSI_ECHO_LAST_MODIFIED: { time_t t = sce->st.st_mtime; - + b = chunkqueue_get_append_buffer(con->write_queue); if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) { buffer_copy_string(b, "(none)"); @@ -422,7 +422,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } case SSI_ECHO_DATE_LOCAL: { time_t t = time(NULL); - + b = chunkqueue_get_append_buffer(con->write_queue); if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) { buffer_copy_string(b, "(none)"); @@ -433,7 +433,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } case SSI_ECHO_DATE_GMT: { time_t t = time(NULL); - + b = chunkqueue_get_append_buffer(con->write_queue); if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) { buffer_copy_string(b, "(none)"); @@ -444,7 +444,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } case SSI_ECHO_DOCUMENT_NAME: { char *sl; - + b = chunkqueue_get_append_buffer(con->write_queue); if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) { buffer_copy_string_buffer(b, con->physical.path); @@ -461,15 +461,15 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, default: { data_string *ds; /* check if it is a cgi-var */ - + b = chunkqueue_get_append_buffer(con->write_queue); - + if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) { buffer_copy_string_buffer(b, ds->value); } else { buffer_copy_string(b, "(none)"); } - + break; } } @@ -481,7 +481,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, const char * file_path = NULL, *virt_path = NULL; struct stat st; char *sl; - + for (i = 2; i < n; i += 2) { if (0 == strcmp(l[i], "file")) { file_path = l[i+1]; @@ -489,28 +489,28 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, virt_path = l[i+1]; } else { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: unknow attribute for ", + "ssi: unknow attribute for ", l[1], l[i]); } } - + if (!file_path && !virt_path) { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: ", + "ssi: ", l[1], "file or virtual are missing"); break; } - + if (file_path && virt_path) { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: ", + "ssi: ", l[1], "only one of file and virtual is allowed here"); break; } - - + + if (p->if_is_false) break; - + if (file_path) { /* current doc-root */ if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) { @@ -519,46 +519,46 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1); } - buffer_copy_string(srv->tmp_buf, file_path); + buffer_copy_string(srv->tmp_buf, file_path); buffer_urldecode_path(srv->tmp_buf); - buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); - buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); + buffer_path_simplify(srv->tmp_buf, srv->tmp_buf); + buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); } else { /* virtual */ - + if (virt_path[0] == '/') { buffer_copy_string(p->stat_fn, virt_path); } else { /* there is always a / */ sl = strrchr(con->uri.path->ptr, '/'); - + buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1); buffer_append_string(p->stat_fn, virt_path); } - + buffer_urldecode_path(p->stat_fn); buffer_path_simplify(srv->tmp_buf, p->stat_fn); - + /* we have an uri */ - + buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root); buffer_append_string_buffer(p->stat_fn, srv->tmp_buf); } - + if (0 == stat(p->stat_fn->ptr, &st)) { time_t t = st.st_mtime; - + switch (ssicmd) { case SSI_FSIZE: b = chunkqueue_get_append_buffer(con->write_queue); if (p->sizefmt) { int j = 0; const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL }; - + off_t s = st.st_size; - + for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++); - + buffer_copy_off_t(b, s); buffer_append_string(b, abr[j]); } else { @@ -579,7 +579,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } } else { log_error_write(srv, __FILE__, __LINE__, "sbs", - "ssi: stating failed ", + "ssi: stating failed ", p->stat_fn, strerror(errno)); } break; @@ -593,33 +593,33 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, val = l[i+1]; } else { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: unknow attribute for ", + "ssi: unknow attribute for ", l[1], l[i]); } } - + if (p->if_is_false) break; - + if (key && val) { data_string *ds; - + if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) { ds = data_string_init(); } buffer_copy_string(ds->key, key); buffer_copy_string(ds->value, val); - + array_insert_unique(p->ssi_vars, (data_unset *)ds); } else { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: var and value have to be set in", + "ssi: var and value have to be set in", l[0], l[1]); } break; } - case SSI_CONFIG: + case SSI_CONFIG: if (p->if_is_false) break; - + for (i = 2; i < n; i += 2) { if (0 == strcmp(l[i], "timefmt")) { buffer_copy_string(p->timefmt, l[i+1]); @@ -632,63 +632,63 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, log_error_write(srv, __FILE__, __LINE__, "sssss", "ssi: unknow value for attribute '", l[i], - "' for ", + "' for ", l[1], l[i+1]); } } else { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: unknow attribute for ", + "ssi: unknow attribute for ", l[1], l[i]); } } break; case SSI_PRINTENV: if (p->if_is_false) break; - + b = chunkqueue_get_append_buffer(con->write_queue); buffer_copy_string(b, "<pre>"); for (i = 0; i < p->ssi_vars->used; i++) { data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]]; - + buffer_append_string_buffer(b, ds->key); buffer_append_string(b, ": "); buffer_append_string_buffer(b, ds->value); buffer_append_string(b, "<br />"); - + } buffer_append_string(b, "</pre>"); - + break; case SSI_EXEC: { const char *cmd = NULL; pid_t pid; int from_exec_fds[2]; - + for (i = 2; i < n; i += 2) { if (0 == strcmp(l[i], "cmd")) { cmd = l[i+1]; } else { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: unknow attribute for ", + "ssi: unknow attribute for ", l[1], l[i]); } } - + if (p->if_is_false) break; - + /* create a return pipe and send output to the html-page - * - * as exec is assumed evil it is implemented synchronously + * + * as exec is assumed evil it is implemented synchronously */ - + if (!cmd) break; -#ifdef HAVE_FORK +#ifdef HAVE_FORK if (pipe(from_exec_fds)) { - log_error_write(srv, __FILE__, __LINE__, "ss", + log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno)); return -1; } - + /* fork, execve */ switch (pid = fork()) { case 0: { @@ -698,14 +698,14 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, close(from_exec_fds[1]); /* not needed */ close(from_exec_fds[0]); - + /* close stdin */ close(STDIN_FILENO); - + execl("/bin/sh", "sh", "-c", cmd, NULL); - + log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd); - + /* */ SEGFAULT(); break; @@ -718,16 +718,16 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, /* father */ int status; ssize_t r; - + close(from_exec_fds[1]); - + /* wait for the client to end */ /* * FIXME: if we get interrupted by a SIGCHILD we count this as error * * for now it only happened on OpenBSD. - * + * * that leads to zombies and missing output */ if (-1 == waitpid(pid, &status, 0)) { @@ -738,7 +738,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, while(1) { if (ioctl(from_exec_fds[0], FIONREAD, &toread)) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "unexpected end-of-file (perhaps the ssi-exec process died)"); return -1; } @@ -746,10 +746,10 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, if (toread > 0) { b = chunkqueue_get_append_buffer(con->write_queue); - buffer_prepare_copy(b, toread + 1); + buffer_prepare_copy(b, toread + 1); if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) { - /* read failed */ + /* read failed */ break; } else { b->used = r; @@ -763,7 +763,7 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally"); } close(from_exec_fds[0]); - + break; } } @@ -771,51 +771,51 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, return -1; #endif - + break; } case SSI_IF: { const char *expr = NULL; - + for (i = 2; i < n; i += 2) { if (0 == strcmp(l[i], "expr")) { expr = l[i+1]; } else { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: unknow attribute for ", + "ssi: unknow attribute for ", l[1], l[i]); } } - + if (!expr) { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: ", + "ssi: ", l[1], "expr missing"); break; } - + if ((!p->if_is_false) && - ((p->if_is_false_level == 0) || + ((p->if_is_false_level == 0) || (p->if_level < p->if_is_false_level))) { switch (ssi_eval_expr(srv, con, p, expr)) { case -1: - case 0: - p->if_is_false = 1; + case 0: + p->if_is_false = 1; p->if_is_false_level = p->if_level; break; - case 1: - p->if_is_false = 0; + case 1: + p->if_is_false = 0; break; } } - + p->if_level++; - + break; } case SSI_ELSE: p->if_level--; - + if (p->if_is_false) { if ((p->if_level == p->if_is_false_level) && (p->if_is_false_endif == 0)) { @@ -823,11 +823,11 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, } } else { p->if_is_false = 1; - + p->if_is_false_level = p->if_level; } p->if_level++; - + break; case SSI_ELIF: { const char *expr = NULL; @@ -836,52 +836,52 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, expr = l[i+1]; } else { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: unknow attribute for ", + "ssi: unknow attribute for ", l[1], l[i]); } } - + if (!expr) { log_error_write(srv, __FILE__, __LINE__, "sss", - "ssi: ", + "ssi: ", l[1], "expr missing"); break; } - + p->if_level--; - + if (p->if_level == p->if_is_false_level) { if ((p->if_is_false) && (p->if_is_false_endif == 0)) { switch (ssi_eval_expr(srv, con, p, expr)) { case -1: - case 0: - p->if_is_false = 1; + case 0: + p->if_is_false = 1; p->if_is_false_level = p->if_level; break; - case 1: - p->if_is_false = 0; + case 1: + p->if_is_false = 0; break; } } else { - p->if_is_false = 1; + p->if_is_false = 1; p->if_is_false_level = p->if_level; p->if_is_false_endif = 1; } } - + p->if_level++; - + break; } case SSI_ENDIF: p->if_level--; - + if (p->if_level == p->if_is_false_level) { p->if_is_false = 0; p->if_is_false_endif = 0; } - + break; default: log_error_write(srv, __FILE__, __LINE__, "ss", @@ -889,41 +889,41 @@ static int process_ssi_stmt(server *srv, connection *con, plugin_data *p, l[1]); break; } - + return 0; - + } static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) { stream s; #ifdef HAVE_PCRE_H int i, n; - + #define N 10 int ovec[N * 3]; #endif - + /* get a stream to the file */ - + array_reset(p->ssi_vars); array_reset(p->ssi_cgi_env); buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z"); p->sizefmt = 0; build_ssi_cgi_vars(srv, con, p); p->if_is_false = 0; - + if (-1 == stream_open(&s, con->physical.path)) { log_error_write(srv, __FILE__, __LINE__, "sb", "stream-open: ", con->physical.path); return -1; } - - + + /** - * <!--#element attribute=value attribute=value ... --> - * + * <!--#element attribute=value attribute=value ... --> + * * config DONE - * errmsg -- missing + * errmsg -- missing * sizefmt DONE * timefmt DONE * echo DONE @@ -945,13 +945,13 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) * set DONE * var DONE * value DONE - * + * * if DONE * elif DONE * else DONE * endif DONE - * - * + * + * * expressions * AND, OR DONE * comp DONE @@ -959,60 +959,60 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) * $... DONE * '...' DONE * ( ... ) DONE - * - * - * + * + * + * * ** all DONE ** - * DATE_GMT - * The current date in Greenwich Mean Time. - * DATE_LOCAL - * The current date in the local time zone. - * DOCUMENT_NAME - * The filename (excluding directories) of the document requested by the user. - * DOCUMENT_URI - * The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document. - * LAST_MODIFIED - * The last modification date of the document requested by the user. - * USER_NAME + * DATE_GMT + * The current date in Greenwich Mean Time. + * DATE_LOCAL + * The current date in the local time zone. + * DOCUMENT_NAME + * The filename (excluding directories) of the document requested by the user. + * DOCUMENT_URI + * The (%-decoded) URL path of the document requested by the user. Note that in the case of nested include files, this is not then URL for the current document. + * LAST_MODIFIED + * The last modification date of the document requested by the user. + * USER_NAME * Contains the owner of the file which included it. - * + * */ -#ifdef HAVE_PCRE_H +#ifdef HAVE_PCRE_H for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) { const char **l; /* take everything from last offset to current match pos */ - + if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i); - + pcre_get_substring_list(s.start, ovec, n, &l); process_ssi_stmt(srv, con, p, l, n); pcre_free_substring_list(l); } - + switch(n) { case PCRE_ERROR_NOMATCH: /* copy everything/the rest */ chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i); - + break; default: log_error_write(srv, __FILE__, __LINE__, "sd", "execution error while matching: ", n); break; } -#endif - - +#endif + + stream_close(&s); - + con->file_started = 1; con->file_finished = 1; - + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); - + /* reset physical.path */ buffer_reset(con->physical.path); - + return 0; } @@ -1021,27 +1021,27 @@ static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(ssi_extension); - + /* 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("ssi.extension"))) { PATCH(ssi_extension); } } } - + return 0; } #undef PATCH @@ -1049,28 +1049,28 @@ static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p URIHANDLER_FUNC(mod_ssi_physical_path) { plugin_data *p = p_d; size_t k; - + if (con->physical.path->used == 0) return HANDLER_GO_ON; - + mod_ssi_patch_connection(srv, con, p); - + for (k = 0; k < p->conf.ssi_extension->used; k++) { data_string *ds = (data_string *)p->conf.ssi_extension->data[k]; - + if (ds->value->used == 0) continue; - + if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) { /* handle ssi-request */ - + if (mod_ssi_handle_request(srv, con, p)) { /* on error */ con->http_status = 500; } - + return HANDLER_FINISHED; } } - + /* not found */ return HANDLER_GO_ON; } @@ -1080,13 +1080,13 @@ URIHANDLER_FUNC(mod_ssi_physical_path) { int mod_ssi_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("ssi"); - + p->init = mod_ssi_init; p->handle_subrequest_start = mod_ssi_physical_path; p->set_defaults = mod_ssi_set_defaults; p->cleanup = mod_ssi_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_ssi.h b/src/mod_ssi.h index 80f03ed..4d2214b 100644 --- a/src/mod_ssi.h +++ b/src/mod_ssi.h @@ -19,23 +19,23 @@ typedef struct { typedef struct { PLUGIN_DATA; - -#ifdef HAVE_PCRE_H + +#ifdef HAVE_PCRE_H pcre *ssi_regex; -#endif +#endif buffer *timefmt; int sizefmt; - + buffer *stat_fn; - + array *ssi_vars; array *ssi_cgi_env; - + int if_level, if_is_false_level, if_is_false, if_is_false_endif; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr); diff --git a/src/mod_ssi_expr.c b/src/mod_ssi_expr.c index 98959ab..fc6e4cb 100644 --- a/src/mod_ssi_expr.c +++ b/src/mod_ssi_expr.c @@ -11,9 +11,9 @@ typedef struct { const char *input; size_t offset; size_t size; - + int line_pos; - + int in_key; int in_brace; int in_cond; @@ -21,15 +21,15 @@ typedef struct { ssi_val_t *ssi_val_init() { ssi_val_t *s; - + s = calloc(1, sizeof(*s)); - + return s; } void ssi_val_free(ssi_val_t *s) { if (s->str) buffer_free(s->str); - + free(s); } @@ -45,175 +45,175 @@ static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p, ssi_tokenizer_t *t, int *token_id, buffer *token) { int tid = 0; size_t i; - + UNUSED(con); for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) { char c = t->input[t->offset]; data_string *ds; - + switch (c) { - case '=': + case '=': tid = TK_EQ; - + t->offset++; t->line_pos++; - + buffer_copy_string(token, "(=)"); - + break; case '>': if (t->input[t->offset + 1] == '=') { t->offset += 2; t->line_pos += 2; - + tid = TK_GE; - + buffer_copy_string(token, "(>=)"); } else { t->offset += 1; t->line_pos += 1; - + tid = TK_GT; - + buffer_copy_string(token, "(>)"); } - + break; case '<': if (t->input[t->offset + 1] == '=') { t->offset += 2; t->line_pos += 2; - + tid = TK_LE; - + buffer_copy_string(token, "(<=)"); } else { t->offset += 1; t->line_pos += 1; - + tid = TK_LT; - + buffer_copy_string(token, "(<)"); } - + break; - + case '!': if (t->input[t->offset + 1] == '=') { t->offset += 2; t->line_pos += 2; - + tid = TK_NE; - + buffer_copy_string(token, "(!=)"); } else { t->offset += 1; t->line_pos += 1; - + tid = TK_NOT; - + buffer_copy_string(token, "(!)"); } - + break; case '&': if (t->input[t->offset + 1] == '&') { t->offset += 2; t->line_pos += 2; - + tid = TK_AND; - + buffer_copy_string(token, "(&&)"); } else { - log_error_write(srv, __FILE__, __LINE__, "sds", - "pos:", t->line_pos, + log_error_write(srv, __FILE__, __LINE__, "sds", + "pos:", t->line_pos, "missing second &"); return -1; } - + break; case '|': if (t->input[t->offset + 1] == '|') { t->offset += 2; t->line_pos += 2; - + tid = TK_OR; - + buffer_copy_string(token, "(||)"); } else { - log_error_write(srv, __FILE__, __LINE__, "sds", - "pos:", t->line_pos, + log_error_write(srv, __FILE__, __LINE__, "sds", + "pos:", t->line_pos, "missing second |"); return -1; } - + break; case '\t': case ' ': t->offset++; t->line_pos++; break; - + case '\'': /* search for the terminating " */ for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++); - + if (t->input[t->offset + i]) { tid = TK_VALUE; - + buffer_copy_string_len(token, t->input + t->offset + 1, i-1); - + t->offset += i + 1; t->line_pos += i + 1; } else { /* ERROR */ - - log_error_write(srv, __FILE__, __LINE__, "sds", - "pos:", t->line_pos, + + log_error_write(srv, __FILE__, __LINE__, "sds", + "pos:", t->line_pos, "missing closing quote"); - + return -1; } - + break; case '(': t->offset++; t->in_brace++; - + tid = TK_LPARAN; - + buffer_copy_string(token, "("); break; case ')': t->offset++; t->in_brace--; - + tid = TK_RPARAN; - + buffer_copy_string(token, ")"); break; case '$': if (t->input[t->offset + 1] == '{') { for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++); - + if (t->input[t->offset + i] != '}') { - log_error_write(srv, __FILE__, __LINE__, "sds", - "pos:", t->line_pos, + log_error_write(srv, __FILE__, __LINE__, "sds", + "pos:", t->line_pos, "missing closing quote"); - + return -1; } - + buffer_copy_string_len(token, t->input + t->offset + 2, i-3); } else { for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_'; i++); - + buffer_copy_string_len(token, t->input + t->offset + 1, i-1); } - + tid = TK_VALUE; - + if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) { buffer_copy_string_buffer(token, ds->value); } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) { @@ -221,16 +221,16 @@ static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p, } else { buffer_copy_string(token, ""); } - + t->offset += i; t->line_pos += i; - + break; default: for (i = 0; isgraph(t->input[t->offset + i]); i++) { char d = t->input[t->offset + i]; switch(d) { - case ' ': + case ' ': case '\t': case ')': case '(': @@ -244,25 +244,25 @@ static int ssi_expr_tokenizer(server *srv, connection *con, plugin_data *p, break; } } - + tid = TK_VALUE; - + buffer_copy_string_len(token, t->input + t->offset, i); - + t->offset += i; t->line_pos += i; - + break; } } - + if (tid) { *token_id = tid; - + return 1; } else if (t->offset < t->size) { - log_error_write(srv, __FILE__, __LINE__, "sds", - "pos:", t->line_pos, + log_error_write(srv, __FILE__, __LINE__, "sds", + "pos:", t->line_pos, "foobar"); } return 0; @@ -275,50 +275,50 @@ int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr buffer *token; ssi_ctx_t context; int ret; - + t.input = expr; t.offset = 0; t.size = strlen(expr); t.line_pos = 1; - + t.in_key = 1; t.in_brace = 0; t.in_cond = 0; - + context.ok = 1; context.srv = srv; - + /* default context */ - + pParser = ssiexprparserAlloc( malloc ); token = buffer_init(); while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) { ssiexprparser(pParser, token_id, token, &context); - + token = buffer_init(); } ssiexprparser(pParser, 0, token, &context); ssiexprparserFree(pParser, free ); - + buffer_free(token); - + if (ret == -1) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "expr parser failed"); return -1; } - + if (context.ok == 0) { - log_error_write(srv, __FILE__, __LINE__, "sds", - "pos:", t.line_pos, + log_error_write(srv, __FILE__, __LINE__, "sds", + "pos:", t.line_pos, "parser failed somehow near here"); return -1; } #if 0 - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "expr: ", expr, context.val.bo); -#endif +#endif return context.val.bo; } diff --git a/src/mod_ssi_expr.h b/src/mod_ssi_expr.h index b484f78..2d3ae8b 100644 --- a/src/mod_ssi_expr.h +++ b/src/mod_ssi_expr.h @@ -5,16 +5,16 @@ typedef struct { enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type; - + buffer *str; int bo; } ssi_val_t; typedef struct { int ok; - + ssi_val_t val; - + void *srv; } ssi_ctx_t; diff --git a/src/mod_ssi_exprparser.c b/src/mod_ssi_exprparser.c index 65ec4dc..d049e9a 100644 --- a/src/mod_ssi_exprparser.c +++ b/src/mod_ssi_exprparser.c @@ -18,10 +18,10 @@ /* Next is all token values, in a form suitable for use by makeheaders. ** This section will be null unless lemon is run with the -m switch. */ -/* +/* ** These constants (all generated automatically by the parser generator) ** specify the various kinds of tokens (terminals) that the parser -** understands. +** understands. ** ** Each symbol here is a terminal symbol in the grammar. */ @@ -38,7 +38,7 @@ ** and nonterminals. "int" is used otherwise. ** YYNOCODE is a number of type YYCODETYPE which corresponds ** to no legal terminal or nonterminal number. This -** number is used to fill in empty slots of the hash +** number is used to fill in empty slots of the hash ** table. ** YYFALLBACK If defined, this indicates that one or more tokens ** have fall-back values which should be used if the @@ -47,7 +47,7 @@ ** and nonterminal numbers. "unsigned char" is ** used if there are fewer than 250 rules and ** states combined. "int" is used otherwise. -** ssiexprparserTOKENTYPE is the data type used for minor tokens given +** ssiexprparserTOKENTYPE is the data type used for minor tokens given ** directly to the parser from the tokenizer. ** YYMINORTYPE is the data type used for all minor tokens. ** This is typically a union of many types, one of @@ -91,7 +91,7 @@ typedef union { /* Next are that tables used to determine what action to take based on the ** current state and lookahead token. These tables are used to implement ** functions that take a state number and lookahead value and return an -** action integer. +** action integer. ** ** Suppose the action integer is N. Then the action is determined as ** follows @@ -116,7 +116,7 @@ typedef union { ** If the index value yy_shift_ofst[S]+X is out of range or if the value ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that yy_default[S] should be used instead. +** and that yy_default[S] should be used instead. ** ** The formula above is for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after @@ -168,7 +168,7 @@ static YYACTIONTYPE yy_default[] = { /* The next table maps tokens into fallback tokens. If a construct ** like the following: -** +** ** %fallback ID X Y Z. ** ** appears in the grammer, then ID becomes a fallback token for X, Y, @@ -219,10 +219,10 @@ static char *yyTracePrompt = 0; #endif /* NDEBUG */ #ifndef NDEBUG -/* +/* ** Turn parser tracing on by giving a stream to which to write the trace ** and a prompt to preface each trace message. Tracing is turned off -** by making either argument NULL +** by making either argument NULL ** ** Inputs: ** <ul> @@ -247,7 +247,7 @@ void ssiexprparserTrace(FILE *TraceFILE, char *zTracePrompt){ #ifndef NDEBUG /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ -static const char *yyTokenName[] = { +static const char *yyTokenName[] = { "$", "AND", "OR", "EQ", "NE", "GT", "GE", "LT", "LE", "NOT", "LPARAN", "RPARAN", @@ -295,7 +295,7 @@ const char *ssiexprparserTokenName(int tokenType){ #endif } -/* +/* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like ** malloc. @@ -326,7 +326,7 @@ static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){ /* Here is inserted the actions which take place when a ** terminal or non-terminal is destroyed. This can happen ** when the symbol is popped from the stack during a - ** reduce or during error processing or when a parser is + ** reduce or during error processing or when a parser is ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those @@ -379,7 +379,7 @@ static int yy_pop_parser_stack(yyParser *pParser){ return yymajor; } -/* +/* ** Deallocate and destroy a parser. Destructors are all called for ** all stack elements before shutting the parser down. ** @@ -415,7 +415,7 @@ static int yy_find_shift_action( ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */ i = yy_shift_ofst[stateno]; if( i==YY_SHIFT_USE_DFLT ){ @@ -459,7 +459,7 @@ static int yy_find_reduce_action( ){ int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - + i = yy_reduce_ofst[stateno]; if( i==YY_REDUCE_USE_DFLT ){ return yy_default[stateno]; @@ -559,7 +559,7 @@ static void yy_reduce( ssiexprparserARG_FETCH; yymsp = &yypParser->yystack[yypParser->yyidx]; #ifndef NDEBUG - if( yyTraceFILE && yyruleno>=0 + if( yyTraceFILE && yyruleno>=0 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){ fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, yyRuleName[yyruleno]); @@ -580,7 +580,7 @@ static void yy_reduce( { ctx->val.bo = ssi_val_tobool(yymsp[0].minor.yy29); ctx->val.type = SSI_TYPE_BOOL; - + ssi_val_free(yymsp[0].minor.yy29); } #line 586 "mod_ssi_exprparser.c" @@ -589,16 +589,16 @@ static void yy_reduce( #line 38 "./mod_ssi_exprparser.y" { int cmp; - - if (yymsp[-2].minor.yy29->type == SSI_TYPE_STRING && + + if (yymsp[-2].minor.yy29->type == SSI_TYPE_STRING && yymsp[0].minor.yy29->type == SSI_TYPE_STRING) { cmp = strcmp(yymsp[-2].minor.yy29->str->ptr, yymsp[0].minor.yy29->str->ptr); } else { cmp = ssi_val_tobool(yymsp[-2].minor.yy29) - ssi_val_tobool(yymsp[0].minor.yy29); } - + yygotominor.yy29 = yymsp[-2].minor.yy29; - + switch(yymsp[-1].minor.yy8) { case SSI_COND_EQ: yygotominor.yy29->bo = (cmp == 0) ? 1 : 0; break; case SSI_COND_NE: yygotominor.yy29->bo = (cmp != 0) ? 1 : 0; break; @@ -607,9 +607,9 @@ static void yy_reduce( case SSI_COND_LE: yygotominor.yy29->bo = (cmp <= 0) ? 1 : 0; break; case SSI_COND_LT: yygotominor.yy29->bo = (cmp < 0) ? 1 : 0; break; } - + yygotominor.yy29->type = SSI_TYPE_BOOL; - + ssi_val_free(yymsp[0].minor.yy29); } #line 615 "mod_ssi_exprparser.c" @@ -625,9 +625,9 @@ static void yy_reduce( #line 66 "./mod_ssi_exprparser.y" { int e; - + e = ssi_val_tobool(yymsp[-2].minor.yy29) && ssi_val_tobool(yymsp[0].minor.yy29); - + yygotominor.yy29 = yymsp[-2].minor.yy29; yygotominor.yy29->bo = e; yygotominor.yy29->type = SSI_TYPE_BOOL; @@ -640,9 +640,9 @@ static void yy_reduce( #line 77 "./mod_ssi_exprparser.y" { int e; - + e = ssi_val_tobool(yymsp[-2].minor.yy29) || ssi_val_tobool(yymsp[0].minor.yy29); - + yygotominor.yy29 = yymsp[-2].minor.yy29; yygotominor.yy29->bo = e; yygotominor.yy29->type = SSI_TYPE_BOOL; @@ -655,9 +655,9 @@ static void yy_reduce( #line 88 "./mod_ssi_exprparser.y" { int e; - + e = !ssi_val_tobool(yymsp[0].minor.yy29); - + yygotominor.yy29 = yymsp[0].minor.yy29; yygotominor.yy29->bo = e; yygotominor.yy29->type = SSI_TYPE_BOOL; @@ -872,7 +872,7 @@ void ssiexprparser( #ifdef YYERRORSYMBOL /* A syntax error has occurred. ** The response to an error depends upon whether or not the - ** grammar defines an error token "ERROR". + ** grammar defines an error token "ERROR". ** ** This is what we do if the grammar does define ERROR: ** diff --git a/src/mod_ssi_exprparser.y b/src/mod_ssi_exprparser.y index c123941..ac993d7 100644 --- a/src/mod_ssi_exprparser.y +++ b/src/mod_ssi_exprparser.y @@ -31,22 +31,22 @@ input ::= exprline(B). { ctx->val.bo = ssi_val_tobool(B); ctx->val.type = SSI_TYPE_BOOL; - + ssi_val_free(B); } exprline(A) ::= expr(B) cond(C) expr(D). { int cmp; - - if (B->type == SSI_TYPE_STRING && + + if (B->type == SSI_TYPE_STRING && D->type == SSI_TYPE_STRING) { cmp = strcmp(B->str->ptr, D->str->ptr); } else { cmp = ssi_val_tobool(B) - ssi_val_tobool(D); } - + A = B; - + switch(C) { case SSI_COND_EQ: A->bo = (cmp == 0) ? 1 : 0; break; case SSI_COND_NE: A->bo = (cmp != 0) ? 1 : 0; break; @@ -55,9 +55,9 @@ exprline(A) ::= expr(B) cond(C) expr(D). { case SSI_COND_LE: A->bo = (cmp <= 0) ? 1 : 0; break; case SSI_COND_LT: A->bo = (cmp < 0) ? 1 : 0; break; } - + A->type = SSI_TYPE_BOOL; - + ssi_val_free(D); } exprline(A) ::= expr(B). { @@ -65,9 +65,9 @@ exprline(A) ::= expr(B). { } expr(A) ::= expr(B) AND expr(C). { int e; - + e = ssi_val_tobool(B) && ssi_val_tobool(C); - + A = B; A->bo = e; A->type = SSI_TYPE_BOOL; @@ -76,9 +76,9 @@ expr(A) ::= expr(B) AND expr(C). { expr(A) ::= expr(B) OR expr(C). { int e; - + e = ssi_val_tobool(B) || ssi_val_tobool(C); - + A = B; A->bo = e; A->type = SSI_TYPE_BOOL; @@ -87,9 +87,9 @@ expr(A) ::= expr(B) OR expr(C). { expr(A) ::= NOT expr(B). { int e; - + e = !ssi_val_tobool(B); - + A = B; A->bo = e; A->type = SSI_TYPE_BOOL; diff --git a/src/mod_staticfile.c b/src/mod_staticfile.c index f5308cd..35dd279 100644 --- a/src/mod_staticfile.c +++ b/src/mod_staticfile.c @@ -16,7 +16,7 @@ /** * this is a staticfile for a lighttpd plugin - * + * */ @@ -29,48 +29,48 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *range_buf; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_staticfile_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->range_buf = buffer_init(); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_staticfile_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]; - + array_free(s->exclude_ext); - + free(s); } free(p->config_storage); } buffer_free(p->range_buf); - + free(p); - + return HANDLER_GO_ON; } @@ -79,31 +79,31 @@ FREE_FUNC(mod_staticfile_free) { SETDEFAULTS_FUNC(mod_staticfile_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->exclude_ext = array_init(); - + cv[0].destination = s->exclude_ext; - + 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; } @@ -112,27 +112,27 @@ SETDEFAULTS_FUNC(mod_staticfile_set_defaults) { static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(exclude_ext); - + /* 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("static-file.exclude-extensions"))) { PATCH(exclude_ext); } } } - + return 0; } #undef PATCH @@ -146,69 +146,69 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data * data_string *ds; stat_cache_entry *sce = NULL; buffer *content_type = NULL; - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) { SEGFAULT(); } - + start = 0; end = sce->st.st_size - 1; - + con->response.content_length = 0; - + if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) { content_type = ds->value; } - + for (s = con->request.http_range, error = 0; !error && *s && NULL != (minus = strchr(s, '-')); ) { char *err; off_t la, le; - + if (s == minus) { /* -<stop> */ - + le = strtoll(s, &err, 10); - + if (le == 0) { /* RFC 2616 - 14.35.1 */ - + con->http_status = 416; error = 1; } else if (*err == '\0') { /* end */ s = err; - + end = sce->st.st_size - 1; start = sce->st.st_size + le; } else if (*err == ',') { multipart = 1; s = err + 1; - + end = sce->st.st_size - 1; start = sce->st.st_size + le; } else { error = 1; } - + } else if (*(minus+1) == '\0' || *(minus+1) == ',') { /* <start>- */ - + la = strtoll(s, &err, 10); - + if (err == minus) { /* ok */ - + if (*(err + 1) == '\0') { s = err + 1; - + end = sce->st.st_size - 1; start = la; - + } else if (*(err + 1) == ',') { multipart = 1; s = err + 2; - + end = sce->st.st_size - 1; start = la; } else { @@ -220,64 +220,64 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data * } } else { /* <start>-<stop> */ - + la = strtoll(s, &err, 10); - + if (err == minus) { le = strtoll(minus+1, &err, 10); - + /* RFC 2616 - 14.35.1 */ if (la > le) { error = 1; } - + if (*err == '\0') { /* ok, end*/ s = err; - + end = le; start = la; } else if (*err == ',') { multipart = 1; s = err + 1; - + end = le; start = la; } else { /* error */ - + error = 1; } } else { /* error */ - + error = 1; } } - + if (!error) { if (start < 0) start = 0; - + /* RFC 2616 - 14.35.1 */ if (end > sce->st.st_size - 1) end = sce->st.st_size - 1; - + if (start > sce->st.st_size - 1) { error = 1; - + con->http_status = 416; } } - + if (!error) { if (multipart) { /* write boundary-header */ buffer *b; - + b = chunkqueue_get_append_buffer(con->write_queue); - + buffer_copy_string(b, "\r\n--"); buffer_append_string(b, boundary); - + /* write Content-Range */ buffer_append_string(b, "\r\nContent-Range: bytes "); buffer_append_off_t(b, start); @@ -285,54 +285,54 @@ static int http_response_parse_range(server *srv, connection *con, plugin_data * buffer_append_off_t(b, end); buffer_append_string(b, "/"); buffer_append_off_t(b, sce->st.st_size); - + buffer_append_string(b, "\r\nContent-Type: "); buffer_append_string_buffer(b, content_type); - + /* write END-OF-HEADER */ buffer_append_string(b, "\r\n\r\n"); - + con->response.content_length += b->used - 1; - + } - + chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1); con->response.content_length += end - start + 1; } } - + /* something went wrong */ if (error) return -1; - + if (multipart) { /* add boundary end */ buffer *b; - + b = chunkqueue_get_append_buffer(con->write_queue); - + buffer_copy_string_len(b, "\r\n--", 4); buffer_append_string(b, boundary); buffer_append_string_len(b, "--\r\n", 4); - + con->response.content_length += b->used - 1; - + /* set header-fields */ - + buffer_copy_string(p->range_buf, "multipart/byteranges; boundary="); buffer_append_string(p->range_buf, boundary); - + /* overwrite content-type */ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf)); } else { /* add Content-Range-header */ - + buffer_copy_string(p->range_buf, "bytes "); buffer_append_off_t(p->range_buf, start); buffer_append_string(p->range_buf, "-"); buffer_append_off_t(p->range_buf, end); buffer_append_string(p->range_buf, "/"); buffer_append_off_t(p->range_buf, sce->st.st_size); - + response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf)); } @@ -347,12 +347,12 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { stat_cache_entry *sce = NULL; buffer *mtime; data_string *ds; - + /* someone else has done a decision for us */ if (con->http_status != 0) return HANDLER_GO_ON; if (con->uri.path->used == 0) return HANDLER_GO_ON; if (con->physical.path->used == 0) return HANDLER_GO_ON; - + /* someone else has handled this request */ if (con->mode != DIRECT) return HANDLER_GO_ON; @@ -365,42 +365,42 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { default: return HANDLER_GO_ON; } - + mod_staticfile_patch_connection(srv, con, p); - + s_len = con->uri.path->used - 1; - + /* ignore certain extensions */ for (k = 0; k < p->conf.exclude_ext->used; k++) { - ds = (data_string *)p->conf.exclude_ext->data[k]; - + ds = (data_string *)p->conf.exclude_ext->data[k]; + if (ds->value->used == 0) continue; if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) { return HANDLER_GO_ON; } } - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file"); } - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) { con->http_status = 403; - + log_error_write(srv, __FILE__, __LINE__, "sbsb", "not a regular file:", con->uri.path, "->", con->physical.path); - + return HANDLER_FINISHED; } - + /* we only handline regular files */ #ifdef HAVE_LSTAT if ((sce->is_symlink == 1) && !con->conf.follow_symlink) { con->http_status = 403; - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied due symlink restriction"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); @@ -412,18 +412,18 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { #endif if (!S_ISREG(sce->st.st_mode)) { con->http_status = 404; - + if (con->conf.log_file_not_found) { log_error_write(srv, __FILE__, __LINE__, "sbsb", "not a regular file:", con->uri.path, "->", sce->name); } - + return HANDLER_FINISHED; } /* mod_compress might set several data directly, don't overwrite them */ - + /* set response content-type, if not set already */ if (NULL == array_get_element(con->response.headers, "Content-Type")) { @@ -433,15 +433,15 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type)); } } - + if (NULL == array_get_element(con->response.headers, "ETag")) { /* generate e-tag */ etag_mutate(con->physical.etag, sce->etag); - + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag)); } response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes")); - + /* prepare header */ if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) { mtime = strftime_cache_get(srv, sce->st.st_mtime); @@ -457,34 +457,34 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { /* check if we have a conditional GET */ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) { - /* if the value is the same as our ETag, we do a Range-request, + /* 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; } return HANDLER_FINISHED; } } - + /* if we are still here, prepare body */ - - /* we add it here for all requests - * the HEAD request will drop it afterwards again + + /* we add it here for all requests + * the HEAD request will drop it afterwards again */ http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size); - + con->file_finished = 1; - + return HANDLER_FINISHED; } @@ -493,13 +493,13 @@ URIHANDLER_FUNC(mod_staticfile_subrequest) { int mod_staticfile_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("staticfile"); - + p->init = mod_staticfile_init; p->handle_subrequest_start = mod_staticfile_subrequest; p->set_defaults = mod_staticfile_set_defaults; p->cleanup = mod_staticfile_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_status.c b/src/mod_status.c index f5a35e9..2a4003a 100644 --- a/src/mod_status.c +++ b/src/mod_status.c @@ -29,114 +29,114 @@ typedef struct { typedef struct { PLUGIN_DATA; - + double traffic_out; double requests; - + double mod_5s_traffic_out[5]; double mod_5s_requests[5]; size_t mod_5s_ndx; - + double rel_traffic_out; double rel_requests; - + double abs_traffic_out; double abs_requests; - + double bytes_written; - + buffer *module_list; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; INIT_FUNC(mod_status_init) { plugin_data *p; size_t i; - + p = calloc(1, sizeof(*p)); - + p->traffic_out = p->requests = 0; p->rel_traffic_out = p->rel_requests = 0; p->abs_traffic_out = p->abs_requests = 0; p->bytes_written = 0; p->module_list = buffer_init(); - + for (i = 0; i < 5; i++) { p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0; } - + return p; } FREE_FUNC(mod_status_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + buffer_free(p->module_list); - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; - + buffer_free(s->status_url); buffer_free(s->statistics_url); buffer_free(s->config_url); - + free(s); } free(p->config_storage); } - - + + free(p); - + return HANDLER_GO_ON; } SETDEFAULTS_FUNC(mod_status_set_defaults) { plugin_data *p = p_d; size_t i; - - config_values_t cv[] = { + + 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.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->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; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } } - + return HANDLER_GO_ON; } @@ -151,7 +151,7 @@ static int mod_status_row_append(buffer *b, const char *key, const char *value) buffer_append_string(b, value); BUFFER_APPEND_STRING_CONST(b, "</td>\n"); BUFFER_APPEND_STRING_CONST(b, " </tr>\n"); - + return 0; } @@ -161,29 +161,29 @@ static int mod_status_header_append(buffer *b, const char *key) { buffer_append_string(b, key); BUFFER_APPEND_STRING_CONST(b, "</th>\n"); BUFFER_APPEND_STRING_CONST(b, " </tr>\n"); - + return 0; } static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) { plugin_data *p = p_d; - + if (p->conf.sort) { BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">"); buffer_append_string(b, key); - BUFFER_APPEND_STRING_CONST(b, "<span class=\"sortarrow\"></span></a></th>\n"); + BUFFER_APPEND_STRING_CONST(b, "<span class=\"sortarrow\">:</span></a></th>\n"); } else { BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\">"); buffer_append_string(b, key); BUFFER_APPEND_STRING_CONST(b, "</th>\n"); } - + return 0; } static int mod_status_get_multiplier(double *avg, char *multiplier, int size) { *multiplier = ' '; - + if (*avg > size) { *avg /= size; *multiplier = 'k'; } if (*avg > size) { *avg /= size; *multiplier = 'M'; } if (*avg > size) { *avg /= size; *multiplier = 'G'; } @@ -204,19 +204,19 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c char multiplier = '\0'; char buf[32]; time_t ts; - + int days, hours, mins, seconds; - + b = chunkqueue_get_append_buffer(con->write_queue); - BUFFER_COPY_STRING_CONST(b, + BUFFER_COPY_STRING_CONST(b, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" " <head>\n" " <title>Status</title>\n"); - + BUFFER_APPEND_STRING_CONST(b, " <style type=\"text/css\">\n" " table.status { border: black solid thin; }\n" @@ -226,14 +226,14 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n" " span.sortarrow { color: white; text-decoration: none; }\n" " </style>\n"); - + if (p->conf.sort) { BUFFER_APPEND_STRING_CONST(b, "<script type=\"text/javascript\">\n" "// <!--\n" "var sort_column;\n" "var prev_span = null;\n"); - + BUFFER_APPEND_STRING_CONST(b, "function get_inner_text(el) {\n" " if((typeof el == 'string')||(typeof el == 'undefined'))\n" @@ -251,7 +251,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c " }\n" " return str;\n" "}\n"); - + BUFFER_APPEND_STRING_CONST(b, "function sortfn(a,b) {\n" " var at = get_inner_text(a.cells[sort_column]);\n" @@ -266,7 +266,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c " else return 1;\n" " }\n" "}\n"); - + BUFFER_APPEND_STRING_CONST(b, "function resort(lnk) {\n" " var span = lnk.childNodes[1];\n" @@ -276,7 +276,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c " rows[j-1] = table.rows[j];\n" " sort_column = lnk.parentNode.cellIndex;\n" " rows.sort(sortfn);\n"); - + BUFFER_APPEND_STRING_CONST(b, " if (prev_span != null) prev_span.innerHTML = '';\n" " if (span.getAttribute('sortdir')=='down') {\n" @@ -294,77 +294,77 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c "// -->\n" "</script>\n"); } - - BUFFER_APPEND_STRING_CONST(b, + + BUFFER_APPEND_STRING_CONST(b, " </head>\n" " <body>\n"); - - - + + + /* connection listing */ BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>"); - - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">"); + + BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">"); buffer_append_string_buffer(b, con->uri.authority); BUFFER_APPEND_STRING_CONST(b, " ("); buffer_append_string_buffer(b, con->server_name); BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">"); - + ts = srv->cur_ts - srv->startup_ts; - + days = ts / (60 * 60 * 24); ts %= (60 * 60 * 24); - + hours = ts / (60 * 60); ts %= (60 * 60); - + mins = ts / (60); ts %= (60); - + seconds = ts; - + if (days) { buffer_append_long(b, days); BUFFER_APPEND_STRING_CONST(b, " days "); } - + if (hours) { buffer_append_long(b, hours); BUFFER_APPEND_STRING_CONST(b, " hours "); } - + if (mins) { buffer_append_long(b, mins); BUFFER_APPEND_STRING_CONST(b, " min "); } - + buffer_append_long(b, seconds); BUFFER_APPEND_STRING_CONST(b, " s"); - + BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">"); - + ts = srv->startup_ts; - + strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts)); buffer_append_string(b, buf); BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); - - + + BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n"); - + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); avg = p->abs_requests; mod_status_get_multiplier(&avg, &multiplier, 1000); - + buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n"); - + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); avg = p->abs_traffic_out; @@ -379,7 +379,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n"); - + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); avg = p->abs_requests / (srv->cur_ts - srv->startup_ts); @@ -389,7 +389,7 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n"); - + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts); @@ -401,15 +401,15 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n"); - - + + BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n"); for (j = 0, avg = 0; j < 5; j++) { avg += p->mod_5s_requests[j]; } - + avg /= 5; - + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">"); mod_status_get_multiplier(&avg, &multiplier, 1000); @@ -417,15 +417,15 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); - + BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n"); - + for (j = 0, avg = 0; j < 5; j++) { avg += p->mod_5s_traffic_out[j]; } - + avg /= 5; - + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">"); mod_status_get_multiplier(&avg, &multiplier, 1024); @@ -435,34 +435,34 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c BUFFER_APPEND_STRING_CONST(b, " "); if (multiplier) buffer_append_string_len(b, &multiplier, 1); BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n"); - + BUFFER_APPEND_STRING_CONST(b, "</table>\n"); - - + + BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n"); BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n"); BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n"); BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n"); BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n"); - + BUFFER_APPEND_STRING_CONST(b, "<b>"); buffer_append_long(b, srv->conns->used); BUFFER_APPEND_STRING_CONST(b, " connections</b>\n"); - + for (j = 0; j < srv->conns->used; j++) { connection *c = srv->conns->ptr[j]; const char *state = connection_get_short_state(c->state); - + buffer_append_string_len(b, state, 1); - + if (((j + 1) % 50) == 0) { BUFFER_APPEND_STRING_CONST(b, "\n"); } } - + BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n"); - - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n"); + + BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">\n"); BUFFER_APPEND_STRING_CONST(b, "<tr>"); mod_status_header_append_sort(b, p_d, "Client IP"); mod_status_header_append_sort(b, p_d, "Read"); @@ -473,16 +473,16 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c mod_status_header_append_sort(b, p_d, "URI"); mod_status_header_append_sort(b, p_d, "File"); BUFFER_APPEND_STRING_CONST(b, "</tr>\n"); - + for (j = 0; j < srv->conns->used; j++) { connection *c = srv->conns->ptr[j]; - + BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">"); - + buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr))); - + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); - + if (con->request.content_length) { buffer_append_long(b, c->request_content_queue->bytes_in); BUFFER_APPEND_STRING_CONST(b, "/"); @@ -490,55 +490,55 @@ static handler_t mod_status_handle_server_status_html(server *srv, connection *c } else { BUFFER_APPEND_STRING_CONST(b, "0/0"); } - + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); - + buffer_append_off_t(b, chunkqueue_written(c->write_queue)); BUFFER_APPEND_STRING_CONST(b, "/"); buffer_append_off_t(b, chunkqueue_length(c->write_queue)); - + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); - + buffer_append_string(b, connection_get_state(c->state)); - + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">"); - + buffer_append_long(b, srv->cur_ts - c->request_start); - + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); - + if (buffer_is_empty(c->server_name)) { buffer_append_string_buffer(b, c->uri.authority); } else { buffer_append_string_buffer(b, c->server_name); } - + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); - + if (!buffer_is_empty(c->uri.path)) { buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML); } - + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">"); - + buffer_append_string_buffer(b, c->physical.path); - + BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n"); } - - - BUFFER_APPEND_STRING_CONST(b, + + + BUFFER_APPEND_STRING_CONST(b, "</table>\n"); - - - BUFFER_APPEND_STRING_CONST(b, + + + BUFFER_APPEND_STRING_CONST(b, " </body>\n" "</html>\n" ); - + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); - + return 0; } @@ -548,7 +548,7 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c buffer *b; double avg; time_t ts; - + b = chunkqueue_get_append_buffer(con->write_queue); /* output total number of requests */ @@ -556,19 +556,19 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c avg = p->abs_requests; buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, "\n"); - + /* output total traffic out in kbytes */ BUFFER_APPEND_STRING_CONST(b, "Total kBytes: "); avg = p->abs_traffic_out / 1024; buffer_append_long(b, avg); BUFFER_APPEND_STRING_CONST(b, "\n"); - + /* output uptime */ BUFFER_APPEND_STRING_CONST(b, "Uptime: "); ts = srv->cur_ts - srv->startup_ts; buffer_append_long(b, ts); BUFFER_APPEND_STRING_CONST(b, "\n"); - + /* output busy servers */ BUFFER_APPEND_STRING_CONST(b, "BusyServers: "); buffer_append_long(b, srv->conns->used); @@ -577,13 +577,13 @@ static handler_t mod_status_handle_server_status_text(server *srv, connection *c /* set text/plain output */ response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain")); - + 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; + buffer *b = p->module_list; size_t i; array *st = srv->status; @@ -591,10 +591,10 @@ static handler_t mod_status_handle_server_statistics(server *srv, connection *co /* 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++) { @@ -605,27 +605,27 @@ static handler_t mod_status_handle_server_statistics(server *srv, connection *co 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"))) { mod_status_handle_server_status_text(srv, con, p_d); } else { mod_status_handle_server_status_html(srv, con, p_d); } - + con->http_status = 200; con->file_finished = 1; - + return HANDLER_FINISHED; } @@ -634,9 +634,9 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v plugin_data *p = p_d; buffer *b, *m = p->module_list; size_t i; - - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = - { + + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] = + { /* - poll is most reliable * - select works everywhere * - linux-* are experimental @@ -661,10 +661,10 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v #endif { FDEVENT_HANDLER_UNSET, NULL } }; - + b = chunkqueue_get_append_buffer(con->write_queue); - - BUFFER_COPY_STRING_CONST(b, + + BUFFER_COPY_STRING_CONST(b, "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n" " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" @@ -674,8 +674,8 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v " </head>\n" " <body>\n" " <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n" - " <table border=\"1\">\n"); - + " <table summary=\"status\" border=\"1\">\n"); + mod_status_header_append(b, "Server-Features"); #ifdef HAVE_PCRE_H mod_status_row_append(b, "RegEx Conditionals", "enabled"); @@ -683,21 +683,21 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing"); #endif mod_status_header_append(b, "Network Engine"); - + for (i = 0; event_handlers[i].name; i++) { if (event_handlers[i].et == srv->event_handler) { mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name); break; } } - + mod_status_header_append(b, "Config-File-Settings"); - + for (i = 0; i < srv->plugins.used; i++) { plugin **ps = srv->plugins.ptr; - + plugin *pl = ps[i]; - + if (i == 0) { buffer_copy_string_buffer(m, pl->name); } else { @@ -705,21 +705,21 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v buffer_append_string_buffer(m, pl->name); } } - + mod_status_row_append(b, "Loaded Modules", m->ptr); - + BUFFER_APPEND_STRING_CONST(b, " </table>\n"); - - BUFFER_APPEND_STRING_CONST(b, + + BUFFER_APPEND_STRING_CONST(b, " </body>\n" "</html>\n" ); - + response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html")); - + con->http_status = 200; con->file_finished = 1; - + return HANDLER_FINISHED; } @@ -728,24 +728,24 @@ static handler_t mod_status_handle_server_config(server *srv, connection *con, v static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + 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++) { 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("status.status-url"))) { PATCH(status_url); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) { @@ -754,88 +754,88 @@ static int mod_status_patch_connection(server *srv, connection *con, plugin_data PATCH(sort); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) { PATCH(statistics_url); - } + } } } - + return 0; } static handler_t mod_status_handler(server *srv, connection *con, void *p_d) { plugin_data *p = p_d; - + mod_status_patch_connection(srv, con, p); - - if (!buffer_is_empty(p->conf.status_url) && + + if (!buffer_is_empty(p->conf.status_url) && buffer_is_equal(p->conf.status_url, con->uri.path)) { return mod_status_handle_server_status(srv, con, p_d); - } else if (!buffer_is_empty(p->conf.config_url) && + } 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) && + } 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; } TRIGGER_FUNC(mod_status_trigger) { plugin_data *p = p_d; size_t i; - + /* check all connections */ for (i = 0; i < srv->conns->used; i++) { connection *c = srv->conns->ptr[i]; - + p->bytes_written += c->bytes_written_cur_second; } - + /* a sliding average */ p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written; p->mod_5s_requests [p->mod_5s_ndx] = p->requests; - + p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5; - + p->abs_traffic_out += p->bytes_written; p->rel_traffic_out += p->bytes_written; - + p->bytes_written = 0; - + /* reset storage - second */ p->traffic_out = 0; p->requests = 0; - + return HANDLER_GO_ON; } REQUESTDONE_FUNC(mod_status_account) { plugin_data *p = p_d; - + UNUSED(srv); p->requests++; p->rel_requests++; p->abs_requests++; - + p->bytes_written += con->bytes_written_cur_second; - + return HANDLER_GO_ON; } int mod_status_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("status"); - + p->init = mod_status_init; p->cleanup = mod_status_free; p->set_defaults= mod_status_set_defaults; - + p->handle_uri_clean = mod_status_handler; p->handle_trigger = mod_status_trigger; p->handle_request_done = mod_status_account; - + p->data = NULL; - + return 0; } diff --git a/src/mod_trigger_b4_dl.c b/src/mod_trigger_b4_dl.c index 8281ec0..bc49b1e 100644 --- a/src/mod_trigger_b4_dl.c +++ b/src/mod_trigger_b4_dl.c @@ -24,18 +24,18 @@ /** * this is a trigger_b4_dl for a lighttpd plugin - * + * */ /* plugin config for all request/connections */ typedef struct { buffer *db_filename; - + buffer *trigger_url; buffer *download_url; buffer *deny_url; - + array *mc_hosts; buffer *mc_namespace; #if defined(HAVE_PCRE_H) @@ -46,58 +46,58 @@ typedef struct { GDBM_FILE db; #endif -#if defined(HAVE_MEMCACHE_H) +#if defined(HAVE_MEMCACHE_H) struct memcache *mc; #endif - + unsigned short trigger_timeout; unsigned short debug; } plugin_config; typedef struct { PLUGIN_DATA; - + buffer *tmp_buf; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_trigger_b4_dl_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->tmp_buf = buffer_init(); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_trigger_b4_dl_free) { plugin_data *p = p_d; - + UNUSED(srv); if (!p) return HANDLER_GO_ON; - + if (p->config_storage) { size_t i; for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; if (!s) continue; - + buffer_free(s->db_filename); buffer_free(s->download_url); buffer_free(s->trigger_url); buffer_free(s->deny_url); - + buffer_free(s->mc_namespace); array_free(s->mc_hosts); - + #if defined(HAVE_PCRE_H) if (s->trigger_regex) pcre_free(s->trigger_regex); if (s->download_regex) pcre_free(s->download_regex); @@ -108,16 +108,16 @@ FREE_FUNC(mod_trigger_b4_dl_free) { #if defined(HAVE_MEMCACHE_H) if (s->mc) mc_free(s->mc); #endif - + free(s); } free(p->config_storage); } - + buffer_free(p->tmp_buf); - + free(p); - + return HANDLER_GO_ON; } @@ -126,9 +126,9 @@ FREE_FUNC(mod_trigger_b4_dl_free) { SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - - config_values_t cv[] = { + + + config_values_t cv[] = { { "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ @@ -139,18 +139,18 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) { { "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; #if defined(HAVE_PCRE_H) const char *errptr; int erroff; #endif - + s = calloc(1, sizeof(plugin_config)); s->db_filename = buffer_init(); s->download_url = buffer_init(); @@ -158,7 +158,7 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) { s->deny_url = buffer_init(); s->mc_hosts = array_init(); s->mc_namespace = buffer_init(); - + cv[0].destination = s->db_filename; cv[1].destination = s->trigger_url; cv[2].destination = s->download_url; @@ -167,41 +167,41 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) { cv[5].destination = s->mc_hosts; cv[6].destination = s->mc_namespace; cv[7].destination = &(s->debug); - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } #if defined(HAVE_GDBM_H) if (!buffer_is_empty(s->db_filename)) { if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "gdbm-open failed"); return HANDLER_ERROR; } } #endif -#if defined(HAVE_PCRE_H) +#if defined(HAVE_PCRE_H) if (!buffer_is_empty(s->download_url)) { if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr, 0, &errptr, &erroff, NULL))) { - - log_error_write(srv, __FILE__, __LINE__, "sbss", - "compiling regex for download-url failed:", + + log_error_write(srv, __FILE__, __LINE__, "sbss", + "compiling regex for download-url failed:", s->download_url, "pos:", erroff); return HANDLER_ERROR; } } - + if (!buffer_is_empty(s->trigger_url)) { if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr, 0, &errptr, &erroff, NULL))) { - - log_error_write(srv, __FILE__, __LINE__, "sbss", - "compiling regex for trigger-url failed:", + + log_error_write(srv, __FILE__, __LINE__, "sbss", + "compiling regex for trigger-url failed:", s->trigger_url, "pos:", erroff); - + return HANDLER_ERROR; } } @@ -211,33 +211,33 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) { #if defined(HAVE_MEMCACHE_H) size_t k; s->mc = mc_new(); - + for (k = 0; k < s->mc_hosts->used; k++) { data_string *ds = (data_string *)s->mc_hosts->data[k]; - + if (0 != mc_server_add4(s->mc, ds->value->ptr)) { - log_error_write(srv, __FILE__, __LINE__, "sb", - "connection to host failed:", + log_error_write(srv, __FILE__, __LINE__, "sb", + "connection to host failed:", ds->value); - + return HANDLER_ERROR; } } #else - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting"); return HANDLER_ERROR; #endif } - + #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H) - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "(either gdbm or libmemcache) and pcre are require, but were not found, aborting"); return HANDLER_ERROR; #endif } - + return HANDLER_GO_ON; } @@ -246,14 +246,14 @@ SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) { static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + #if defined(HAVE_GDBM) PATCH(db); -#endif +#endif #if defined(HAVE_PCRE_H) PATCH(download_regex); PATCH(trigger_regex); -#endif +#endif PATCH(trigger_timeout); PATCH(deny_url); PATCH(mc_namespace); @@ -261,15 +261,15 @@ static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plug #if defined(HAVE_MEMCACHE_H) PATCH(mc); #endif - + /* 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]; @@ -301,7 +301,7 @@ static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plug } } } - + return 0; } #undef PATCH @@ -315,20 +315,20 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { int n; # define N 10 int ovec[N * 3]; - + if (con->uri.path->used == 0) return HANDLER_GO_ON; - + mod_trigger_b4_dl_patch_connection(srv, con, p); - + if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON; - + # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H) return HANDLER_GO_ON; # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H) if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON; if (p->conf.db && p->conf.mc) { /* can't decide which one */ - + return HANDLER_GO_ON; } # elif defined(HAVE_GDBM_H) @@ -336,12 +336,12 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { # else if (!p->conf.mc) return HANDLER_GO_ON; # endif - + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) { /* X-Forwarded-For contains the ip behind the proxy */ - + remote_ip = ds->value->ptr; - + /* memcache can't handle spaces */ } else { remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr)); @@ -350,13 +350,13 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip); } - + /* check if URL is a trigger -> insert IP into DB */ if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { log_error_write(srv, __FILE__, __LINE__, "sd", "execution error while matching:", n); - + return HANDLER_ERROR; } } else { @@ -364,34 +364,34 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { if (p->conf.db) { /* the trigger matched */ datum key, val; - + key.dptr = (char *)remote_ip; key.dsize = strlen(remote_ip); - + val.dptr = (char *)&(srv->cur_ts); val.dsize = sizeof(srv->cur_ts); - + if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) { log_error_write(srv, __FILE__, __LINE__, "s", "insert failed"); } } # endif -# if defined(HAVE_MEMCACHE_H) +# if defined(HAVE_MEMCACHE_H) if (p->conf.mc) { size_t i; buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace); buffer_append_string(p->tmp_buf, remote_ip); - + for (i = 0; i < p->tmp_buf->used - 1; i++) { if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-'; } - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf); } - if (0 != mc_set(p->conf.mc, + if (0 != mc_set(p->conf.mc, CONST_BUF_LEN(p->tmp_buf), (char *)&(srv->cur_ts), sizeof(srv->cur_ts), p->conf.trigger_timeout, 0)) { @@ -401,7 +401,7 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { } # endif } - + /* check if URL is a download -> check IP in DB, update timestamp */ if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) { if (n != PCRE_ERROR_NOMATCH) { @@ -411,93 +411,93 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { } } else { /* the download uri matched */ -# if defined(HAVE_GDBM_H) +# if defined(HAVE_GDBM_H) if (p->conf.db) { datum key, val; time_t last_hit; - + key.dptr = (char *)remote_ip; key.dsize = strlen(remote_ip); - + val = gdbm_fetch(p->conf.db, key); - + if (val.dptr == NULL) { /* not found, redirect */ - + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url)); - + con->http_status = 307; - + return HANDLER_FINISHED; } - + last_hit = *(time_t *)(val.dptr); - + free(val.dptr); - + if (srv->cur_ts - last_hit > p->conf.trigger_timeout) { /* found, but timeout, redirect */ - + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url)); con->http_status = 307; - + if (p->conf.db) { if (0 != gdbm_delete(p->conf.db, key)) { log_error_write(srv, __FILE__, __LINE__, "s", "delete failed"); } } - + return HANDLER_FINISHED; } - + val.dptr = (char *)&(srv->cur_ts); val.dsize = sizeof(srv->cur_ts); - + if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) { log_error_write(srv, __FILE__, __LINE__, "s", "insert failed"); } } # endif - -# if defined(HAVE_MEMCACHE_H) + +# if defined(HAVE_MEMCACHE_H) if (p->conf.mc) { void *r; size_t i; - + buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace); buffer_append_string(p->tmp_buf, remote_ip); - + for (i = 0; i < p->tmp_buf->used - 1; i++) { if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-'; } - + if (p->conf.debug) { log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf); } /** - * + * * memcached is do expiration for us, as long as we can fetch it every thing is ok - * and the timestamp is updated - * + * and the timestamp is updated + * */ - if (NULL == (r = mc_aget(p->conf.mc, + if (NULL == (r = mc_aget(p->conf.mc, CONST_BUF_LEN(p->tmp_buf) ))) { - + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url)); - + con->http_status = 307; - + return HANDLER_FINISHED; } - + free(r); - + /* set a new timeout */ - if (0 != mc_set(p->conf.mc, + if (0 != mc_set(p->conf.mc, CONST_BUF_LEN(p->tmp_buf), (char *)&(srv->cur_ts), sizeof(srv->cur_ts), p->conf.trigger_timeout, 0)) { @@ -507,13 +507,13 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { } # endif } - + #else UNUSED(srv); UNUSED(con); UNUSED(p_d); #endif - + return HANDLER_GO_ON; } @@ -521,21 +521,21 @@ URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) { TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) { plugin_data *p = p_d; size_t i; - + /* check DB each minute */ if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON; - + /* cleanup */ for (i = 0; i < srv->config_context->used; i++) { plugin_config *s = p->config_storage[i]; datum key, val, okey; - + if (!s->db) continue; - + okey.dptr = NULL; - - /* according to the manual this loop + delete does delete all entries on its way - * + + /* according to the manual this loop + delete does delete all entries on its way + * * we don't care as the next round will remove them. We don't have to perfect here. */ for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) { @@ -544,21 +544,21 @@ TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) { free(okey.dptr); okey.dptr = NULL; } - + val = gdbm_fetch(s->db, key); - + last_hit = *(time_t *)(val.dptr); - + free(val.dptr); - + if (srv->cur_ts - last_hit > s->trigger_timeout) { gdbm_delete(s->db, key); } - + okey = key; } if (okey.dptr) free(okey.dptr); - + /* reorg once a day */ if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db); } @@ -571,7 +571,7 @@ TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) { int mod_trigger_b4_dl_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("trigger_b4_dl"); - + p->init = mod_trigger_b4_dl_init; p->handle_uri_clean = mod_trigger_b4_dl_uri_handler; p->set_defaults = mod_trigger_b4_dl_set_defaults; @@ -579,8 +579,8 @@ int mod_trigger_b4_dl_plugin_init(plugin *p) { p->handle_trigger = mod_trigger_b4_dl_handle_trigger; #endif p->cleanup = mod_trigger_b4_dl_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_userdir.c b/src/mod_userdir.c index 9612fa8..2fef0f2 100644 --- a/src/mod_userdir.c +++ b/src/mod_userdir.c @@ -25,54 +25,54 @@ typedef struct { typedef struct { PLUGIN_DATA; - + buffer *username; buffer *temp_path; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_userdir_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + p->username = buffer_init(); p->temp_path = buffer_init(); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_userdir_free) { plugin_data *p = p_d; - + 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]; - + array_free(s->include_user); array_free(s->exclude_user); buffer_free(s->path); buffer_free(s->basepath); - + free(s); } free(p->config_storage); } - + buffer_free(p->username); buffer_free(p->temp_path); - + free(p); - + return HANDLER_GO_ON; } @@ -81,40 +81,40 @@ FREE_FUNC(mod_userdir_free) { SETDEFAULTS_FUNC(mod_userdir_set_defaults) { plugin_data *p = p_d; size_t i; - - config_values_t cv[] = { + + config_values_t cv[] = { { "userdir.path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ { "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */ { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->exclude_user = array_init(); s->include_user = array_init(); s->path = buffer_init(); s->basepath = buffer_init(); - + cv[0].destination = s->path; cv[1].destination = s->exclude_user; cv[2].destination = s->include_user; cv[3].destination = s->basepath; - + 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; } @@ -123,24 +123,24 @@ SETDEFAULTS_FUNC(mod_userdir_set_defaults) { static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(path); PATCH(exclude_user); PATCH(include_user); PATCH(basepath); - + /* 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("userdir.path"))) { PATCH(path); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) { @@ -152,7 +152,7 @@ static int mod_userdir_patch_connection(server *srv, connection *con, plugin_dat } } } - + return 0; } #undef PATCH @@ -169,18 +169,18 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) { if (con->uri.path->used == 0) return HANDLER_GO_ON; mod_userdir_patch_connection(srv, con, p); - + uri_len = con->uri.path->used - 1; - + /* /~user/foo.html -> /home/user/public_html/foo.html */ - + if (con->uri.path->ptr[0] != '/' || con->uri.path->ptr[1] != '~') return HANDLER_GO_ON; - + if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) { /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */ http_response_redirect_to_directory(srv, con); - + return HANDLER_FINISHED; } @@ -188,10 +188,10 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) { if (0 == rel_url - (con->uri.path->ptr + 2)) { return HANDLER_GO_ON; } - + buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2)); - - if (buffer_is_empty(p->conf.basepath) + + if (buffer_is_empty(p->conf.basepath) #ifdef HAVE_PWD_H && NULL == (pwd = getpwnam(p->username->ptr)) #endif @@ -200,31 +200,31 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) { return HANDLER_GO_ON; } - + for (k = 0; k < p->conf.exclude_user->used; k++) { data_string *ds = (data_string *)p->conf.exclude_user->data[k]; - + if (buffer_is_equal(ds->value, p->username)) { /* user in exclude list */ return HANDLER_GO_ON; } } - + if (p->conf.include_user->used) { int found_user = 0; for (k = 0; k < p->conf.include_user->used; k++) { data_string *ds = (data_string *)p->conf.include_user->data[k]; - + if (buffer_is_equal(ds->value, p->username)) { /* user in include list */ found_user = 1; break; } } - + if (!found_user) return HANDLER_GO_ON; } - + /* we build the physical path */ if (buffer_is_empty(p->conf.basepath)) { @@ -256,16 +256,16 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) { buffer_append_string_buffer(p->temp_path, p->username); } BUFFER_APPEND_SLASH(p->temp_path); - buffer_append_string_buffer(p->temp_path, p->conf.path); + buffer_append_string_buffer(p->temp_path, p->conf.path); if (buffer_is_empty(p->conf.basepath)) { struct stat st; int ret; - + ret = stat(p->temp_path->ptr, &st); if (ret < 0 || S_ISDIR(st.st_mode) != 1) { return HANDLER_GO_ON; - } + } } BUFFER_APPEND_SLASH(p->temp_path); @@ -282,13 +282,13 @@ URIHANDLER_FUNC(mod_userdir_docroot_handler) { int mod_userdir_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("userdir"); - + p->init = mod_userdir_init; p->handle_physical = mod_userdir_docroot_handler; p->set_defaults = mod_userdir_set_defaults; p->cleanup = mod_userdir_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_usertrack.c b/src/mod_usertrack.c index d3314c2..fb1839d 100644 --- a/src/mod_usertrack.c +++ b/src/mod_usertrack.c @@ -24,44 +24,44 @@ typedef struct { typedef struct { PLUGIN_DATA; - + plugin_config **config_storage; - - plugin_config conf; + + plugin_config conf; } plugin_data; /* init the plugin data */ INIT_FUNC(mod_usertrack_init) { plugin_data *p; - + p = calloc(1, sizeof(*p)); - + return p; } /* detroy the plugin data */ FREE_FUNC(mod_usertrack_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]; - + buffer_free(s->cookie_name); buffer_free(s->cookie_domain); - + free(s); } free(p->config_storage); } - + free(p); - + return HANDLER_GO_ON; } @@ -70,38 +70,38 @@ FREE_FUNC(mod_usertrack_free) { SETDEFAULTS_FUNC(mod_usertrack_set_defaults) { plugin_data *p = p_d; size_t i = 0; - - config_values_t cv[] = { + + config_values_t cv[] = { { "usertrack.cookie-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */ { "usertrack.cookie-max-age", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */ { "usertrack.cookie-domain", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */ - - { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION }, + + { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION }, { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } }; - + if (!p) return HANDLER_ERROR; - + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *)); - + for (i = 0; i < srv->config_context->used; i++) { plugin_config *s; - + s = calloc(1, sizeof(plugin_config)); s->cookie_name = buffer_init(); s->cookie_domain = buffer_init(); s->cookie_max_age = 0; - + cv[0].destination = s->cookie_name; cv[1].destination = &(s->cookie_max_age); cv[2].destination = s->cookie_domain; - + p->config_storage[i] = s; - + if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) { return HANDLER_ERROR; } - + if (buffer_is_empty(s->cookie_name)) { buffer_copy_string(s->cookie_name, "TRACKID"); } else { @@ -109,30 +109,30 @@ SETDEFAULTS_FUNC(mod_usertrack_set_defaults) { for (j = 0; j < s->cookie_name->used - 1; j++) { char c = s->cookie_name->ptr[j] | 32; if (c < 'a' || c > 'z') { - log_error_write(srv, __FILE__, __LINE__, "sb", - "invalid character in usertrack.cookie-name:", + log_error_write(srv, __FILE__, __LINE__, "sb", + "invalid character in usertrack.cookie-name:", s->cookie_name); - + return HANDLER_ERROR; } } } - + if (!buffer_is_empty(s->cookie_domain)) { size_t j; for (j = 0; j < s->cookie_domain->used - 1; j++) { char c = s->cookie_domain->ptr[j]; if (c <= 32 || c >= 127 || c == '"' || c == '\\') { - log_error_write(srv, __FILE__, __LINE__, "sb", - "invalid character in usertrack.cookie-domain:", + log_error_write(srv, __FILE__, __LINE__, "sb", + "invalid character in usertrack.cookie-domain:", s->cookie_domain); - + return HANDLER_ERROR; } } } } - + return HANDLER_GO_ON; } @@ -141,23 +141,23 @@ SETDEFAULTS_FUNC(mod_usertrack_set_defaults) { static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) { size_t i, j; plugin_config *s = p->config_storage[0]; - + PATCH(cookie_name); PATCH(cookie_domain); PATCH(cookie_max_age); - + /* 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("usertrack.cookie-name"))) { PATCH(cookie_name); } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) { @@ -167,7 +167,7 @@ static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_d } } } - + return 0; } #undef PATCH @@ -178,38 +178,38 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) { unsigned char h[16]; MD5_CTX Md5Ctx; char hh[32]; - + if (con->uri.path->used == 0) return HANDLER_GO_ON; - + mod_usertrack_patch_connection(srv, con, p); - + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) { char *g; /* we have a cookie, does it contain a valid name ? */ - - /* parse the cookie - * + + /* parse the cookie + * * check for cookiename + (WS | '=') - * + * */ - + if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) { char *nc; - + /* skip WS */ for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++); - + if (*nc == '=') { /* ok, found the key of our own cookie */ - + if (strlen(nc) > 32) { /* i'm lazy */ return HANDLER_GO_ON; } } } - } - + } + /* set a cookie */ if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) { ds = data_response_init(); @@ -217,39 +217,39 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) { buffer_copy_string(ds->key, "Set-Cookie"); buffer_copy_string_buffer(ds->value, p->conf.cookie_name); buffer_append_string(ds->value, "="); - + /* taken from mod_auth.c */ - + /* generate shared-secret */ MD5_Init(&Md5Ctx); MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1); MD5_Update(&Md5Ctx, (unsigned char *)"+", 1); - + /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */ ltostr(hh, srv->cur_ts); MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); ltostr(hh, rand()); MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh)); - + MD5_Final(h, &Md5Ctx); - + buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX); buffer_append_string(ds->value, "; Path=/"); buffer_append_string(ds->value, "; Version=1"); - + if (!buffer_is_empty(p->conf.cookie_domain)) { buffer_append_string(ds->value, "; Domain="); buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI); } - + if (p->conf.cookie_max_age) { buffer_append_string(ds->value, "; max-age="); buffer_append_long(ds->value, p->conf.cookie_max_age); } - + array_insert_unique(con->response.headers, (data_unset *)ds); - + return HANDLER_GO_ON; } @@ -258,13 +258,13 @@ URIHANDLER_FUNC(mod_usertrack_uri_handler) { int mod_usertrack_plugin_init(plugin *p) { p->version = LIGHTTPD_VERSION_ID; p->name = buffer_init_string("usertrack"); - + p->init = mod_usertrack_init; p->handle_uri_clean = mod_usertrack_uri_handler; p->set_defaults = mod_usertrack_set_defaults; p->cleanup = mod_usertrack_free; - + p->data = NULL; - + return 0; } diff --git a/src/mod_webdav.c b/src/mod_webdav.c index 3fd021f..572a7b6 100644 --- a/src/mod_webdav.c +++ b/src/mod_webdav.c @@ -23,7 +23,7 @@ #include <sqlite3.h> #endif -#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H) +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_UUID_H) #define USE_LOCKS #include <uuid/uuid.h> #endif @@ -48,7 +48,8 @@ * */ - +#define WEBDAV_FILE_MODE S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH +#define WEBDAV_DIR_MODE S_IRWXU | S_IRWXG | S_IRWXO /* plugin config for all request/connections */ @@ -207,7 +208,9 @@ SETDEFAULTS_FUNC(mod_webdav_set_defaults) { char *err; if (SQLITE_OK != sqlite3_open(s->sqlite_db_name->ptr, &(s->sql))) { - log_error_write(srv, __FILE__, __LINE__, "s", "sqlite3_open failed"); + log_error_write(srv, __FILE__, __LINE__, "sbs", "sqlite3_open failed for", + s->sqlite_db_name, + sqlite3_errmsg(s->sql)); return HANDLER_ERROR; } @@ -661,14 +664,14 @@ static int webdav_delete_dir(server *srv, connection *con, plugin_data *p, physi static int webdav_copy_file(server *srv, connection *con, plugin_data *p, physical *src, physical *dst, int overwrite) { stream s; int status = 0, ofd; - + UNUSED(srv); UNUSED(con); if (stream_open(&s, src->path)) { return 403; } - if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) { + if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), WEBDAV_FILE_MODE))) { /* opening the destination failed for some reason */ switch(errno) { case EEXIST: @@ -773,7 +776,7 @@ static int webdav_copy_dir(server *srv, connection *con, plugin_data *p, physica /* why ? */ } else if (S_ISDIR(st.st_mode)) { /* a directory */ - if (-1 == mkdir(d.path->ptr, 0700) && + if (-1 == mkdir(d.path->ptr, WEBDAV_DIR_MODE) && errno != EEXIST) { /* WTH ? */ } else { @@ -1148,31 +1151,32 @@ int webdav_lockdiscovery(server *srv, connection *con, * */ int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) { + UNUSED(srv); int has_lock = 1; #ifdef USE_LOCKS data_string *ds; /** - * If can have - * - <lock-token> - * - [etag] - * - * there is NOT, AND and OR - * and a list can be tagged - * - * (<lock-token>) is untagged - * <tag> (<lock-token>) is tagged - * - * as long as we don't handle collections it is simple. :) + * This implementation is more fake than real + * we need a parser for the If: header to really handle the full scope * * X-Litmus: locks: 11 (owner_modify) * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>) + * - a tagged check: + * if http://127.0.0.1:1025/dav/litmus/lockme is locked with + * opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1, go on * * X-Litmus: locks: 16 (fail_cond_put) * If: (<DAV:no-lock> ["-1622396671"]) + * - untagged: + * go on if the resource has the etag [...] and the lock */ if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) { + /* Ooh, ooh. A if tag, now the fun begins. + * + * this can only work with a real parser + **/ } else { /* we didn't provided a lock-token -> */ /* if the resource is locked -> 423 */ @@ -1493,7 +1497,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { /* let's create the directory */ - if (-1 == mkdir(con->physical.path->ptr, 0700)) { + if (-1 == mkdir(con->physical.path->ptr, WEBDAV_DIR_MODE)) { switch(errno) { case EPERM: con->http_status = 403; @@ -1651,7 +1655,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { return HANDLER_FINISHED; } - if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) { + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, WEBDAV_FILE_MODE))) { switch (errno) { case ENOENT: con->http_status = 404; /* not found */ @@ -1675,9 +1679,9 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { /* take what we have in the request-body and write it to a file */ /* if the file doesn't exist, create it */ - if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) { + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, WEBDAV_FILE_MODE))) { if (errno == ENOENT && - -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH))) { + -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, WEBDAV_FILE_MODE))) { /* we can't open the file */ con->http_status = 403; @@ -1883,7 +1887,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { /* src is a directory */ if (-1 == stat(p->physical.path->ptr, &st)) { - if (-1 == mkdir(p->physical.path->ptr, 0700)) { + if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) { con->http_status = 403; return HANDLER_FINISHED; } @@ -1894,7 +1898,7 @@ URIHANDLER_FUNC(mod_webdav_subrequest_handler) { return HANDLER_FINISHED; } else { unlink(p->physical.path->ptr); - if (-1 == mkdir(p->physical.path->ptr, 0700)) { + if (-1 == mkdir(p->physical.path->ptr, WEBDAV_DIR_MODE)) { con->http_status = 403; return HANDLER_FINISHED; } @@ -2202,7 +2206,7 @@ propmatch_cleanup: if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) { xmlNode *lockinfo; - const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL; + const xmlChar *lockscope = NULL, *locktype = NULL; /* TODO: compiler says unused: *owner = NULL; */ for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) { if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) { @@ -2306,12 +2310,12 @@ propmatch_cleanup: SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, - lockscope, + (const char *)lockscope, xmlStrlen(lockscope), SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 4, - locktype, + (const char *)locktype, xmlStrlen(locktype), SQLITE_TRANSIENT); @@ -2332,7 +2336,7 @@ propmatch_cleanup: } /* looks like we survived */ - webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth); + webdav_lockdiscovery(srv, con, p->tmp_buf, (const char *)lockscope, (const char *)locktype, depth); con->http_status = 201; con->file_finished = 1; diff --git a/src/network.c b/src/network.c index 5b21b83..ba024aa 100644 --- a/src/network.c +++ b/src/network.c @@ -21,9 +21,9 @@ #include "sys-socket.h" #ifdef USE_OPENSSL -# include <openssl/ssl.h> -# include <openssl/err.h> -# include <openssl/rand.h> +# include <openssl/ssl.h> +# include <openssl/err.h> +# include <openssl/rand.h> #endif handler_t network_server_handle_fdevent(void *s, void *context, int revents) { @@ -31,11 +31,11 @@ handler_t network_server_handle_fdevent(void *s, void *context, int revents) { server_socket *srv_socket = (server_socket *)context; connection *con; int loops = 0; - + UNUSED(context); - + if (revents != FDEVENT_IN) { - log_error_write(srv, __FILE__, __LINE__, "sdd", + log_error_write(srv, __FILE__, __LINE__, "sdd", "strange event for server socket", srv_socket->fd, revents); @@ -44,12 +44,12 @@ handler_t network_server_handle_fdevent(void *s, void *context, int revents) { /* accept()s at most 100 connections directly * - * we jump out after 100 to give the waiting connections a chance */ + * we jump out after 100 to give the waiting connections a chance */ for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) { handler_t r; - + connection_state_machine(srv, con); - + switch(r = plugins_call_handle_joblist(srv, con)) { case HANDLER_FINISHED: case HANDLER_GO_ON: @@ -72,7 +72,7 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { buffer *b; int is_unix_domain_socket = 0; int fd; - + #ifdef SO_ACCEPTFILTER struct accept_filter_arg afa; #endif @@ -81,9 +81,9 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { WORD wVersionRequested; WSADATA wsaData; int err; - + wVersionRequested = MAKEWORD( 2, 2 ); - + err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we could not find a usable */ @@ -91,37 +91,37 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { return -1; } #endif - + srv_socket = calloc(1, sizeof(*srv_socket)); srv_socket->fd = -1; - + srv_socket->srv_token = buffer_init(); buffer_copy_string_buffer(srv_socket->srv_token, host_token); - + b = buffer_init(); buffer_copy_string_buffer(b, host_token); - - /* ipv4:port + + /* ipv4:port * [ipv6]:port */ if (NULL == (sp = strrchr(b->ptr, ':'))) { log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b); - + return -1; } - + host = b->ptr; - + /* check for [ and ] */ if (b->ptr[0] == '[' && *(sp-1) == ']') { *(sp-1) = '\0'; host++; - + s->use_ipv6 = 1; } - + *(sp++) = '\0'; - + port = strtol(sp, NULL, 10); if (host[0] == '/') { @@ -129,17 +129,17 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { is_unix_domain_socket = 1; } else if (port == 0 || port > 65535) { log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port); - + return -1; } - + if (*host == '\0') host = NULL; if (is_unix_domain_socket) { #ifdef HAVE_SYS_UN_H srv_socket->addr.plain.sa_family = AF_UNIX; - + if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) { log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); return -1; @@ -154,7 +154,7 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { #ifdef HAVE_IPV6 if (s->use_ipv6) { srv_socket->addr.plain.sa_family = AF_INET6; - + if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) { log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno)); return -1; @@ -162,7 +162,7 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { srv_socket->use_ipv6 = 1; } #endif - + if (srv_socket->fd == -1) { srv_socket->addr.plain.sa_family = AF_INET; if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) { @@ -170,16 +170,16 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { return -1; } } - + /* */ srv->cur_fds = srv_socket->fd; - + val = 1; if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno)); return -1; } - + switch(srv_socket->addr.plain.sa_family) { #ifdef HAVE_IPV6 case AF_INET6: @@ -190,23 +190,23 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { } else { struct addrinfo hints, *res; int r; - + memset(&hints, 0, sizeof(hints)); - + hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; - + if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) { - log_error_write(srv, __FILE__, __LINE__, - "sssss", "getaddrinfo failed: ", + log_error_write(srv, __FILE__, __LINE__, + "sssss", "getaddrinfo failed: ", gai_strerror(r), "'", host, "'"); - + return -1; } - + memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen); - + freeaddrinfo(res); } srv_socket->addr.ipv6.sin6_port = htons(port); @@ -221,33 +221,33 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { } else { struct hostent *he; if (NULL == (he = gethostbyname(host))) { - log_error_write(srv, __FILE__, __LINE__, - "sds", "gethostbyname failed: ", + log_error_write(srv, __FILE__, __LINE__, + "sds", "gethostbyname failed: ", h_errno, host); return -1; } - + if (he->h_addrtype != AF_INET) { log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype); return -1; } - + if (he->h_length != sizeof(struct in_addr)) { log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length); return -1; } - + memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length); } srv_socket->addr.ipv4.sin_port = htons(port); - + addr_len = sizeof(struct sockaddr_in); - + break; case AF_UNIX: srv_socket->addr.un.sun_family = AF_UNIX; strcpy(srv_socket->addr.un.sun_path, host); - + #ifdef SUN_LEN addr_len = SUN_LEN(&srv_socket->addr.un); #else @@ -259,8 +259,8 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { 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:", + log_error_write(srv, __FILE__, __LINE__, "ss", + "server socket is still in use:", host); @@ -275,8 +275,8 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { case ENOENT: break; default: - log_error_write(srv, __FILE__, __LINE__, "sds", - "testing socket failed:", + log_error_write(srv, __FILE__, __LINE__, "sds", + "testing socket failed:", host, strerror(errno)); return -1; @@ -285,47 +285,47 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { break; default: addr_len = 0; - + return -1; } - + if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) { switch(srv_socket->addr.plain.sa_family) { case AF_UNIX: - log_error_write(srv, __FILE__, __LINE__, "sds", - "can't bind to socket:", + 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:", + log_error_write(srv, __FILE__, __LINE__, "ssds", + "can't bind to port:", host, port, strerror(errno)); break; } return -1; } - + if (-1 == listen(srv_socket->fd, 128 * 8)) { log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno)); return -1; } - + if (s->is_ssl) { #ifdef USE_OPENSSL if (srv->ssl_is_init == 0) { SSL_load_error_strings(); SSL_library_init(); srv->ssl_is_init = 1; - + if (0 == RAND_status()) { - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", "not enough entropy in the pool"); return -1; } } - + if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) { - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", ERR_error_string(ERR_get_error(), NULL)); return -1; } @@ -347,34 +347,34 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { return -1; } } - + if (buffer_is_empty(s->ssl_pemfile)) { log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set"); return -1; } - + if (!buffer_is_empty(s->ssl_ca_file)) { if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) { - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file); return -1; } } - + if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) { - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); return -1; } - + if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) { - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); return -1; } - + if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) { - log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:", "Private key does not match the certificate public key, reason:", ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile); @@ -385,15 +385,15 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { srv_socket->ssl_ctx = s->ssl_ctx; #else - + buffer_free(srv_socket->srv_token); free(srv_socket); - + buffer_free(b); - - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", + + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:", "ssl requested but openssl support is not compiled in"); - + return -1; #endif } else { @@ -411,10 +411,10 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { } #endif } - + srv_socket->is_ssl = s->is_ssl; srv_socket->fde_ndx = -1; - + if (srv->srv_sockets.size == 0) { srv->srv_sockets.size = 4; srv->srv_sockets.used = 0; @@ -423,11 +423,11 @@ int network_server_init(server *srv, buffer *host_token, specific_config *s) { srv->srv_sockets.size += 4; srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket)); } - + srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket; - + buffer_free(b); - + return 0; } @@ -435,24 +435,24 @@ int network_close(server *srv) { size_t i; for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; - + if (srv_socket->fd != -1) { /* check if server fd are already registered */ if (srv_socket->fde_ndx != -1) { fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd); fdevent_unregister(srv->ev, srv_socket->fd); } - + close(srv_socket->fd); } - + buffer_free(srv_socket->srv_token); - + free(srv_socket); } - + free(srv->srv_sockets.ptr); - + return 0; } @@ -469,11 +469,11 @@ int network_init(server *srv) { buffer *b; size_t i; network_backend_t backend; - - struct nb_map { - network_backend_t nb; - const char *name; - } network_backends[] = { + + struct nb_map { + network_backend_t nb; + const char *name; + } network_backends[] = { /* lowest id wins */ #if defined USE_LINUX_SENDFILE { NETWORK_BACKEND_LINUX_SENDFILE, "linux-sendfile" }, @@ -490,18 +490,18 @@ int network_init(server *srv) { { NETWORK_BACKEND_WRITE, "write" }, { NETWORK_BACKEND_UNSET, NULL } }; - + b = buffer_init(); - + buffer_copy_string_buffer(b, srv->srvconf.bindhost); buffer_append_string(b, ":"); buffer_append_long(b, srv->srvconf.port); - + if (0 != network_server_init(srv, b, srv->config_storage[0])) { return -1; } buffer_free(b); - + #ifdef USE_OPENSSL srv->network_ssl_backend_write = network_write_chunkqueue_openssl; #endif @@ -521,8 +521,8 @@ int network_init(server *srv) { if (NULL == network_backends[i].name) { /* we don't know it */ - log_error_write(srv, __FILE__, __LINE__, "sb", - "server.network-backend has a unknown value:", + log_error_write(srv, __FILE__, __LINE__, "sb", + "server.network-backend has a unknown value:", srv->srvconf.network_backend); return -1; @@ -540,17 +540,17 @@ int network_init(server *srv) { #endif #ifdef USE_LINUX_SENDFILE case NETWORK_BACKEND_LINUX_SENDFILE: - srv->network_backend_write = network_write_chunkqueue_linuxsendfile; + srv->network_backend_write = network_write_chunkqueue_linuxsendfile; break; #endif #ifdef USE_FREEBSD_SENDFILE case NETWORK_BACKEND_FREEBSD_SENDFILE: - srv->network_backend_write = network_write_chunkqueue_freebsdsendfile; + srv->network_backend_write = network_write_chunkqueue_freebsdsendfile; break; #endif #ifdef USE_SOLARIS_SENDFILEV case NETWORK_BACKEND_SOLARIS_SENDFILEV: - srv->network_backend_write = network_write_chunkqueue_solarissendfilev; + srv->network_backend_write = network_write_chunkqueue_solarissendfilev; break; #endif default: @@ -562,13 +562,13 @@ int network_init(server *srv) { data_config *dc = (data_config *)srv->config_context->data[i]; specific_config *s = srv->config_storage[i]; size_t j; - + /* not our stage */ if (COMP_SERVER_SOCKET != dc->comp) continue; - + if (dc->cond != CONFIG_COND_EQ) { log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"]."); - + return -1; } @@ -579,26 +579,26 @@ int network_init(server *srv) { break; } } - + if (j == srv->srv_sockets.used) { if (0 != network_server_init(srv, dc->string, s)) return -1; } } - + return 0; } int network_register_fdevents(server *srv) { size_t i; - + if (-1 == fdevent_reset(srv->ev)) { return -1; } - + /* register fdevents after reset */ for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; - + fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket); fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN); } @@ -608,7 +608,7 @@ int network_register_fdevents(server *srv) { int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) { int ret = -1; off_t written = 0; -#ifdef TCP_CORK +#ifdef TCP_CORK int corked = 0; #endif server_socket *srv_socket = con->srv_socket; @@ -621,11 +621,11 @@ int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) { joblist_append(srv, con); return 1; - } + } written = cq->bytes_out; -#ifdef TCP_CORK +#ifdef TCP_CORK /* Linux: put a cork into the socket as we want to combine the write() calls * but only if we really have multiple chunks */ @@ -634,7 +634,7 @@ int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) { setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked)); } #endif - + if (srv_socket->is_ssl) { #ifdef USE_OPENSSL ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq); @@ -642,12 +642,12 @@ int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) { } else { ret = srv->network_backend_write(srv, con, con->fd, cq); } - + if (ret >= 0) { chunkqueue_remove_finished_chunks(cq); ret = chunkqueue_is_empty(cq) ? 0 : 1; } - + #ifdef TCP_CORK if (corked) { corked = 0; @@ -660,13 +660,13 @@ int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) { con->bytes_written_cur_second += written; *(con->conf.global_bytes_per_second_cnt_ptr) += written; - + if (con->conf.kbytes_per_second && (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) { /* we reached the traffic limit */ con->traffic_limit_reached = 1; joblist_append(srv, con); - } + } return ret; } diff --git a/src/network_freebsd_sendfile.c b/src/network_freebsd_sendfile.c index f6f4d82..819d16f 100644 --- a/src/network_freebsd_sendfile.c +++ b/src/network_freebsd_sendfile.c @@ -26,7 +26,7 @@ #ifndef UIO_MAXIOV # ifdef __FreeBSD__ -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */ +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */ # define UIO_MAXIOV 1024 # endif #endif @@ -34,30 +34,30 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) { chunk *c; size_t chunks_written = 0; - + for(c = cq->first; c; c = c->next, chunks_written++) { int chunk_finished = 0; - + switch(c->type) { case MEM_CHUNK: { char * offset; size_t toSend; ssize_t r; - + size_t num_chunks, i; struct iovec chunks[UIO_MAXIOV]; chunk *tc; size_t num_bytes = 0; - + /* we can't send more then SSIZE_MAX bytes in one chunk */ - - /* build writev list - * + + /* build writev list + * * 1. limit: num_chunks < UIO_MAXIOV * 2. limit: num_bytes < SSIZE_MAX */ for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next); - + for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) { if (tc->mem->used == 0) { chunks[i].iov_base = tc->mem->ptr; @@ -65,24 +65,24 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f } else { offset = tc->mem->ptr + tc->offset; toSend = tc->mem->used - 1 - tc->offset; - + chunks[i].iov_base = offset; - + /* protect the return value of writev() */ if (toSend > SSIZE_MAX || num_bytes + toSend > SSIZE_MAX) { chunks[i].iov_len = SSIZE_MAX - num_bytes; - + num_chunks = i + 1; break; } else { chunks[i].iov_len = toSend; } - + num_bytes += toSend; } } - + if ((r = writev(fd, chunks, num_chunks)) < 0) { switch (errno) { case EAGAIN: @@ -94,24 +94,24 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f case ECONNRESET: return -2; default: - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "writev failed:", strerror(errno), fd); - + return -1; } r = 0; } - + /* check which chunks have been written */ cq->bytes_out += r; - + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) { if (r >= (ssize_t)chunks[i].iov_len) { /* written */ r -= chunks[i].iov_len; tc->offset += chunks[i].iov_len; - + if (chunk_finished) { /* skip the chunks from further touches */ chunks_written++; @@ -122,14 +122,14 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f } } else { /* partially written */ - + tc->offset += r; chunk_finished = 0; - + break; } } - + break; } case FILE_CHUNK: { @@ -137,32 +137,32 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f size_t toSend; stat_cache_entry *sce = NULL; int ifd; - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), c->file.name); return -1; } - + offset = c->file.start + c->offset; /* limit the toSend to 2^31-1 bytes in a chunk */ - toSend = c->file.length - c->offset > ((1 << 30) - 1) ? + toSend = c->file.length - c->offset > ((1 << 30) - 1) ? ((1 << 30) - 1) : c->file.length - c->offset; - + if (offset > sce->st.st_size) { log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); - + return -1; } - + if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); - + return -1; } - + r = 0; - + /* FreeBSD sendfile() */ if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) { switch(errno) { @@ -178,26 +178,26 @@ int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int f } } close(ifd); - + c->offset += r; cq->bytes_out += r; - + if (c->offset == c->file.length) { chunk_finished = 1; } - + break; } default: - + log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); - + return -1; } - + if (!chunk_finished) { /* not finished yet */ - + break; } } diff --git a/src/network_linux_sendfile.c b/src/network_linux_sendfile.c index 580ba87..6586efb 100644 --- a/src/network_linux_sendfile.c +++ b/src/network_linux_sendfile.c @@ -29,32 +29,32 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) { chunk *c; size_t chunks_written = 0; - + for(c = cq->first; c; c = c->next, chunks_written++) { int chunk_finished = 0; - + switch(c->type) { case MEM_CHUNK: { char * offset; size_t toSend; ssize_t r; - + size_t num_chunks, i; struct iovec chunks[UIO_MAXIOV]; chunk *tc; size_t num_bytes = 0; - + /* we can't send more then SSIZE_MAX bytes in one chunk */ - - /* build writev list - * + + /* build writev list + * * 1. limit: num_chunks < UIO_MAXIOV * 2. limit: num_bytes < SSIZE_MAX */ - for (num_chunks = 0, tc = c; - tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; + for (num_chunks = 0, tc = c; + tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; tc = tc->next, num_chunks++); - + for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) { if (tc->mem->used == 0) { chunks[i].iov_base = tc->mem->ptr; @@ -62,24 +62,24 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, } else { offset = tc->mem->ptr + tc->offset; toSend = tc->mem->used - 1 - tc->offset; - + chunks[i].iov_base = offset; - + /* protect the return value of writev() */ if (toSend > SSIZE_MAX || num_bytes + toSend > SSIZE_MAX) { chunks[i].iov_len = SSIZE_MAX - num_bytes; - + num_chunks = i + 1; break; } else { chunks[i].iov_len = toSend; } - + num_bytes += toSend; } } - + if ((r = writev(fd, chunks, num_chunks)) < 0) { switch (errno) { case EAGAIN: @@ -90,13 +90,13 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, case ECONNRESET: return -2; default: - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "writev failed:", strerror(errno), fd); - + return -1; } } - + /* check which chunks have been written */ cq->bytes_out += r; @@ -105,7 +105,7 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, /* written */ r -= chunks[i].iov_len; tc->offset += chunks[i].iov_len; - + if (chunk_finished) { /* skip the chunks from further touches */ chunks_written++; @@ -116,14 +116,14 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, } } else { /* partially written */ - + tc->offset += r; chunk_finished = 0; - + break; } } - + break; } case FILE_CHUNK: { @@ -131,17 +131,17 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, off_t offset; size_t toSend; stat_cache_entry *sce = NULL; - + offset = c->file.start + c->offset; /* limit the toSend to 2^31-1 bytes in a chunk */ - toSend = c->file.length - c->offset > ((1 << 30) - 1) ? + toSend = c->file.length - c->offset > ((1 << 30) - 1) ? ((1 << 30) - 1) : c->file.length - c->offset; - - /* open file if not already opened */ + + /* open file if not already opened */ if (-1 == c->file.fd) { if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); - + return -1; } #ifdef FD_CLOEXEC @@ -151,7 +151,7 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, /* tell the kernel that we want to stream the file */ if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) { if (ENOSYS != errno) { - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "posix_fadvise failed:", strerror(errno), c->file.fd); } } @@ -168,18 +168,19 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, case ECONNRESET: return -2; default: - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile failed:", strerror(errno), fd); return -1; } } if (r == 0) { + int oerrno = errno; /* We got an event to write but we wrote nothing * * - the file shrinked -> error * - the remote side closed inbetween -> remote-close */ - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { /* file is gone ? */ return -1; @@ -187,31 +188,34 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, if (offset > sce->st.st_size) { /* file shrinked, close the connection */ + errno = oerrno; + return -1; } + errno = oerrno; return -2; } #ifdef HAVE_POSIX_FADVISE #if 0 #define K * 1024 -#define M * 1024 K +#define M * 1024 K #define READ_AHEAD 4 M /* check if we need a new chunk */ if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) { /* tell the kernel that we want to stream the file */ if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) { - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "posix_fadvise failed:", strerror(errno), c->file.fd); } } #endif #endif - + c->offset += r; cq->bytes_out += r; - + if (c->offset == c->file.length) { chunk_finished = 1; @@ -222,19 +226,19 @@ int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, c->file.fd = -1; } } - + break; } default: - + log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); - + return -1; } - + if (!chunk_finished) { /* not finished yet */ - + break; } } diff --git a/src/network_openssl.c b/src/network_openssl.c index 86043fa..e6df35e 100644 --- a/src/network_openssl.c +++ b/src/network_openssl.c @@ -23,8 +23,8 @@ #include "log.h" #include "stat_cache.h" -# include <openssl/ssl.h> -# include <openssl/err.h> +# include <openssl/ssl.h> +# include <openssl/err.h> int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) { int ssl_r; @@ -33,7 +33,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu /* this is a 64k sendbuffer * - * it has to stay at the same location all the time to satisfy the needs + * it has to stay at the same location all the time to satisfy the needs * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE * * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown @@ -43,14 +43,14 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu * In reality we would like to use mmap() but we don't have a guarantee that * we get the same mmap() address for each call. On openbsd the mmap() address * even randomized. - * That means either we keep the mmap() open or we do a read() into a - * constant buffer + * That means either we keep the mmap() open or we do a read() into a + * constant buffer * */ #define LOCAL_SEND_BUFSIZE (64 * 1024) static char *local_send_buffer = NULL; /* the remote side closed the connection before without shutdown request - * - IE + * - IE * - wget * if keep-alive is disabled */ @@ -85,31 +85,31 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu for(c = cq->first; c; c = c->next) { int chunk_finished = 0; - + switch(c->type) { case MEM_CHUNK: { char * offset; size_t toSend; ssize_t r; - + if (c->mem->used == 0 || c->mem->used == 1) { chunk_finished = 1; break; } - + offset = c->mem->ptr + c->offset; toSend = c->mem->used - 1 - c->offset; - + /** * SSL_write man-page - * + * * WARNING * When an SSL_write() operation has to be repeated because of * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be * repeated with the same arguments. - * + * */ - + if ((r = SSL_write(ssl, offset, toSend)) <= 0) { unsigned long err; @@ -120,7 +120,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu /* perhaps we have error waiting in our error-queue */ if (0 != (err = ERR_get_error())) { do { - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", ssl_r, r, ERR_error_string(err, NULL)); } while((err = ERR_get_error())); @@ -130,43 +130,43 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu case EPIPE: return -2; default: - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", ssl_r, r, errno, strerror(errno)); break; } } else { /* neither error-queue nor errno ? */ - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", ssl_r, r, errno, strerror(errno)); } - + return -1; case SSL_ERROR_ZERO_RETURN: /* clean shutdown on the remote side */ - + if (r == 0) return -2; - + /* fall through */ default: while((err = ERR_get_error())) { - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", ssl_r, r, ERR_error_string(err, NULL)); } - + return -1; } } else { c->offset += r; cq->bytes_out += r; } - + if (c->offset == (off_t)c->mem->used - 1) { chunk_finished = 1; } - + break; } case FILE_CHUNK: { @@ -175,7 +175,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu stat_cache_entry *sce = NULL; int ifd; int write_wait = 0; - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), c->file.name); @@ -189,13 +189,13 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu do { off_t offset = c->file.start + c->offset; - off_t toSend = c->file.length - c->offset; + off_t toSend = c->file.length - c->offset; if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE; - + if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno)); - + return -1; } @@ -208,9 +208,9 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu } s = local_send_buffer; - + close(ifd); - + if ((r = SSL_write(ssl, s, toSend)) <= 0) { unsigned long err; @@ -222,7 +222,7 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu /* perhaps we have error waiting in our error-queue */ if (0 != (err = ERR_get_error())) { do { - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", ssl_r, r, ERR_error_string(err, NULL)); } while((err = ERR_get_error())); @@ -232,58 +232,58 @@ int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chu case EPIPE: return -2; default: - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:", ssl_r, r, errno, strerror(errno)); break; } } else { /* neither error-queue nor errno ? */ - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):", ssl_r, r, errno, strerror(errno)); } - + return -1; case SSL_ERROR_ZERO_RETURN: /* clean shutdown on the remote side */ - + if (r == 0) return -2; - + /* fall thourgh */ default: while((err = ERR_get_error())) { - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:", ssl_r, r, ERR_error_string(err, NULL)); } - + return -1; } } else { c->offset += r; cq->bytes_out += r; } - + if (c->offset == c->file.length) { chunk_finished = 1; } } while(!chunk_finished && !write_wait); - + break; } default: log_error_write(srv, __FILE__, __LINE__, "s", "type not known"); - + return -1; } - + if (!chunk_finished) { /* not finished yet */ - + break; } - + chunks_written++; } diff --git a/src/network_solaris_sendfilev.c b/src/network_solaris_sendfilev.c index 0ab669f..fcb7d10 100644 --- a/src/network_solaris_sendfilev.c +++ b/src/network_solaris_sendfilev.c @@ -29,11 +29,11 @@ #endif /** - * a very simple sendfilev() interface for solaris which can be optimised a lot more + * a very simple sendfilev() interface for solaris which can be optimised a lot more * as solaris sendfilev() supports 'sending everythin in one syscall()' - * - * If you want such an interface and need the performance, just give me an account on - * a solaris box. + * + * If you want such an interface and need the performance, just give me an account on + * a solaris box. * - jan@kneschke.de */ @@ -41,31 +41,31 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) { chunk *c; size_t chunks_written = 0; - + for(c = cq->first; c; c = c->next, chunks_written++) { int chunk_finished = 0; - + switch(c->type) { case MEM_CHUNK: { char * offset; size_t toSend; ssize_t r; - + size_t num_chunks, i; struct iovec chunks[UIO_MAXIOV]; chunk *tc; - + size_t num_bytes = 0; - + /* we can't send more then SSIZE_MAX bytes in one chunk */ - - /* build writev list - * + + /* build writev list + * * 1. limit: num_chunks < UIO_MAXIOV * 2. limit: num_bytes < SSIZE_MAX */ for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next); - + for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) { if (tc->mem->used == 0) { chunks[i].iov_base = tc->mem->ptr; @@ -73,24 +73,24 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int } else { offset = tc->mem->ptr + tc->offset; toSend = tc->mem->used - 1 - tc->offset; - + chunks[i].iov_base = offset; - + /* protect the return value of writev() */ if (toSend > SSIZE_MAX || num_bytes + toSend > SSIZE_MAX) { chunks[i].iov_len = SSIZE_MAX - num_bytes; - + num_chunks = i + 1; break; } else { chunks[i].iov_len = toSend; } - + num_bytes += toSend; } } - + if ((r = writev(fd, chunks, num_chunks)) < 0) { switch (errno) { case EAGAIN: @@ -101,22 +101,22 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int case ECONNRESET: return -2; default: - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "writev failed:", strerror(errno), fd); - + return -1; } } - + /* check which chunks have been written */ cq->bytes_out += r; - + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) { if (r >= (ssize_t)chunks[i].iov_len) { /* written */ r -= chunks[i].iov_len; tc->offset += chunks[i].iov_len; - + if (chunk_finished) { /* skip the chunks from further touches */ chunks_written++; @@ -127,14 +127,14 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int } } else { /* partially written */ - + tc->offset += r; chunk_finished = 0; - + break; } } - + break; } case FILE_CHUNK: { @@ -144,25 +144,25 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int sendfilevec_t fvec; stat_cache_entry *sce = NULL; int ifd; - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), c->file.name); return -1; } - + offset = c->file.start + c->offset; toSend = c->file.length - c->offset; - + if (offset > sce->st.st_size) { log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); - + return -1; } if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); - + return -1; } @@ -170,39 +170,39 @@ int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fvec.sfv_flag = 0; fvec.sfv_off = offset; fvec.sfv_len = toSend; - + /* Solaris sendfilev() */ if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) { if (errno != EAGAIN) { log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno); - + close(ifd); return -1; } - + r = 0; } - + close(ifd); c->offset += written; cq->bytes_out += written; - + if (c->offset == c->file.length) { chunk_finished = 1; } - + break; } default: - + log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); - + return -1; } - + if (!chunk_finished) { /* not finished yet */ - + break; } } diff --git a/src/network_write.c b/src/network_write.c index 90fc2ac..7fb52cb 100644 --- a/src/network_write.c +++ b/src/network_write.c @@ -27,44 +27,44 @@ int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) { chunk *c; size_t chunks_written = 0; - + for(c = cq->first; c; c = c->next) { int chunk_finished = 0; - + switch(c->type) { case MEM_CHUNK: { char * offset; size_t toSend; ssize_t r; - + if (c->mem->used == 0) { chunk_finished = 1; break; } - + offset = c->mem->ptr + c->offset; toSend = c->mem->used - 1 - c->offset; -#ifdef __WIN32 +#ifdef __WIN32 if ((r = send(fd, offset, toSend, 0)) < 0) { log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd); - + return -1; } #else if ((r = write(fd, offset, toSend)) < 0) { log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd); - + return -1; } #endif - + c->offset += r; cq->bytes_out += r; - + if (c->offset == (off_t)c->mem->used - 1) { chunk_finished = 1; } - + break; } case FILE_CHUNK: { @@ -76,34 +76,34 @@ int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqu size_t toSend; stat_cache_entry *sce = NULL; int ifd; - + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), c->file.name); return -1; } - + offset = c->file.start + c->offset; toSend = c->file.length - c->offset; - + if (offset > sce->st.st_size) { log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); - + return -1; } if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno)); - + return -1; } - + #if defined USE_MMAP if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) { log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno)); close(ifd); - + return -1; } close(ifd); @@ -113,48 +113,48 @@ int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqu munmap(p, sce->st.st_size); return -1; } - + munmap(p, sce->st.st_size); #else buffer_prepare_copy(srv->tmp_buf, toSend); - + lseek(ifd, offset, SEEK_SET); if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) { log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno)); close(ifd); - + return -1; } close(ifd); if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) { log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno)); - + return -1; } #endif c->offset += r; cq->bytes_out += r; - + if (c->offset == c->file.length) { chunk_finished = 1; } - + break; } default: - + log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); - + return -1; } - + if (!chunk_finished) { /* not finished yet */ - + break; } - + chunks_written++; } diff --git a/src/network_writev.c b/src/network_writev.c index 5fdec8c..d628f75 100644 --- a/src/network_writev.c +++ b/src/network_writev.c @@ -33,16 +33,16 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) { chunk *c; size_t chunks_written = 0; - + for(c = cq->first; c; c = c->next) { int chunk_finished = 0; - + switch(c->type) { case MEM_CHUNK: { char * offset; size_t toSend; ssize_t r; - + size_t num_chunks, i; struct iovec *chunks; chunk *tc; @@ -55,21 +55,23 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq const size_t max_chunks = MAX_IOVEC; #elif defined(UIO_MAXIOV) /* Linux x86 (glibc-2.2.5-233) */ const size_t max_chunks = UIO_MAXIOV; +#elif (defined(__FreeBSD__) && __FreeBSD_version < 500000) /* FreeBSD 4.x */ + const size_t max_chunks = 1024; /* UIO_MAXIOV value from sys/uio.h */ #else #error "sysconf() doesnt return _SC_IOV_MAX ..., check the output of 'man writev' for the EINVAL error and send the output to jan@kneschke.de" #endif /* we can't send more then SSIZE_MAX bytes in one chunk */ - - /* build writev list - * + + /* build writev list + * * 1. limit: num_chunks < max_chunks * 2. limit: num_bytes < SSIZE_MAX */ for (num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < max_chunks; num_chunks++, tc = tc->next); chunks = calloc(num_chunks, sizeof(*chunks)); - + for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) { if (tc->mem->used == 0) { chunks[i].iov_base = tc->mem->ptr; @@ -77,24 +79,24 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq } else { offset = tc->mem->ptr + tc->offset; toSend = tc->mem->used - 1 - tc->offset; - + chunks[i].iov_base = offset; - + /* protect the return value of writev() */ if (toSend > SSIZE_MAX || num_bytes + toSend > SSIZE_MAX) { chunks[i].iov_len = SSIZE_MAX - num_bytes; - + num_chunks = i + 1; break; } else { chunks[i].iov_len = toSend; } - + num_bytes += toSend; } } - + if ((r = writev(fd, chunks, num_chunks)) < 0) { switch (errno) { case EAGAIN: @@ -106,24 +108,24 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq free(chunks); return -2; default: - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "writev failed:", strerror(errno), fd); - + free(chunks); return -1; } } - + cq->bytes_out += r; /* check which chunks have been written */ - + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) { if (r >= (ssize_t)chunks[i].iov_len) { /* written */ r -= chunks[i].iov_len; tc->offset += chunks[i].iov_len; - + if (chunk_finished) { /* skip the chunks from further touches */ chunks_written++; @@ -134,7 +136,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq } } else { /* partially written */ - + tc->offset += r; chunk_finished = 0; @@ -142,7 +144,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq } } free(chunks); - + break; } case FILE_CHUNK: { @@ -154,7 +156,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq #define KByte * 1024 #define MByte * 1024 KByte #define GByte * 1024 MByte - const off_t we_want_to_mmap = 512 KByte; + const off_t we_want_to_mmap = 512 KByte; char *start = NULL; if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) { @@ -164,16 +166,16 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq } abs_offset = c->file.start + c->offset; - + if (abs_offset > sce->st.st_size) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name); - + return -1; } - /* mmap the buffer - * - first mmap + /* mmap the buffer + * - first mmap * - new mmap as the we are at the end of the last one */ if (c->file.mmap.start == MAP_FAILED || abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) { @@ -183,7 +185,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq * adaptive mem-mapping * the problem: * we mmap() the whole file. If someone has alot large files and 32bit - * machine the virtual address area will be unrun and we will have a failing + * machine the virtual address area will be unrun and we will have a failing * mmap() call. * solution: * only mmap 16M in one chunk and move the window as soon as we have finished @@ -229,7 +231,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq if (-1 == c->file.fd) { /* open the file if not already open */ if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno)); - + return -1; } #ifdef FD_CLOEXEC @@ -240,7 +242,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) { /* close it here, otherwise we'd have to set FD_CLOEXEC */ - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:", strerror(errno), c->file.name, c->file.fd); return -1; @@ -253,7 +255,7 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq #ifdef HAVE_MADVISE /* don't advise files < 64Kb */ if (c->file.mmap.length > (64 KByte)) { - /* darwin 7 is returning EINVAL all the time and I don't know how to + /* darwin 7 is returning EINVAL all the time and I don't know how to * detect this at runtime.i * * ignore the return value for now */ @@ -269,12 +271,12 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset); if (toSend < 0) { - log_error_write(srv, __FILE__, __LINE__, "soooo", + log_error_write(srv, __FILE__, __LINE__, "soooo", "toSend is negative:", toSend, c->file.mmap.length, abs_offset, - c->file.mmap.offset); + c->file.mmap.offset); assert(toSend < 0); } @@ -294,16 +296,16 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq case ECONNRESET: return -2; default: - log_error_write(srv, __FILE__, __LINE__, "ssd", + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), fd); - + return -1; } } - + c->offset += r; cq->bytes_out += r; - + if (c->offset == c->file.length) { chunk_finished = 1; @@ -313,22 +315,22 @@ int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkq c->file.mmap.start = MAP_FAILED; } } - + break; } default: - + log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known"); - + return -1; } - + if (!chunk_finished) { /* not finished yet */ - + break; } - + chunks_written++; } diff --git a/src/plugin.c b/src/plugin.c index e74d8b0..faf5520 100644 --- a/src/plugin.c +++ b/src/plugin.c @@ -17,23 +17,23 @@ #include <dlfcn.h> #endif /* - * + * * if you change this enum to add a new callback, be sure * - that PLUGIN_FUNC_SIZEOF is the last entry * - that you add PLUGIN_TO_SLOT twice: - * 1. as callback-dispatcher + * 1. as callback-dispatcher * 2. in plugins_call_init() - * + * */ typedef struct { PLUGIN_DATA; } plugin_data; -typedef enum { +typedef enum { PLUGIN_FUNC_UNSET, - PLUGIN_FUNC_HANDLE_URI_CLEAN, - PLUGIN_FUNC_HANDLE_URI_RAW, + PLUGIN_FUNC_HANDLE_URI_CLEAN, + PLUGIN_FUNC_HANDLE_URI_RAW, PLUGIN_FUNC_HANDLE_REQUEST_DONE, PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, PLUGIN_FUNC_HANDLE_TRIGGER, @@ -44,18 +44,18 @@ typedef enum { PLUGIN_FUNC_HANDLE_DOCROOT, PLUGIN_FUNC_HANDLE_PHYSICAL, PLUGIN_FUNC_CONNECTION_RESET, - PLUGIN_FUNC_INIT, + PLUGIN_FUNC_INIT, PLUGIN_FUNC_CLEANUP, PLUGIN_FUNC_SET_DEFAULTS, - + PLUGIN_FUNC_SIZEOF } plugin_t; static plugin *plugin_init(void) { plugin *p; - + p = calloc(1, sizeof(*p)); - + return p; } @@ -67,7 +67,7 @@ static void plugin_free(plugin *p) { #endif #ifndef LIGHTTPD_STATIC - if (use_dlclose && p->lib) { + if (use_dlclose && p->lib) { #ifdef __WIN32 FreeLibrary(p->lib); #else @@ -75,7 +75,7 @@ static void plugin_free(plugin *p) { #endif } #endif - + free(p); } @@ -89,17 +89,17 @@ static int plugins_register(server *srv, plugin *p) { srv->plugins.size += 4; srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps)); } - + ps = srv->plugins.ptr; ps[srv->plugins.used++] = p; - + return 0; } /** - * - * - * + * + * + * */ #ifdef LIGHTTPD_STATIC @@ -124,11 +124,11 @@ int plugins_load(server *srv) { int (*init)(plugin *pl); const char *error; size_t i; - + for (i = 0; i < srv->srvconf.modules->used; i++) { data_string *d = (data_string *)srv->srvconf.modules->data[i]; char *modules = d->value->ptr; - + buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir); buffer_append_string(srv->tmp_buf, "/"); @@ -138,13 +138,13 @@ int plugins_load(server *srv) { #else buffer_append_string(srv->tmp_buf, ".so"); #endif - + p = plugin_init(); #ifdef __WIN32 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) { LPVOID lpMsgBuf; FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), @@ -152,24 +152,24 @@ int plugins_load(server *srv) { (LPTSTR) &lpMsgBuf, 0, NULL ); - log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", + log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed", lpMsgBuf, srv->tmp_buf); - + plugin_free(p); - + return -1; } -#else - if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) { - log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", +#else + if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) { + log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:", srv->tmp_buf, dlerror()); - + plugin_free(p); - + return -1; } - + #endif buffer_reset(srv->tmp_buf); buffer_copy_string(srv->tmp_buf, modules); @@ -181,7 +181,7 @@ int plugins_load(server *srv) { if (init == NULL) { LPVOID lpMsgBuf; FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), @@ -190,7 +190,7 @@ int plugins_load(server *srv) { 0, NULL ); log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf); - + plugin_free(p); return -1; } @@ -203,15 +203,15 @@ int plugins_load(server *srv) { #endif if ((error = dlerror()) != NULL) { log_error_write(srv, __FILE__, __LINE__, "s", error); - + plugin_free(p); return -1; } - + #endif if ((*init)(p)) { log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" ); - + plugin_free(p); return -1; } @@ -220,7 +220,7 @@ int plugins_load(server *srv) { #endif plugins_register(srv, p); } - + return 0; } #endif @@ -253,8 +253,8 @@ int plugins_load(server *srv) { } /** - * plugins that use - * + * plugins that use + * * - server *srv * - connection *con * - void *p_d (plugin_data *) @@ -301,12 +301,12 @@ PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset) } /** - * plugins that use - * + * plugins that use + * * - server *srv * - void *p_d (plugin_data *) */ - + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger) PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup) PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup) @@ -314,18 +314,18 @@ PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults) #undef PLUGIN_TO_SLOT -#if 0 +#if 0 /** - * + * * special handler - * + * */ handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) { size_t i; plugin **ps; - + ps = srv->plugins.ptr; - + for (i = 0; i < srv->plugins.used; i++) { plugin *p = ps[i]; if (p->handle_fdevent) { @@ -344,34 +344,34 @@ handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) { } } } - + return HANDLER_GO_ON; } #endif /** - * + * * - call init function of all plugins to init the plugin-internals * - added each plugin that supports has callback to the corresponding slot - * + * * - is only called once. */ handler_t plugins_call_init(server *srv) { size_t i; plugin **ps; - + ps = srv->plugins.ptr; - + /* fill slots */ - + srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps)); - + for (i = 0; i < srv->plugins.used; i++) { size_t j; /* check which calls are supported */ - + plugin *p = ps[i]; - + #define PLUGIN_TO_SLOT(x, y) \ if (p->y) { \ plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \ @@ -384,11 +384,11 @@ handler_t plugins_call_init(server *srv) { slot[j] = p;\ break;\ }\ - } - - - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); + } + + + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean); + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw); PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done); PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close); PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger); @@ -402,19 +402,19 @@ handler_t plugins_call_init(server *srv) { PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup); PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults); #undef PLUGIN_TO_SLOT - + if (p->init) { if (NULL == (p->data = p->init())) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "plugin-init failed for module", p->name); return HANDLER_ERROR; } - + /* used for con->mode, DIRECT == 0, plugins above that */ ((plugin_data *)(p->data))->id = i + 1; - + if (p->version != LIGHTTPD_VERSION_ID) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "plugin-version doesn't match lighttpd-version for", p->name); return HANDLER_ERROR; } @@ -422,29 +422,29 @@ handler_t plugins_call_init(server *srv) { p->data = NULL; } } - + return HANDLER_GO_ON; } void plugins_free(server *srv) { size_t i; plugins_call_cleanup(srv); - + for (i = 0; i < srv->plugins.used; i++) { plugin *p = ((plugin **)srv->plugins.ptr)[i]; - + plugin_free(p); } - + for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) { plugin **slot = ((plugin ***)(srv->plugin_slots))[i]; - + if (slot) free(slot); } - + free(srv->plugin_slots); srv->plugin_slots = NULL; - + free(srv->plugins.ptr); srv->plugins.ptr = NULL; srv->plugins.used = 0; diff --git a/src/plugin.h b/src/plugin.h index b43129a..aa64bee 100644 --- a/src/plugin.h +++ b/src/plugin.h @@ -25,19 +25,19 @@ #define URIHANDLER_FUNC CONNECTION_FUNC #define PLUGIN_DATA size_t id - + typedef struct { size_t version; - + buffer *name; /* name of the plugin */ - + void *(* init) (); handler_t (* set_defaults) (server *srv, void *p_d); handler_t (* cleanup) (server *srv, void *p_d); /* is called ... */ handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */ handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */ - + handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */ handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */ handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */ @@ -45,18 +45,18 @@ typedef struct { handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */ handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */ handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */ - - - - handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d); - - /* when a handler for the request + + + + handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d); + + /* when a handler for the request * has to be found */ handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */ handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */ void *data; - + /* dlopen handle */ void *lib; } plugin; diff --git a/src/request.c b/src/request.c index f539c80..eb35332 100644 --- a/src/request.c +++ b/src/request.c @@ -16,9 +16,9 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { int label_len = 0; size_t host_len; char *colon; - int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ + int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */ int level = 0; - + UNUSED(srv); UNUSED(con); @@ -32,17 +32,17 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { * IPv6address = "[" ... "]" * port = *digit */ - + /* no Host: */ if (!host || host->used == 0) return 0; - + host_len = host->used - 1; - + /* IPv6 adress */ if (host->ptr[0] == '[') { char *c = host->ptr + 1; int colon_cnt = 0; - + /* check portnumber */ for (; *c && *c != ']'; c++) { if (*c == ':') { @@ -53,12 +53,12 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { return -1; } } - + /* missing ] */ if (!*c) { return -1; } - + /* check port */ if (*(c+1) == ':') { for (c += 2; *c; c++) { @@ -69,39 +69,39 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { } return 0; } - + if (NULL != (colon = memchr(host->ptr, ':', host_len))) { char *c = colon + 1; - + /* check portnumber */ for (; *c; c++) { if (!light_isdigit(*c)) return -1; } - + /* remove the port from the host-len */ host_len = colon - host->ptr; } - + /* Host is empty */ if (host_len == 0) return -1; - + /* scan from the right and skip the \0 */ for (i = host_len - 1; i + 1 > 0; i--) { const char c = host->ptr[i]; switch (stage) { - case TOPLABEL: + case TOPLABEL: if (c == '.') { /* only switch stage, if this is not the last character */ if (i != host_len - 1) { if (label_len == 0) { return -1; } - + /* check the first character at right of the dot */ if (is_ip == 0) { if (!light_isalpha(host->ptr[i+1])) { - return -1; + return -1; } } else if (!light_isdigit(host->ptr[i+1])) { is_ip = 0; @@ -111,9 +111,9 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { /* just digits */ is_ip = 1; } - + stage = DOMAINLABEL; - + label_len = 0; level++; } else if (i == 0) { @@ -135,7 +135,7 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { } label_len++; } - + break; case DOMAINLABEL: if (is_ip == 1) { @@ -143,7 +143,7 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { if (label_len == 0) { return -1; } - + label_len = 0; level++; } else if (!light_isdigit(c)) { @@ -156,12 +156,12 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { if (label_len == 0) { return -1; } - + /* c is either - or alphanum here */ if ('-' == host->ptr[i+1]) { return -1; } - + label_len = 0; level++; } else if (i == 0) { @@ -176,20 +176,20 @@ static int request_check_hostname(server *srv, connection *con, buffer *host) { label_len++; } } - + break; } } - + /* a IP has to consist of 4 parts */ if (is_ip == 1 && level != 3) { return -1; } - + if (label_len == 0) { return -1; } - + return 0; } @@ -201,53 +201,53 @@ int http_request_split_value(array *vals, buffer *b) { char *s; size_t i; int state = 0; - /* - * parse - * + /* + * parse + * * val1, val2, val3, val4 - * + * * into a array (more or less a explode() incl. striping of whitespaces */ - + if (b->used == 0) return 0; - + s = b->ptr; - + for (i =0; i < b->used - 1; ) { char *start = NULL, *end = NULL; data_string *ds; - + switch (state) { case 0: /* ws */ - + /* skip ws */ for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++); - - + + state = 1; break; case 1: /* value */ start = s; - + for (; *s != ',' && i < b->used - 1; i++, s++); end = s - 1; - + for (; (*end == ' ' || *end == '\t') && end > start; end--); - + if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) { ds = data_string_init(); } buffer_copy_string_len(ds->value, start, end-start+1); array_insert_unique(vals, (data_unset *)ds); - + if (*s == ',') { state = 0; i++; s++; } else { /* end of string */ - + state = 2; } break; @@ -263,7 +263,7 @@ int request_uri_is_valid_char(unsigned char c) { if (c <= 32) return 0; if (c == 127) return 0; if (c == 255) return 0; - + return 1; } @@ -271,28 +271,28 @@ int http_request_parse(server *srv, connection *con) { char *uri = NULL, *proto = NULL, *method = NULL, con_length_set; int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding; char *value = NULL, *key = NULL; - + enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET; - + int line = 0; - + int request_line_stage = 0; size_t i, first; - + int done = 0; - + data_string *ds = NULL; - - /* - * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$" - * Option : "^([-a-zA-Z]+): (.+)$" + + /* + * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$" + * Option : "^([-a-zA-Z]+): (.+)$" * End : "^$" */ if (con->conf.log_request_header) { - log_error_write(srv, __FILE__, __LINE__, "sdsdSb", - "fd:", con->fd, - "request-len:", con->request.request->used, + log_error_write(srv, __FILE__, __LINE__, "sdsdSb", + "fd:", con->fd, + "request-len:", con->request.request->used, "\n", con->request.request); } @@ -300,13 +300,13 @@ int http_request_parse(server *srv, connection *con) { con->request.request->ptr[0] == '\r' && con->request.request->ptr[1] == '\n') { /* we are in keep-alive and might get \r\n after a previous POST request.*/ - + buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2); } else { /* fill the local request buffer */ buffer_copy_string_buffer(con->parse_request, con->request.request); } - + keep_alive_set = 0; con_length_set = 0; @@ -318,25 +318,25 @@ int http_request_parse(server *srv, connection *con) { * */ for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) { char *cur = con->parse_request->ptr + i; - + switch(*cur) { - case '\r': + case '\r': if (con->parse_request->ptr[i+1] == '\n') { http_method_t r; char *nuri = NULL; size_t j; - + /* \r\n -> \0\0 */ con->parse_request->ptr[i] = '\0'; con->parse_request->ptr[i+1] = '\0'; - + buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i); - + if (request_line_stage != 2) { con->http_status = 400; con->response.keep_alive = 0; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", @@ -345,36 +345,36 @@ int http_request_parse(server *srv, connection *con) { } return 0; } - + proto = con->parse_request->ptr + first; - + *(uri - 1) = '\0'; *(proto - 1) = '\0'; - + /* we got the first one :) */ if (-1 == (r = get_http_method_key(method))) { con->http_status = 501; con->response.keep_alive = 0; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request); } - + return 0; } - + con->request.http_method = r; - - /* + + /* * RFC2616 says: * * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT * - * */ + * */ if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) { char * major = proto + sizeof("HTTP/") - 1; char * minor = strchr(major, '.'); @@ -416,7 +416,7 @@ int http_request_parse(server *srv, connection *con) { con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0; } else if (major_num == 1 && minor_num == 0) { con->request.http_version = HTTP_VERSION_1_0; - } else { + } else { con->http_status = 505; if (srv->srvconf.log_request_header_on_error) { @@ -439,30 +439,30 @@ int http_request_parse(server *srv, connection *con) { } return 0; } - + if (0 == strncmp(uri, "http://", 7) && NULL != (nuri = strchr(uri + 7, '/'))) { /* ignore the host-part */ - + buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1); } else { /* everything looks good so far */ buffer_copy_string_len(con->request.uri, uri, proto - uri - 1); } - + /* check uri for invalid characters */ for (j = 0; j < con->request.uri->used - 1; j++) { if (!request_uri_is_valid_char(con->request.uri->ptr[j])) { unsigned char buf[2]; con->http_status = 400; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { buf[0] = con->request.uri->ptr[j]; buf[1] = '\0'; - + if (con->request.uri->ptr[j] > 32 && - con->request.uri->ptr[j] != 127) { + con->request.uri->ptr[j] != 127) { /* the character is printable -> print it */ log_error_write(srv, __FILE__, __LINE__, "ss", "invalid character in URI -> 400", @@ -473,20 +473,20 @@ int http_request_parse(server *srv, connection *con) { "invalid character in URI -> 400", con->request.uri->ptr[j]); } - + log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request); } - + return 0; } } - + buffer_copy_string_buffer(con->request.orig_uri, con->request.uri); - + con->http_status = 0; - + i++; line++; first = i+1; @@ -494,14 +494,14 @@ int http_request_parse(server *srv, connection *con) { break; case ' ': switch(request_line_stage) { - case 0: + case 0: /* GET|POST|... */ - method = con->parse_request->ptr + first; + method = con->parse_request->ptr + first; first = i + 1; break; case 1: /* /foobar/... */ - uri = con->parse_request->ptr + first; + uri = con->parse_request->ptr + first; first = i + 1; break; default: @@ -509,7 +509,7 @@ int http_request_parse(server *srv, connection *con) { con->http_status = 400; con->response.keep_alive = 0; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", @@ -518,12 +518,12 @@ int http_request_parse(server *srv, connection *con) { } return 0; } - + request_line_stage++; break; } } - + in_folding = 0; if (con->request.uri->used == 1) { @@ -540,30 +540,30 @@ int http_request_parse(server *srv, connection *con) { return 0; } - + for (; i < con->parse_request->used && !done; i++) { char *cur = con->parse_request->ptr + i; - + if (is_key) { size_t j; int got_colon = 0; - + /** * 1*<any CHAR except CTLs or separators> * CTLs == 0-31 + 127 - * + * */ switch(*cur) { case ':': is_key = 0; - + value = cur + 1; - + if (is_ws_after_key == 0) { key_len = i - first; } is_ws_after_key = 0; - + break; case '(': case ')': @@ -584,8 +584,8 @@ int http_request_parse(server *srv, connection *con) { con->http_status = 400; con->keep_alive = 0; con->response.keep_alive = 0; - - log_error_write(srv, __FILE__, __LINE__, "sbsds", + + log_error_write(srv, __FILE__, __LINE__, "sbsds", "invalid character in key", con->request.request, cur, *cur, "-> 400"); return 0; case ' ': @@ -594,13 +594,13 @@ int http_request_parse(server *srv, connection *con) { is_key = 0; in_folding = 1; value = cur; - + break; } - - + + key_len = i - first; - + /* skip every thing up to the : */ for (j = 1; !got_colon; j++) { switch(con->parse_request->ptr[j + i]) { @@ -610,40 +610,40 @@ int http_request_parse(server *srv, connection *con) { continue; case ':': /* ok, done */ - + i += j - 1; got_colon = 1; - + break; default: /* error */ - + if (srv->srvconf.log_request_header_on_error) { log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request); } - + con->http_status = 400; con->response.keep_alive = 0; con->keep_alive = 0; - + return 0; } } - + break; case '\r': if (con->parse_request->ptr[i+1] == '\n' && i == first) { /* End of Header */ con->parse_request->ptr[i] = '\0'; con->parse_request->ptr[i+1] = '\0'; - + i++; - + done = 1; - + break; } else { if (srv->srvconf.log_request_header_on_error) { @@ -652,7 +652,7 @@ int http_request_parse(server *srv, connection *con) { "request-header:\n", con->request.request); } - + con->http_status = 400; con->keep_alive = 0; con->response.keep_alive = 0; @@ -693,16 +693,16 @@ int http_request_parse(server *srv, connection *con) { con->http_status = 400; con->keep_alive = 0; con->response.keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { - log_error_write(srv, __FILE__, __LINE__, "sbsds", + log_error_write(srv, __FILE__, __LINE__, "sbsds", "CTL character in key", con->request.request, cur, *cur, "-> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request); } - + return 0; default: /* ok */ @@ -710,25 +710,25 @@ int http_request_parse(server *srv, connection *con) { } } else { switch(*cur) { - case '\r': + case '\r': if (con->parse_request->ptr[i+1] == '\n') { /* End of Headerline */ con->parse_request->ptr[i] = '\0'; con->parse_request->ptr[i+1] = '\0'; - + if (in_folding) { if (!ds) { /* 400 */ - + if (srv->srvconf.log_request_header_on_error) { log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400"); - + log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", con->request.request); } - + con->http_status = 400; con->keep_alive = 0; con->response.keep_alive = 0; @@ -738,9 +738,9 @@ int http_request_parse(server *srv, connection *con) { } else { int s_len; key = con->parse_request->ptr + first; - + s_len = cur - value; - + if (s_len > 0) { int cmp = 0; if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) { @@ -748,50 +748,50 @@ int http_request_parse(server *srv, connection *con) { } buffer_copy_string_len(ds->key, key, key_len); buffer_copy_string_len(ds->value, value, s_len); - - /* retreive values - * - * + + /* retreive values + * + * * the list of options is sorted to simplify the search */ - + if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) { array *vals; size_t vi; - + /* split on , */ - + vals = srv->split_vals; array_reset(vals); - + http_request_split_value(vals, ds->value); - + for (vi = 0; vi < vals->used; vi++) { data_string *dsv = (data_string *)vals->data[vi]; - + if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) { keep_alive_set = HTTP_CONNECTION_KEEPALIVE; - + break; } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) { keep_alive_set = HTTP_CONNECTION_CLOSE; - + break; } } - + } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) { char *err; unsigned long int r; size_t j; - + if (con_length_set) { con->http_status = 400; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "duplicate Content-Length-header -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", @@ -799,35 +799,35 @@ int http_request_parse(server *srv, connection *con) { } return 0; } - + if (ds->value->used == 0) SEGFAULT(); - + for (j = 0; j < ds->value->used - 1; j++) { char c = ds->value->ptr[j]; if (!isdigit((unsigned char)c)) { - log_error_write(srv, __FILE__, __LINE__, "sbs", + log_error_write(srv, __FILE__, __LINE__, "sbs", "content-length broken:", ds->value, "-> 400"); - + con->http_status = 400; con->keep_alive = 0; - + array_insert_unique(con->request.headers, (data_unset *)ds); return 0; } } - + r = strtoul(ds->value->ptr, &err, 10); - + if (*err == '\0') { con_length_set = 1; con->request.content_length = r; } else { - log_error_write(srv, __FILE__, __LINE__, "sbs", + log_error_write(srv, __FILE__, __LINE__, "sbs", "content-length broken:", ds->value, "-> 400"); - + con->http_status = 400; con->keep_alive = 0; - + array_insert_unique(con->request.headers, (data_unset *)ds); return 0; } @@ -838,9 +838,9 @@ int http_request_parse(server *srv, connection *con) { } else { con->http_status = 400; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "duplicate Content-Type-header -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", @@ -849,12 +849,12 @@ 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("Expect")))) { - /* HTTP 2616 8.2.3 + /* HTTP 2616 8.2.3 * Expect: 100-continue - * + * * -> (10.1.1) 100 (read content, process request, send final status-code) * -> (10.4.18) 417 (close) - * + * * (not handled at all yet, we always send 417 here) * * What has to be added ? @@ -863,10 +863,10 @@ int http_request_parse(server *srv, connection *con) { * header * */ - + con->http_status = 417; con->keep_alive = 0; - + array_insert_unique(con->request.headers, (data_unset *)ds); return 0; } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) { @@ -875,9 +875,9 @@ int http_request_parse(server *srv, connection *con) { } else { con->http_status = 400; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "duplicate Host-header -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", @@ -897,9 +897,9 @@ int http_request_parse(server *srv, connection *con) { } else { con->http_status = 400; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "duplicate If-Modified-Since header -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", @@ -914,9 +914,9 @@ int http_request_parse(server *srv, connection *con) { } else { con->http_status = 400; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "duplicate If-None-Match-header -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", @@ -927,19 +927,19 @@ int http_request_parse(server *srv, connection *con) { } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) { if (!con->request.http_range) { /* bytes=.*-.* */ - + if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) && NULL != strchr(ds->value->ptr+6, '-')) { - + /* if dup, only the first one will survive */ con->request.http_range = ds->value->ptr + 6; } } else { con->http_status = 400; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "duplicate Range-header -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", "request-header:\n", @@ -948,13 +948,13 @@ int http_request_parse(server *srv, connection *con) { return 0; } } - + array_insert_unique(con->request.headers, (data_unset *)ds); } else { /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */ } } - + i++; first = i+1; is_key = 1; @@ -963,10 +963,10 @@ int http_request_parse(server *srv, connection *con) { in_folding = 0; } else { if (srv->srvconf.log_request_header_on_error) { - log_error_write(srv, __FILE__, __LINE__, "sbs", + log_error_write(srv, __FILE__, __LINE__, "sbs", "CR without LF", con->request.request, "-> 400"); } - + con->http_status = 400; con->keep_alive = 0; con->response.keep_alive = 0; @@ -982,28 +982,28 @@ int http_request_parse(server *srv, connection *con) { } } } - + con->header_len = i; - + /* do some post-processing */ if (con->request.http_version == HTTP_VERSION_1_1) { if (keep_alive_set != HTTP_CONNECTION_CLOSE) { /* no Connection-Header sent */ - + /* HTTP/1.1 -> keep-alive default TRUE */ con->keep_alive = 1; } else { con->keep_alive = 0; } - + /* RFC 2616, 14.23 */ if (con->request.http_host == NULL || buffer_is_empty(con->request.http_host)) { con->http_status = 400; con->response.keep_alive = 0; con->keep_alive = 0; - + if (srv->srvconf.log_request_header_on_error) { log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400"); log_error_write(srv, __FILE__, __LINE__, "Sb", @@ -1015,18 +1015,18 @@ int http_request_parse(server *srv, connection *con) { } else { if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) { /* no Connection-Header sent */ - + /* HTTP/1.0 -> keep-alive default FALSE */ con->keep_alive = 1; } else { con->keep_alive = 0; } } - + /* check hostname field if it is set */ if (NULL != con->request.http_host && 0 != request_check_hostname(srv, con, con->request.http_host)) { - + if (srv->srvconf.log_request_header_on_error) { log_error_write(srv, __FILE__, __LINE__, "s", "Invalid Hostname -> 400"); @@ -1038,7 +1038,7 @@ int http_request_parse(server *srv, connection *con) { con->http_status = 400; con->response.keep_alive = 0; con->keep_alive = 0; - + return 0; } @@ -1048,7 +1048,7 @@ int http_request_parse(server *srv, connection *con) { /* 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", + log_error_write(srv, __FILE__, __LINE__, "s", "GET/HEAD with content-length -> 400"); con->keep_alive = 0; @@ -1060,7 +1060,7 @@ int http_request_parse(server *srv, connection *con) { /* content-length is required for them */ if (!con_length_set) { /* content-length is missing */ - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "POST-request, but content-length missing -> 411"); con->keep_alive = 0; @@ -1073,16 +1073,16 @@ int http_request_parse(server *srv, connection *con) { /* 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; + con->http_status = 413; con->keep_alive = 0; - log_error_write(srv, __FILE__, __LINE__, "sds", + log_error_write(srv, __FILE__, __LINE__, "sds", "request-size too long:", con->request.content_length, "-> 413"); return 0; } @@ -1090,25 +1090,25 @@ int http_request_parse(server *srv, connection *con) { /* divide by 1024 as srvconf.max_request_size is in kBytes */ if (srv->srvconf.max_request_size != 0 && (con->request.content_length >> 10) > srv->srvconf.max_request_size) { - /* the request body itself is larger then + /* the request body itself is larger then * our our max_request_size */ - + con->http_status = 413; con->keep_alive = 0; - - log_error_write(srv, __FILE__, __LINE__, "sds", + + log_error_write(srv, __FILE__, __LINE__, "sds", "request-size too long:", con->request.content_length, "-> 413"); return 0; } - - + + /* we have content */ if (con->request.content_length != 0) { return 1; } } - + return 0; } @@ -1116,9 +1116,9 @@ int http_request_header_finished(server *srv, connection *con) { UNUSED(srv); if (con->request.request->used < 5) return 0; - + if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1; if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1; - + return 0; } diff --git a/src/response.c b/src/response.c index 45a1782..5f72a9b 100644 --- a/src/response.c +++ b/src/response.c @@ -30,9 +30,9 @@ int http_response_write_header(server *srv, connection *con) { size_t i; int have_date = 0; int have_server = 0; - + b = chunkqueue_get_prepend_buffer(con->write_queue); - + if (con->request.http_version == HTTP_VERSION_1_1) { BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 "); } else { @@ -41,23 +41,23 @@ int http_response_write_header(server *srv, connection *con) { buffer_append_long(b, con->http_status); BUFFER_APPEND_STRING_CONST(b, " "); buffer_append_string(b, get_http_status_name(con->http_status)); - + if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) { BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: "); buffer_append_string(b, con->keep_alive ? "keep-alive" : "close"); } - + if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) { BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked"); } - - + + /* add all headers */ for (i = 0; i < con->response.headers->used; i++) { data_string *ds; - + ds = (data_string *)con->response.headers->data[i]; - + if (ds->value->used && ds->key->used && 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) { if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1; @@ -68,28 +68,28 @@ int http_response_write_header(server *srv, connection *con) { BUFFER_APPEND_STRING_CONST(b, ": "); buffer_append_string_buffer(b, ds->value); #if 0 - log_error_write(srv, __FILE__, __LINE__, "bb", + log_error_write(srv, __FILE__, __LINE__, "bb", ds->key, ds->value); #endif } } - + if (!have_date) { /* HTTP/1.1 requires a Date: header */ BUFFER_APPEND_STRING_CONST(b, "\r\nDate: "); - + /* cache the generated timestamp */ if (srv->cur_ts != srv->last_generated_date_ts) { buffer_prepare_copy(srv->ts_date_str, 255); - - strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, + + strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts))); - + srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1; - + srv->last_generated_date_ts = srv->cur_ts; } - + buffer_append_string_buffer(b, srv->ts_date_str); } @@ -101,16 +101,16 @@ int http_response_write_header(server *srv, connection *con) { buffer_append_string_buffer(b, con->conf.server_tag); } } - + BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n"); - - + + con->bytes_header = b->used - 1; - + if (con->conf.log_response_header) { log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b); } - + return 0; } @@ -118,71 +118,77 @@ int http_response_write_header(server *srv, connection *con) { handler_t http_response_prepare(server *srv, connection *con) { handler_t r; - + /* looks like someone has already done a decision */ - if (con->mode == DIRECT && + if (con->mode == DIRECT && (con->http_status != 0 && con->http_status != 200)) { /* remove a packets in the queue */ if (con->file_finished == 0) { chunkqueue_reset(con->write_queue); } - + return HANDLER_FINISHED; } - + /* 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 + * + * 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"); } config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */ - + /** * prepare strings - * - * - uri.path_raw + * + * - uri.path_raw * - uri.path (secure) * - uri.query - * + * */ - - /** + + /** * Name according to RFC 2396 - * + * * - scheme * - authority * - path * - query - * - * (scheme)://(authority)(path)?(query) - * - * + * + * (scheme)://(authority)(path)?(query)#fragment + * + * */ - + buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http"); buffer_copy_string_buffer(con->uri.authority, con->request.http_host); buffer_to_lower(con->uri.authority); - + config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */ config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */ config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */ config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */ config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */ - + + /** their might be a fragment which has to be cut away */ + if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) { + con->request.uri->used = qstr - con->request.uri->ptr; + con->request.uri->ptr[con->request.uri->used++] = '\0'; + } + /** extract query string from request.uri */ if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) { buffer_copy_string (con->uri.query, qstr + 1); @@ -200,22 +206,22 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path_raw); log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query); } - + /* disable keep-alive if requested */ - + if (con->request_count > con->conf.max_keep_alive_requests) { con->keep_alive = 0; } - - + + /** - * - * call plugins - * + * + * call plugins + * * - based on the raw URL - * + * */ - + switch(r = plugins_call_handle_uri_raw(srv, con)) { case HANDLER_GO_ON: break; @@ -229,14 +235,14 @@ handler_t http_response_prepare(server *srv, connection *con) { break; } - /* build filename + /* build filename * * - decode url-encodings (e.g. %20 -> ' ') * - remove path-modifiers (e.g. /../) */ - - - + + + if (con->request.http_method == HTTP_METHOD_OPTIONS && con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') { /* OPTIONS * ... */ @@ -253,13 +259,13 @@ handler_t http_response_prepare(server *srv, connection *con) { } /** - * - * call plugins - * + * + * call plugins + * * - based on the clean URL - * + * */ - + config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */ config_patch_connection(srv, con, COMP_HTTP_QUERYSTRING); /* HTTPqs */ @@ -280,11 +286,11 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, ""); break; } - + if (con->request.http_method == HTTP_METHOD_OPTIONS && con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') { /* option requests are handled directly without checking of the path */ - + response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST")); con->http_status = 200; @@ -294,38 +300,38 @@ handler_t http_response_prepare(server *srv, connection *con) { } /*** - * - * border - * + * + * border + * * logical filename (URI) becomes a physical filename here - * - * - * + * + * + * */ - - - - + + + + /* 1. stat() * ... ISREG() -> ok, go on * ... ISDIR() -> index-file -> redirect - * - * 2. pathinfo() + * + * 2. pathinfo() * ... ISREG() - * + * * 3. -> 404 - * + * */ - + /* * SEARCH DOCUMENT ROOT */ - + /* set a default */ - + buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root); buffer_copy_string_buffer(con->physical.rel_path, con->uri.path); - + #if defined(__WIN32) || defined(__CYGWIN__) /* strip dots from the end and spaces * @@ -383,9 +389,9 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, ""); break; } - - /* MacOS X and Windows can't distiguish between upper and lower-case - * + + /* MacOS X and Windows can't distiguish between upper and lower-case + * * convert to lower-case */ if (con->conf.force_lowercase_filenames) { @@ -396,13 +402,13 @@ handler_t http_response_prepare(server *srv, connection *con) { if (buffer_is_empty(con->server_name)) { buffer_copy_string_buffer(con->server_name, con->uri.authority); } - - /** - * create physical filename + + /** + * create physical filename * -> physical.path = docroot + rel_path - * + * */ - + buffer_copy_string_buffer(con->physical.path, con->physical.doc_root); BUFFER_APPEND_SLASH(con->physical.path); buffer_copy_string_buffer(con->physical.basedir, con->physical.path); @@ -432,7 +438,7 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, ""); break; } - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical"); log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root); @@ -440,19 +446,19 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } } - - /* + + /* * Noone catched away the file from normal path of execution yet (like mod_access) - * + * * Go on and check of the file exists at all */ - + if (con->mode == DIRECT) { char *slash = NULL; char *pathinfo = NULL; int found = 0; stat_cache_entry *sce = NULL; - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); @@ -460,7 +466,7 @@ handler_t http_response_prepare(server *srv, connection *con) { if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) { /* file exists */ - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- file found"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); @@ -481,9 +487,9 @@ handler_t http_response_prepare(server *srv, connection *con) { if (S_ISDIR(sce->st.st_mode)) { if (con->physical.path->ptr[con->physical.path->used - 2] != '/') { /* redirect to .../ */ - + http_response_redirect_to_directory(srv, con); - + return HANDLER_FINISHED; } #ifdef HAVE_LSTAT @@ -499,12 +505,12 @@ handler_t http_response_prepare(server *srv, connection *con) { switch (errno) { case EACCES: con->http_status = 403; - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } - + buffer_reset(con->physical.path); return HANDLER_FINISHED; case ENOENT: @@ -524,74 +530,74 @@ handler_t http_response_prepare(server *srv, connection *con) { /* we have no idea what happend. let's tell the user so. */ con->http_status = 500; buffer_reset(con->physical.path); - + log_error_write(srv, __FILE__, __LINE__, "ssbsb", "file not found ... or so: ", strerror(errno), con->uri.path, "->", con->physical.path); - + return HANDLER_FINISHED; } - + /* not found, perhaps PATHINFO */ - + buffer_copy_string_buffer(srv->tmp_buf, con->physical.path); - + do { struct stat st; - + if (slash) { buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr); } else { buffer_copy_string_buffer(con->physical.path, srv->tmp_buf); } - + if (0 == stat(con->physical.path->ptr, &(st)) && S_ISREG(st.st_mode)) { found = 1; break; } - + if (pathinfo != NULL) { *pathinfo = '\0'; } slash = strrchr(srv->tmp_buf->ptr, '/'); - + if (pathinfo != NULL) { /* restore '/' */ *pathinfo = '/'; } - + if (slash) pathinfo = slash; - } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2)); - + } while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2))); + if (found == 0) { /* no it really doesn't exists */ con->http_status = 404; - + if (con->conf.log_file_not_found) { log_error_write(srv, __FILE__, __LINE__, "sbsb", "file not found:", con->uri.path, "->", con->physical.path); } - + buffer_reset(con->physical.path); - + return HANDLER_FINISHED; } - + /* we have a PATHINFO */ if (pathinfo) { buffer_copy_string(con->request.pathinfo, pathinfo); - + /* * shorten uri.path */ - + con->uri.path->used -= strlen(pathinfo); con->uri.path->ptr[con->uri.path->used - 1] = '\0'; } - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); @@ -599,12 +605,12 @@ handler_t http_response_prepare(server *srv, connection *con) { log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo); } } - + if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest"); log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path); } - + /* call the handlers */ switch(r = plugins_call_handle_subrequest_start(srv, con)) { case HANDLER_GO_ON: @@ -615,21 +621,21 @@ handler_t http_response_prepare(server *srv, connection *con) { if (con->conf.log_request_handling) { log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished"); } - + /* something strange happend */ return r; } - + /* if we are still here, no one wanted the file, status 403 is ok I think */ - + if (con->mode == DIRECT) { con->http_status = 403; - + return HANDLER_FINISHED; } - + } - + switch(r = plugins_call_handle_subrequest(srv, con)) { case HANDLER_GO_ON: /* request was not handled, looks like we are done */ @@ -640,7 +646,7 @@ handler_t http_response_prepare(server *srv, connection *con) { /* something strange happend */ return r; } - + /* can't happen */ return HANDLER_COMEBACK; } diff --git a/src/server.c b/src/server.c index 0222a22..f0e9ee1 100644 --- a/src/server.c +++ b/src/server.c @@ -55,6 +55,10 @@ #include <sys/prctl.h> #endif +#ifdef USE_OPENSSL +# include <openssl/err.h> +#endif + #ifndef __sgi /* IRIX doesn't like the alarm based time() optimization */ /* #define USE_ALARM */ @@ -72,9 +76,9 @@ static void sigaction_handler(int sig, siginfo_t *si, void *context) { switch (sig) { case SIGTERM: srv_shutdown = 1; break; - case SIGINT: + case SIGINT: if (graceful_shutdown) srv_shutdown = 1; - else graceful_shutdown = 1; + else graceful_shutdown = 1; break; case SIGALRM: handle_sig_alarm = 1; break; @@ -86,9 +90,9 @@ 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: + case SIGINT: if (graceful_shutdown) srv_shutdown = 1; - else graceful_shutdown = 1; + else graceful_shutdown = 1; break; case SIGALRM: handle_sig_alarm = 1; break; @@ -110,25 +114,25 @@ static void daemonize(void) { signal(SIGTSTP, SIG_IGN); #endif if (0 != fork()) exit(0); - + if (-1 == setsid()) exit(0); signal(SIGHUP, SIG_IGN); if (0 != fork()) exit(0); - + if (0 != chdir("/")) exit(0); } #endif static server *server_init(void) { int i; - + server *srv = calloc(1, sizeof(*srv)); assert(srv); #define CLEAN(x) \ srv->x = buffer_init(); - + CLEAN(response_header); CLEAN(parse_full_path); CLEAN(ts_debug_str); @@ -138,7 +142,7 @@ static server *server_init(void) { CLEAN(tmp_buf); srv->empty_string = buffer_init_string(""); CLEAN(cond_check_buf); - + CLEAN(srvconf.errorlog_file); CLEAN(srvconf.groupname); CLEAN(srvconf.username); @@ -146,58 +150,58 @@ static server *server_init(void) { CLEAN(srvconf.bindhost); CLEAN(srvconf.event_handler); CLEAN(srvconf.pid_file); - + CLEAN(tmp_chunk_len); #undef CLEAN - + #define CLEAN(x) \ srv->x = array_init(); - + CLEAN(config_context); CLEAN(config_touched); CLEAN(status); #undef CLEAN - + for (i = 0; i < FILE_CACHE_MAX; i++) { srv->mtime_cache[i].str = buffer_init(); } - + srv->cur_ts = time(NULL); srv->startup_ts = srv->cur_ts; - + srv->conns = calloc(1, sizeof(*srv->conns)); assert(srv->conns); - + srv->joblist = calloc(1, sizeof(*srv->joblist)); assert(srv->joblist); - + srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue)); assert(srv->fdwaitqueue); - + srv->srvconf.modules = array_init(); srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR); srv->srvconf.network_backend = buffer_init(); srv->srvconf.upload_tempdirs = array_init(); - + /* use syslog */ srv->errorlog_fd = -1; srv->errorlog_mode = ERRORLOG_STDERR; srv->split_vals = array_init(); - + return srv; } static void server_free(server *srv) { size_t i; - + for (i = 0; i < FILE_CACHE_MAX; i++) { buffer_free(srv->mtime_cache[i].str); } - + #define CLEAN(x) \ buffer_free(srv->x); - + CLEAN(response_header); CLEAN(parse_full_path); CLEAN(ts_debug_str); @@ -207,7 +211,7 @@ static void server_free(server *srv) { CLEAN(tmp_buf); CLEAN(empty_string); CLEAN(cond_check_buf); - + CLEAN(srvconf.errorlog_file); CLEAN(srvconf.groupname); CLEAN(srvconf.username); @@ -217,7 +221,7 @@ static void server_free(server *srv) { CLEAN(srvconf.pid_file); CLEAN(srvconf.modules_dir); CLEAN(srvconf.network_backend); - + CLEAN(tmp_chunk_len); #undef CLEAN @@ -225,49 +229,61 @@ static void server_free(server *srv) { fdevent_unregister(srv->ev, srv->fd); #endif fdevent_free(srv->ev); - + free(srv->conns); - + if (srv->config_storage) { for (i = 0; i < srv->config_context->used; i++) { specific_config *s = srv->config_storage[i]; if (!s) continue; - + buffer_free(s->document_root); buffer_free(s->server_name); buffer_free(s->server_tag); buffer_free(s->ssl_pemfile); buffer_free(s->ssl_ca_file); + buffer_free(s->ssl_cipher_list); buffer_free(s->error_handler); buffer_free(s->errorfile_prefix); array_free(s->mimetypes); - +#ifdef USE_OPENSSL + SSL_CTX_free(s->ssl_ctx); +#endif free(s); } free(srv->config_storage); srv->config_storage = NULL; } - + #define CLEAN(x) \ array_free(srv->x); - + CLEAN(config_context); CLEAN(config_touched); CLEAN(status); CLEAN(srvconf.upload_tempdirs); #undef CLEAN - + joblist_free(srv, srv->joblist); fdwaitqueue_free(srv, srv->fdwaitqueue); - + if (srv->stat_cache) { stat_cache_free(srv->stat_cache); } array_free(srv->srvconf.modules); array_free(srv->split_vals); - + +#ifdef USE_OPENSSL + if (srv->ssl_is_init) { + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + ERR_remove_state(0); + EVP_cleanup(); + } +#endif + free(srv); } @@ -281,7 +297,7 @@ static void show_version (void) { " - a light and fast webserver\n" \ "Build-Date: " __DATE__ " " __TIME__ "\n"; ; -#undef TEXT_SSL +#undef TEXT_SSL write(STDOUT_FILENO, b, strlen(b)); } @@ -427,7 +443,7 @@ static void show_help (void) { " -h show this help\n" \ "\n" ; -#undef TEXT_SSL +#undef TEXT_SSL #undef TEXT_IPV6 write(STDOUT_FILENO, b, strlen(b)); } @@ -447,27 +463,27 @@ int main (int argc, char **argv) { #ifdef HAVE_GETRLIMIT struct rlimit rlim; #endif - + #ifdef USE_ALARM struct itimerval interval; - + interval.it_interval.tv_sec = 1; interval.it_interval.tv_usec = 0; interval.it_value.tv_sec = 1; interval.it_value.tv_usec = 0; #endif - - + + /* for nice %b handling in strfime() */ setlocale(LC_TIME, "C"); - + if (NULL == (srv = server_init())) { fprintf(stderr, "did this really happen?\n"); return -1; } - + /* init structs done */ - + srv->srvconf.port = 0; #ifdef HAVE_GETUID i_am_root = (getuid() == 0); @@ -475,11 +491,11 @@ int main (int argc, char **argv) { i_am_root = 0; #endif srv->srvconf.dont_daemonize = 0; - + while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) { switch(o) { - case 'f': - if (config_read(srv, optarg)) { + case 'f': + if (config_read(srv, optarg)) { server_free(srv); return -1; } @@ -491,23 +507,23 @@ int main (int argc, char **argv) { case 't': test_config = 1; break; case 'D': srv->srvconf.dont_daemonize = 1; break; case 'v': show_version(); return 0; - case 'V': show_features(); return 0; + case 'V': show_features(); return 0; case 'h': show_help(); return 0; - default: + default: show_help(); server_free(srv); return -1; } } - + if (!srv->config_storage) { log_error_write(srv, __FILE__, __LINE__, "s", "No configuration available. Try using -f option."); - + server_free(srv); return -1; } - + if (print_config) { data_unset *dc = srv->config_context->data[0]; if (dc) { @@ -527,7 +543,7 @@ int main (int argc, char **argv) { server_free(srv); return 0; } - + /* close stdin and stdout, as they are not needed */ /* move stdin to /dev/null */ if (-1 != (fd = open("/dev/null", O_RDONLY))) { @@ -535,54 +551,54 @@ int main (int argc, char **argv) { dup2(fd, STDIN_FILENO); close(fd); } - + /* move stdout to /dev/null */ if (-1 != (fd = open("/dev/null", O_WRONLY))) { close(STDOUT_FILENO); dup2(fd, STDOUT_FILENO); close(fd); } - + if (0 != config_set_defaults(srv)) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "setting default values failed"); server_free(srv); return -1; } - + /* UID handling */ #ifdef HAVE_GETUID if (!i_am_root && (geteuid() == 0 || getegid() == 0)) { /* we are setuid-root */ - - log_error_write(srv, __FILE__, __LINE__, "s", + + log_error_write(srv, __FILE__, __LINE__, "s", "Are you nuts ? Don't apply a SUID bit to this binary"); - + server_free(srv); return -1; } #endif - + /* check document-root */ if (srv->config_storage[0]->document_root->used <= 1) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "document-root is not set\n"); - + server_free(srv); - + return -1; } - + if (plugins_load(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "loading plugins finally failed"); - + plugins_free(srv); server_free(srv); - + return -1; } - + /* open pid file BEFORE chroot */ if (srv->srvconf.pid_file->used) { if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { @@ -592,18 +608,18 @@ int main (int argc, char **argv) { "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); return -1; } - + if (0 != stat(srv->srvconf.pid_file->ptr, &st)) { log_error_write(srv, __FILE__, __LINE__, "sbs", "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno)); } - + if (!S_ISREG(st.st_mode)) { log_error_write(srv, __FILE__, __LINE__, "sb", "pid-file exists and isn't regular file:", srv->srvconf.pid_file); return -1; } - + if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { log_error_write(srv, __FILE__, __LINE__, "sbs", "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno)); @@ -630,7 +646,7 @@ int main (int argc, char **argv) { #ifdef HAVE_VALGRIND_VALGRIND_H if (RUNNING_ON_VALGRIND) use_rlimit = 0; #endif - + #ifdef HAVE_GETRLIMIT if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, @@ -638,13 +654,13 @@ int main (int argc, char **argv) { strerror(errno)); return -1; } - + if (use_rlimit && srv->srvconf.max_fds) { /* set rlimits */ - + rlim.rlim_cur = srv->srvconf.max_fds; rlim.rlim_max = srv->srvconf.max_fds; - + if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) { log_error_write(srv, __FILE__, __LINE__, "ss", "couldn't set 'max filedescriptors'", @@ -653,7 +669,7 @@ int main (int argc, char **argv) { } } - /* #372: solaris need some fds extra for devpoll */ + /* #372: solaris need some fds extra for devpoll */ if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10; if (srv->event_handler == FDEVENT_HANDLER_SELECT) { @@ -671,33 +687,33 @@ int main (int argc, char **argv) { if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > FD_SETSIZE - 200) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } - + #ifdef HAVE_PWD_H /* set user and group */ if (srv->srvconf.username->used) { if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "can't find username", srv->srvconf.username); return -1; } - + if (pwd->pw_uid == 0) { log_error_write(srv, __FILE__, __LINE__, "s", "I will not set uid to 0\n"); return -1; } } - + if (srv->srvconf.groupname->used) { if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) { - log_error_write(srv, __FILE__, __LINE__, "sb", + log_error_write(srv, __FILE__, __LINE__, "sb", "can't find groupname", srv->srvconf.groupname); return -1; } @@ -707,15 +723,15 @@ int main (int argc, char **argv) { return -1; } } -#endif +#endif /* we need root-perms for port < 1024 */ if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); - + return -1; } -#ifdef HAVE_CHROOT +#ifdef HAVE_CHROOT if (srv->srvconf.changeroot->used) { tzset(); @@ -735,9 +751,13 @@ int main (int argc, char **argv) { setgid(grp->gr_gid); setgroups(0, NULL); } - if (srv->srvconf.username->used && srv->srvconf.groupname->used) - initgroups(srv->srvconf.username->ptr, grp->gr_gid); - if (srv->srvconf.username->used) setuid(pwd->pw_uid); + + if (srv->srvconf.username->used) { + if (srv->srvconf.groupname->used) { + initgroups(srv->srvconf.username->ptr, grp->gr_gid); + } + setuid(pwd->pw_uid); + } #endif #ifdef HAVE_PRCTL if (srv->srvconf.enable_cores) { @@ -770,17 +790,17 @@ int main (int argc, char **argv) { if (srv->event_handler == FDEVENT_HANDLER_SELECT) { /* don't raise the limit above FD_SET_SIZE */ if (srv->max_fds > FD_SETSIZE - 200) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "can't raise max filedescriptors above", FD_SETSIZE - 200, "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds."); return -1; } } - + if (0 != network_init(srv)) { plugins_free(srv); server_free(srv); - + return -1; } } @@ -796,25 +816,25 @@ int main (int argc, char **argv) { /* or use the default */ srv->max_conns = srv->max_fds; } - + if (HANDLER_GO_ON != plugins_call_init(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down."); - + plugins_free(srv); network_close(srv); server_free(srv); - + return -1; } -#ifdef HAVE_FORK +#ifdef HAVE_FORK /* network is up, let's deamonize ourself */ if (srv->srvconf.dont_daemonize == 0) daemonize(); #endif srv->gid = getgid(); srv->uid = getuid(); - + /* write pid file */ if (pid_fd != -1) { buffer_copy_long(srv->tmp_buf, getpid()); @@ -823,17 +843,17 @@ int main (int argc, char **argv) { close(pid_fd); pid_fd = -1; } - + if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down."); - + plugins_free(srv); network_close(srv); server_free(srv); - + return -1; } - + /* dump unused config-keys */ for (i = 0; i < srv->config_context->used; i++) { array *config = ((data_config *)srv->config_context->data[i])->value; @@ -841,14 +861,14 @@ int main (int argc, char **argv) { for (j = 0; config && j < config->used; j++) { data_unset *du = config->data[j]; - + /* all var.* is known as user defined variable */ if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) { continue; } if (NULL == array_get_element(srv->config_touched, du->key->ptr)) { - log_error_write(srv, __FILE__, __LINE__, "sbs", + log_error_write(srv, __FILE__, __LINE__, "sbs", "WARNING: unknown config-key:", du->key, "(ignored)"); @@ -857,12 +877,12 @@ int main (int argc, char **argv) { } if (srv->config_unsupported) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains unsupported keys. Going down."); } if (srv->config_deprecated) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "Configuration contains deprecated keys. Going down."); } @@ -875,7 +895,7 @@ int main (int argc, char **argv) { } if (-1 == log_error_open(srv)) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "opening errorlog failed, dying"); plugins_free(srv); @@ -883,8 +903,8 @@ int main (int argc, char **argv) { server_free(srv); return -1; } - - + + #ifdef HAVE_SIGACTION memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; @@ -904,7 +924,7 @@ int main (int argc, char **argv) { sigaction(SIGHUP, &act, NULL); sigaction(SIGALRM, &act, NULL); sigaction(SIGCHLD, &act, NULL); - + #elif defined(HAVE_SIGNAL) /* ignore the SIGPIPE from sendfile() */ signal(SIGPIPE, SIG_IGN); @@ -915,20 +935,20 @@ int main (int argc, char **argv) { signal(SIGCHLD, signal_handler); signal(SIGINT, signal_handler); #endif - + #ifdef USE_ALARM signal(SIGALRM, signal_handler); - + /* setup periodic timer (1 second) */ if (setitimer(ITIMER_REAL, &interval, NULL)) { log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed"); return -1; } - + getitimer(ITIMER_REAL, &interval); #endif -#ifdef HAVE_FORK +#ifdef HAVE_FORK /* start watcher and workers */ num_childs = srv->srvconf.max_worker; if (num_childs > 0) { @@ -964,8 +984,8 @@ int main (int argc, char **argv) { "s", "fdevent_init failed"); return -1; } - /* - * kqueue() is called here, select resets its internals, + /* + * kqueue() is called here, select resets its internals, * all server sockets get their handlers * * */ @@ -973,7 +993,7 @@ int main (int argc, char **argv) { plugins_free(srv); network_close(srv); server_free(srv); - + return -1; } @@ -988,7 +1008,7 @@ int main (int argc, char **argv) { /* setup FAM */ if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) { - log_error_write(srv, __FILE__, __LINE__, "s", + log_error_write(srv, __FILE__, __LINE__, "s", "could not open a fam connection, dieing."); return -1; } @@ -1020,16 +1040,16 @@ int main (int argc, char **argv) { int n; size_t ndx; time_t min_ts; - + if (handle_sig_hup) { handler_t r; - + /* reset notification */ handle_sig_hup = 0; - - + + /* cycle logfiles */ - + switch(r = plugins_call_handle_sighup(srv)) { case HANDLER_GO_ON: break; @@ -1037,30 +1057,30 @@ int main (int argc, char **argv) { log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r); break; } - + if (-1 == log_error_cycle(srv)) { log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying"); - + return -1; } } - + if (handle_sig_alarm) { /* a new second */ - + #ifdef USE_ALARM /* reset notification */ handle_sig_alarm = 0; #endif - + /* get current time */ min_ts = time(NULL); - + if (min_ts != srv->cur_ts) { int cs = 0; connections *conns = srv->conns; handler_t r; - + switch(r = plugins_call_handle_trigger(srv)) { case HANDLER_GO_ON: break; @@ -1071,21 +1091,21 @@ int main (int argc, char **argv) { log_error_write(srv, __FILE__, __LINE__, "d", r); break; } - + /* trigger waitpid */ srv->cur_ts = min_ts; - - /* cleanup stat-cache */ + + /* cleanup stat-cache */ stat_cache_trigger_cleanup(srv); /** - * check all connections for timeouts - * + * check all connections for timeouts + * */ for (ndx = 0; ndx < conns->used; ndx++) { int changed = 0; connection *con; int t_diff; - + con = conns->ptr[ndx]; if (con->state == CON_STATE_READ || @@ -1094,7 +1114,7 @@ int main (int argc, char **argv) { if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) { /* time - out */ #if 0 - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); @@ -1104,7 +1124,7 @@ int main (int argc, char **argv) { if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) { /* time - out */ #if 0 - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "connection closed - read-timeout:", con->fd); #endif connection_set_state(srv, con, CON_STATE_ERROR); @@ -1112,20 +1132,20 @@ int main (int argc, char **argv) { } } } - + if ((con->state == CON_STATE_WRITE) && - (con->write_request_ts != 0)) { + (con->write_request_ts != 0)) { #if 0 if (srv->cur_ts - con->write_request_ts > 60) { - log_error_write(srv, __FILE__, __LINE__, "sdd", + log_error_write(srv, __FILE__, __LINE__, "sdd", "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts); } #endif - + if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) { /* time - out */ #if 1 - log_error_write(srv, __FILE__, __LINE__, "sbsosds", + log_error_write(srv, __FILE__, __LINE__, "sbsosds", "NOTE: a request for", con->request.uri, "timed out after writing", @@ -1140,35 +1160,35 @@ int main (int argc, char **argv) { } /* we don't like div by zero */ if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1; - - if (con->traffic_limit_reached && - (con->conf.kbytes_per_second == 0 || + + if (con->traffic_limit_reached && + (con->conf.kbytes_per_second == 0 || ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) { /* enable connection again */ con->traffic_limit_reached = 0; - + changed = 1; } - + if (changed) { connection_state_machine(srv, con); } con->bytes_written_cur_second = 0; *(con->conf.global_bytes_per_second_cnt_ptr) = 0; - + #if 0 if (cs == 0) { fprintf(stderr, "connection-state: "); cs = 1; } - + fprintf(stderr, "c[%d,%d]: %s ", con->fd, con->fcgi.fd, connection_get_state(con->state)); #endif } - + if (cs == 1) fprintf(stderr, "\n"); } } @@ -1183,18 +1203,18 @@ int main (int argc, char **argv) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN); } - + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again"); - + srv->sockets_disabled = 0; } } else { if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */ (srv->conns->used > srv->max_conns) || /* out of connections */ - (graceful_shutdown)) { /* graceful_shutdown */ + (graceful_shutdown)) { /* graceful_shutdown */ /* disable server-fds */ - + for (i = 0; i < srv->srv_sockets.used; i++) { server_socket *srv_socket = srv->srv_sockets.ptr[i]; fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd); @@ -1213,7 +1233,7 @@ int main (int argc, char **argv) { /* network_close() will cleanup after us */ } } - + if (graceful_shutdown) { log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started"); } else if (srv->conns->used > srv->max_conns) { @@ -1221,7 +1241,7 @@ int main (int argc, char **argv) { } else { log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds"); } - + srv->sockets_disabled = 1; } } @@ -1231,16 +1251,16 @@ int main (int argc, char **argv) { * we are ready to terminate without harming anyone */ srv_shutdown = 1; } - + /* we still have some fds to share */ - if (srv->want_fds) { + if (srv->want_fds) { /* check the fdwaitqueue for waiting fds */ int free_fds = srv->max_fds - srv->cur_fds - 16; connection *con; - + for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) { connection_state_machine(srv, con); - + srv->want_fds--; } } @@ -1251,27 +1271,27 @@ int main (int argc, char **argv) { int fd_ndx; #if 0 if (n > 0) { - log_error_write(srv, __FILE__, __LINE__, "sd", + log_error_write(srv, __FILE__, __LINE__, "sd", "polls:", n); } -#endif +#endif fd_ndx = -1; do { fdevent_handler handler; void *context; handler_t r; - + fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx); revents = fdevent_event_get_revent (srv->ev, fd_ndx); fd = fdevent_event_get_fd (srv->ev, fd_ndx); handler = fdevent_get_handler(srv->ev, fd); context = fdevent_get_context(srv->ev, fd); - + /* connection_handle_fdevent needs a joblist_append */ #if 0 - log_error_write(srv, __FILE__, __LINE__, "sdd", + log_error_write(srv, __FILE__, __LINE__, "sdd", "event for", fd, revents); -#endif +#endif switch (r = (*handler)(srv, context, revents)) { case HANDLER_FINISHED: case HANDLER_GO_ON: @@ -1288,17 +1308,17 @@ int main (int argc, char **argv) { } } while (--n > 0); } else if (n < 0 && errno != EINTR) { - log_error_write(srv, __FILE__, __LINE__, "ss", - "fdevent_poll failed:", + log_error_write(srv, __FILE__, __LINE__, "ss", + "fdevent_poll failed:", strerror(errno)); } - + for (ndx = 0; ndx < srv->joblist->used; ndx++) { connection *con = srv->joblist->ptr[ndx]; handler_t r; - + connection_state_machine(srv, con); - + switch(r = plugins_call_handle_joblist(srv, con)) { case HANDLER_FINISHED: case HANDLER_GO_ON: @@ -1307,32 +1327,32 @@ int main (int argc, char **argv) { log_error_write(srv, __FILE__, __LINE__, "d", r); break; } - + con->in_joblist = 0; } - + srv->joblist->used = 0; } - + if (srv->srvconf.pid_file->used && srv->srvconf.changeroot->used == 0) { if (0 != unlink(srv->srvconf.pid_file->ptr)) { if (errno != EACCES && errno != EPERM) { - log_error_write(srv, __FILE__, __LINE__, "sbds", - "unlink failed for:", + log_error_write(srv, __FILE__, __LINE__, "sbds", + "unlink failed for:", srv->srvconf.pid_file, errno, strerror(errno)); } } } - + /* clean-up */ log_error_close(srv); network_close(srv); connections_free(srv); plugins_free(srv); server_free(srv); - + return 0; } diff --git a/src/settings.h b/src/settings.h index f0c6354..349fc20 100644 --- a/src/settings.h +++ b/src/settings.h @@ -9,24 +9,24 @@ /** * max size of a buffer which will just be reset * to ->used = 0 instead of really freeing the buffer - * + * * 64kB (no real reason, just a guess) */ #define BUFFER_MAX_REUSE_SIZE (4 * 1024) /** * max size of the HTTP request header - * + * * 32k should be enough for everything (just a guess) - * + * */ #define MAX_HTTP_REQUEST_HEADER (32 * 1024) -typedef enum { HANDLER_UNSET, - HANDLER_GO_ON, +typedef enum { HANDLER_UNSET, + HANDLER_GO_ON, HANDLER_FINISHED, - HANDLER_COMEBACK, - HANDLER_WAIT_FOR_EVENT, + HANDLER_COMEBACK, + HANDLER_WAIT_FOR_EVENT, HANDLER_ERROR, HANDLER_WAIT_FOR_FD } handler_t; diff --git a/src/spawn-fcgi.c b/src/spawn-fcgi.c index fd869a2..c40d8f9 100644 --- a/src/spawn-fcgi.c +++ b/src/spawn-fcgi.c @@ -45,28 +45,28 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const int fcgi_fd; int socket_type, status; struct timeval tv = { 0, 100 * 1000 }; - + struct sockaddr_un fcgi_addr_un; struct sockaddr_in fcgi_addr_in; struct sockaddr *fcgi_addr; - + socklen_t servlen; - + if (child_count < 2) { child_count = 5; } - + if (child_count > 256) { child_count = 256; } - - + + if (unixsocket) { memset(&fcgi_addr, 0, sizeof(fcgi_addr)); - + fcgi_addr_un.sun_family = AF_UNIX; strcpy(fcgi_addr_un.sun_path, unixsocket); - + #ifdef SUN_LEN servlen = SUN_LEN(&fcgi_addr_un); #else @@ -84,50 +84,50 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const } fcgi_addr_in.sin_port = htons(port); servlen = sizeof(fcgi_addr_in); - + socket_type = AF_INET; fcgi_addr = (struct sockaddr *) &fcgi_addr_in; } - + if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - fprintf(stderr, "%s.%d\n", + fprintf(stderr, "%s.%d\n", __FILE__, __LINE__); return -1; } - + if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { /* server is not up, spawn in */ pid_t child; int val; - + if (unixsocket) unlink(unixsocket); - + close(fcgi_fd); - + /* reopen socket */ if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - fprintf(stderr, "%s.%d\n", + fprintf(stderr, "%s.%d\n", __FILE__, __LINE__); return -1; } val = 1; if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { - fprintf(stderr, "%s.%d\n", + fprintf(stderr, "%s.%d\n", __FILE__, __LINE__); return -1; } /* create socket */ if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { - fprintf(stderr, "%s.%d: bind failed: %s\n", + fprintf(stderr, "%s.%d: bind failed: %s\n", __FILE__, __LINE__, strerror(errno)); return -1; } - + if (-1 == listen(fcgi_fd, 1024)) { - fprintf(stderr, "%s.%d: fd = -1\n", + fprintf(stderr, "%s.%d: fd = -1\n", __FILE__, __LINE__); return -1; } @@ -137,42 +137,42 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const } else { child = 0; } - + switch (child) { case 0: { char cgi_childs[64]; char *b; - + int i = 0; - + /* is save as we limit to 256 childs */ sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count); - + if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { close(FCGI_LISTENSOCK_FILENO); dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); close(fcgi_fd); } - + /* we don't need the client socket */ for (i = 3; i < 256; i++) { close(i); } - + /* create environment */ - + putenv(cgi_childs); - + /* fork and replace shell */ b = malloc(strlen("exec ") + strlen(appPath) + 1); strcpy(b, "exec "); strcat(b, appPath); - + /* exec the cgi */ execl("/bin/sh", "sh", "-c", b, NULL); - + exit(errno); - + break; } case -1: @@ -180,47 +180,47 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const break; default: /* father */ - + /* wait */ select(0, NULL, NULL, NULL, &tv); - + switch (waitpid(child, &status, WNOHANG)) { case 0: - fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", + fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n", __FILE__, __LINE__, child); - + /* write pid file */ if (pid_fd != -1) { /* assume a 32bit pid_t */ char pidbuf[12]; - + snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); - + write(pid_fd, pidbuf, strlen(pidbuf)); close(pid_fd); pid_fd = -1; } - + break; case -1: break; default: if (WIFEXITED(status)) { - fprintf(stderr, "%s.%d: child exited with: %d, %s\n", + fprintf(stderr, "%s.%d: child exited with: %d, %s\n", __FILE__, __LINE__, WEXITSTATUS(status), strerror(WEXITSTATUS(status))); } else if (WIFSIGNALED(status)) { - fprintf(stderr, "%s.%d: child signaled: %d\n", + fprintf(stderr, "%s.%d: child signaled: %d\n", __FILE__, __LINE__, WTERMSIG(status)); } else { - fprintf(stderr, "%s.%d: child died somehow: %d\n", + fprintf(stderr, "%s.%d: child died somehow: %d\n", __FILE__, __LINE__, status); } } - + break; } } else { @@ -228,16 +228,16 @@ int fcgi_spawn_connection(char *appPath, char *addr, unsigned short port, const __FILE__, __LINE__); return -1; } - + close(fcgi_fd); - + return 0; } void show_version () { char *b = "spawn-fcgi" "-" PACKAGE_VERSION \ -" - spawns fastcgi processes\n" +" - spawns fastcgi processes\n" ; write(1, b, strlen(b)); } @@ -265,7 +265,7 @@ void show_help () { int main(int argc, char **argv) { - char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, + char *fcgi_app = NULL, *changeroot = NULL, *username = NULL, *groupname = NULL, *unixsocket = NULL, *pid_file = NULL, *addr = NULL; unsigned short port = 0; @@ -273,9 +273,9 @@ int main(int argc, char **argv) { int i_am_root, o; int pid_fd = -1; int nofork = 0; - + i_am_root = (getuid() == 0); - + while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) { switch(o) { case 'f': fcgi_app = optarg; break; @@ -290,145 +290,149 @@ int main(int argc, char **argv) { case 'P': pid_file = optarg; /* PID file */ break; case 'v': show_version(); return 0; case 'h': show_help(); return 0; - default: + default: show_help(); return -1; } } - + if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) { show_help(); return -1; } - + if (unixsocket && port) { - fprintf(stderr, "%s.%d: %s\n", + fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, "either a unix domain socket or a tcp-port, but not both\n"); - + return -1; } - + if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) { - fprintf(stderr, "%s.%d: %s\n", + fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, "path of the unix socket is too long\n"); - + return -1; } /* UID handling */ if (!i_am_root && (geteuid() == 0 || getegid() == 0)) { /* we are setuid-root */ - - fprintf(stderr, "%s.%d: %s\n", + + fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, "Are you nuts ? Don't apply a SUID bit to this binary\n"); - + return -1; } - - if (pid_file && + + if (pid_file && (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) { struct stat st; if (errno != EEXIST) { - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", __FILE__, __LINE__, pid_file, strerror(errno)); - + return -1; } - + /* ok, file exists */ - + if (0 != stat(pid_file, &st)) { - fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n", + fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n", __FILE__, __LINE__, pid_file, strerror(errno)); - + return -1; } - + /* is it a regular file ? */ - + if (!S_ISREG(st.st_mode)) { - fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n", + fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n", __FILE__, __LINE__, pid_file); - + return -1; } - + if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) { - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n", __FILE__, __LINE__, pid_file, strerror(errno)); - + return -1; } } - + if (i_am_root) { struct group *grp = NULL; struct passwd *pwd = NULL; - + /* set user and group */ - + if (username) { if (NULL == (pwd = getpwnam(username))) { - fprintf(stderr, "%s.%d: %s, %s\n", + fprintf(stderr, "%s.%d: %s, %s\n", __FILE__, __LINE__, "can't find username", username); return -1; } - + if (pwd->pw_uid == 0) { - fprintf(stderr, "%s.%d: %s\n", + fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, "I will not set uid to 0\n"); return -1; } } - + if (groupname) { if (NULL == (grp = getgrnam(groupname))) { - fprintf(stderr, "%s.%d: %s %s\n", + fprintf(stderr, "%s.%d: %s %s\n", __FILE__, __LINE__, - "can't find groupname", + "can't find groupname", groupname); return -1; } if (grp->gr_gid == 0) { - fprintf(stderr, "%s.%d: %s\n", + fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, "I will not set gid to 0\n"); return -1; } } - + if (changeroot) { if (-1 == chroot(changeroot)) { - fprintf(stderr, "%s.%d: %s %s\n", + fprintf(stderr, "%s.%d: %s %s\n", __FILE__, __LINE__, "chroot failed: ", strerror(errno)); return -1; } if (-1 == chdir("/")) { - fprintf(stderr, "%s.%d: %s %s\n", + fprintf(stderr, "%s.%d: %s %s\n", __FILE__, __LINE__, "chdir failed: ", strerror(errno)); return -1; } } - + /* drop root privs */ if (groupname) { setgid(grp->gr_gid); - setgroups(0, NULL); } - if (username) setuid(pwd->pw_uid); + if (username) { + if (groupname) { + initgroups(username, grp->gr_gid); + } + setuid(pwd->pw_uid); + } } - + return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork); } #else diff --git a/src/splaytree.c b/src/splaytree.c index 3a80910..5d6a2b4 100644 --- a/src/splaytree.c +++ b/src/splaytree.c @@ -56,19 +56,19 @@ #define node_size splaytree_size -/* Splay using the key i (which may or may not be in the tree.) - * The starting root is t, and the tree used is defined by rat +/* Splay using the key i (which may or may not be in the tree.) + * The starting root is t, and the tree used is defined by rat * size fields are maintained */ splay_tree * splaytree_splay (splay_tree *t, int i) { splay_tree N, *l, *r, *y; int comp, root_size, l_size, r_size; - + if (t == NULL) return t; N.left = N.right = NULL; l = r = &N; root_size = node_size(t); l_size = r_size = 0; - + for (;;) { comp = compare(i, t->key); if (comp < 0) { @@ -120,7 +120,7 @@ splay_tree * splaytree_splay (splay_tree *t, int i) { y->size = r_size; r_size -= 1+node_size(y->right); } - + l->right = t->left; /* assemble */ r->left = t->right; t->left = N.right; diff --git a/src/splaytree.h b/src/splaytree.h index 98e4234..4be1523 100644 --- a/src/splaytree.h +++ b/src/splaytree.h @@ -19,6 +19,6 @@ splay_tree * splaytree_size(splay_tree *t); /* This macro returns the size of a node. Unlike "x->size", */ /* it works even if x=NULL. The test could be avoided by using */ /* a special version of NULL which was a real node with size 0. */ - + #endif diff --git a/src/stat_cache.c b/src/stat_cache.c index a4f31a4..283ead9 100644 --- a/src/stat_cache.c +++ b/src/stat_cache.c @@ -52,8 +52,8 @@ * * if we get a change-event from FAM, we increment the version in the FAM->dir mapping * - * if the stat()-cache is queried we check if the version id for the directory is the - * same and return immediatly. + * if the stat()-cache is queried we check if the version id for the directory is the + * same and return immediatly. * * * What we need: @@ -62,17 +62,17 @@ * - for each FAMRequest we have to find the version in the directory cache (index as userdata) * * stat <<-> directory <-> FAMRequest - * - * if file is deleted, directory is dirty, file is rechecked ... + * + * if file is deleted, directory is dirty, file is rechecked ... * if directory is deleted, directory mapping is removed - * + * * */ #ifdef HAVE_FAM_H typedef struct { FAMRequest *req; FAMConnection *fc; - + buffer *name; int version; @@ -83,16 +83,16 @@ typedef struct { * - we need a hash * - the hash-key is used as sorting criteria for a tree * - a splay-tree is used as we can use the caching effect of it - */ + */ /* we want to cleanup the stat-cache every few seconds, let's say 10 * * - remove entries which are outdated since 30s * - remove entries which are fresh but havn't been used since 60s * - if we don't have a stat-cache entry for a directory, release it from the monitor - */ + */ -#ifdef DEBUG_STAT_CACHE +#ifdef DEBUG_STAT_CACHE typedef struct { int *ptr; @@ -105,16 +105,16 @@ static fake_keys ctrl; stat_cache *stat_cache_init(void) { stat_cache *fc = NULL; - + fc = calloc(1, sizeof(*fc)); - + fc->dir_name = buffer_init(); fc->hash_key = buffer_init(); #ifdef HAVE_FAM_H fc->fam = calloc(1, sizeof(*fc->fam)); #endif -#ifdef DEBUG_STAT_CACHE +#ifdef DEBUG_STAT_CACHE ctrl.size = 0; #endif @@ -123,24 +123,24 @@ stat_cache *stat_cache_init(void) { static stat_cache_entry * stat_cache_entry_init(void) { stat_cache_entry *sce = NULL; - + sce = calloc(1, sizeof(*sce)); - + sce->name = buffer_init(); sce->etag = buffer_init(); sce->content_type = buffer_init(); - + return sce; } static void stat_cache_entry_free(void *data) { stat_cache_entry *sce = data; if (!sce) return; - + buffer_free(sce->etag); buffer_free(sce->name); buffer_free(sce->content_type); - + free(sce); } @@ -149,22 +149,22 @@ static fam_dir_entry * fam_dir_entry_init(void) { fam_dir_entry *fam_dir = NULL; fam_dir = calloc(1, sizeof(*fam_dir)); - + fam_dir->name = buffer_init(); - + return fam_dir; } static void fam_dir_entry_free(void *data) { fam_dir_entry *fam_dir = data; - + if (!fam_dir) return; - + FAMCancelMonitor(fam_dir->fc, fam_dir->req); - + buffer_free(fam_dir->name); free(fam_dir->req); - + free(fam_dir); } #endif @@ -175,7 +175,7 @@ void stat_cache_free(stat_cache *sc) { splay_tree *node = sc->files; osize = sc->files->size; - + stat_cache_entry_free(node->data); sc->files = splaytree_delete(sc->files, node->key); @@ -189,12 +189,12 @@ void stat_cache_free(stat_cache *sc) { while (sc->dirs) { int osize; splay_tree *node = sc->dirs; - + osize = sc->dirs->size; fam_dir_entry_free(node->data); sc->dirs = splaytree_delete(sc->dirs, node->key); - + if (osize == 1) { assert(NULL == sc->dirs); } else { @@ -214,7 +214,7 @@ void stat_cache_free(stat_cache *sc) { static int stat_cache_attr_get(buffer *buf, char *name) { int attrlen; int ret; - + attrlen = 1024; buffer_prepare_copy(buf, attrlen); attrlen--; @@ -253,15 +253,15 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) { sc->fam) { events = FAMPending(sc->fam); - + for (i = 0; i < events; i++) { FAMEvent fe; fam_dir_entry *fam_dir; splay_tree *node; int ndx, j; - + FAMNextEvent(sc->fam, &fe); - + /* handle event */ switch(fe.code) { @@ -286,13 +286,13 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) { sc->dirs = splaytree_splay(sc->dirs, ndx); node = sc->dirs; - + if (node && (node->key == ndx)) { int osize = splaytree_size(sc->dirs); - + fam_dir_entry_free(node->data); sc->dirs = splaytree_delete(sc->dirs, ndx); - + assert(osize - 1 == splaytree_size(sc->dirs)); } } @@ -315,7 +315,7 @@ handler_t stat_cache_handle_fdevent(void *_srv, void *_fce, int revent) { sc->fam = NULL; } - + return HANDLER_GO_ON; } @@ -353,7 +353,7 @@ static int stat_cache_lstat(server *srv, buffer *dname, struct stat *lst) { * * * - * returns: + * returns: * - HANDLER_FINISHED on cache-miss (don't forget to reopen the file) * - HANDLER_ERROR on stat() failed -> see errno for problem */ @@ -370,16 +370,16 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ size_t k; int fd; struct stat lst; -#ifdef DEBUG_STAT_CACHE +#ifdef DEBUG_STAT_CACHE size_t i; #endif int file_ndx; splay_tree *file_node = NULL; - *ret_sce = NULL; + *ret_sce = NULL; - /* + /* * check if the directory for this file has changed */ @@ -391,23 +391,23 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ file_ndx = hashme(sc->hash_key); sc->files = splaytree_splay(sc->files, file_ndx); -#ifdef DEBUG_STAT_CACHE +#ifdef DEBUG_STAT_CACHE for (i = 0; i < ctrl.used; i++) { if (ctrl.ptr[i] == file_ndx) break; } #endif if (sc->files && (sc->files->key == file_ndx)) { -#ifdef DEBUG_STAT_CACHE +#ifdef DEBUG_STAT_CACHE /* it was in the cache */ assert(i < ctrl.used); #endif - - /* we have seen this file already and + + /* we have seen this file already and * don't stat() it again in the same second */ file_node = sc->files; - + sce = file_node->data; /* check if the name is the same, we might have a collision */ @@ -415,7 +415,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ if (buffer_is_equal(name, sce->name)) { if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) { if (sce->stat_ts == srv->cur_ts) { - *ret_sce = sce; + *ret_sce = sce; return HANDLER_GO_ON; } } @@ -425,15 +425,15 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ * file_node is used by the FAM check below to see if we know this file * and if we can save a stat(). * - * BUT, the sce is not reset here as the entry into the cache is ok, we + * BUT, the sce is not reset here as the entry into the cache is ok, we * it is just not pointing to our requested file. - * + * * */ file_node = NULL; } } else { -#ifdef DEBUG_STAT_CACHE +#ifdef DEBUG_STAT_CACHE if (i != ctrl.used) { fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr); } @@ -447,28 +447,28 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ if (0 != buffer_copy_dirname(sc->dir_name, name)) { SEGFAULT(); } - + buffer_copy_string_buffer(sc->hash_key, sc->dir_name); buffer_append_long(sc->hash_key, con->conf.follow_symlink); dir_ndx = hashme(sc->hash_key); - + sc->dirs = splaytree_splay(sc->dirs, dir_ndx); - + if (sc->dirs && (sc->dirs->key == dir_ndx)) { dir_node = sc->dirs; } - + if (dir_node && file_node) { /* we found a file */ - + sce = file_node->data; fam_dir = dir_node->data; - + if (fam_dir->version == sce->dir_version) { /* the stat()-cache entry is still ok */ - - *ret_sce = sce; + + *ret_sce = sce; return HANDLER_GO_ON; } } @@ -476,7 +476,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ #endif /* - * *lol* + * *lol* * - open() + fstat() on a named-pipe results in a (intended) hang. * - stat() if regular file + open() to see if we can read from it is better * @@ -496,16 +496,16 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ if (NULL == sce) { int osize = 0; - + if (sc->files) { osize = sc->files->size; } sce = stat_cache_entry_init(); buffer_copy_string_buffer(sce->name, name); - - sc->files = splaytree_insert(sc->files, file_ndx, sce); -#ifdef DEBUG_STAT_CACHE + + sc->files = splaytree_insert(sc->files, file_ndx, sce); +#ifdef DEBUG_STAT_CACHE if (ctrl.size == 0) { ctrl.size = 16; ctrl.used = 0; @@ -526,22 +526,22 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ sce->st = st; sce->stat_ts = srv->cur_ts; - /* catch the obvious symlinks + /* catch the obvious symlinks * * this is not a secure check as we still have a race-condition between - * the stat() and the open. We can only solve this by + * the stat() and the open. We can only solve this by * 1. open() the file * 2. fstat() the fd * * and keeping the file open for the rest of the time. But this can * only be done at network level. - * + * * per default it is not a symlink * */ #ifdef HAVE_LSTAT sce->is_symlink = 0; - /* we want to only check for symlinks if we should block symlinks. + /* we want to only check for symlinks if we should block symlinks. */ if (!con->conf.follow_symlink) { if (stat_cache_lstat(srv, name, &lst) == 0) { @@ -590,14 +590,14 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ }; #endif - if (S_ISREG(st.st_mode)) { + if (S_ISREG(st.st_mode)) { /* determine mimetype */ buffer_reset(sce->content_type); - + for (k = 0; k < con->conf.mimetypes->used; k++) { data_string *ds = (data_string *)con->conf.mimetypes->data[k]; buffer *type = ds->key; - + if (type->used == 0) continue; /* check if the right side is the same */ @@ -617,7 +617,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ } else if (S_ISDIR(st.st_mode)) { etag_create(sce->etag, &(sce->st)); } - + #ifdef HAVE_FAM_H if (sc->fam && (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) { @@ -627,19 +627,19 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ fam_dir->fc = sc->fam; buffer_copy_string_buffer(fam_dir->name, sc->dir_name); - + fam_dir->version = 1; - + fam_dir->req = calloc(1, sizeof(FAMRequest)); - - if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, + + if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, fam_dir->req, fam_dir)) { - - log_error_write(srv, __FILE__, __LINE__, "sbs", - "monitoring dir failed:", - fam_dir->name, + + log_error_write(srv, __FILE__, __LINE__, "sbs", + "monitoring dir failed:", + fam_dir->name, FamErrlist[FAMErrno]); - + fam_dir_entry_free(fam_dir); } else { int osize = 0; @@ -648,7 +648,7 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ osize = sc->dirs->size; } - sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); + sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); assert(sc->dirs); assert(sc->dirs->data == fam_dir); assert(osize == (sc->dirs->size - 1)); @@ -656,9 +656,9 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ } else { fam_dir = dir_node->data; } - + /* bind the fam_fc to the stat() cache entry */ - + if (fam_dir) { sce->dir_version = fam_dir->version; sce->dir_ndx = dir_ndx; @@ -672,11 +672,11 @@ handler_t stat_cache_get_entry(server *srv, connection *con, buffer *name, stat_ } /** - * remove stat() from cache which havn't been stat()ed for + * remove stat() from cache which havn't been stat()ed for * more than 10 seconds - * * - * walk though the stat-cache, collect the ids which are too old + * + * walk though the stat-cache, collect the ids which are too old * and remove them in a second loop */ @@ -717,9 +717,9 @@ int stat_cache_trigger_cleanup(server *srv) { sc->files = splaytree_splay(sc->files, ndx); node = sc->files; - + if (node && (node->key == ndx)) { -#ifdef DEBUG_STAT_CACHE +#ifdef DEBUG_STAT_CACHE size_t j; int osize = splaytree_size(sc->files); stat_cache_entry *sce = node->data; @@ -727,7 +727,7 @@ int stat_cache_trigger_cleanup(server *srv) { stat_cache_entry_free(node->data); sc->files = splaytree_delete(sc->files, ndx); -#ifdef DEBUG_STAT_CACHE +#ifdef DEBUG_STAT_CACHE for (j = 0; j < ctrl.used; j++) { if (ctrl.ptr[j] == ndx) { ctrl.ptr[j] = ctrl.ptr[--ctrl.used]; diff --git a/src/status_counter.c b/src/status_counter.c index 3b345cd..eaf9251 100644 --- a/src/status_counter.c +++ b/src/status_counter.c @@ -32,7 +32,7 @@ data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) return di; } -/* dummies of the statistic framework functions +/* 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); diff --git a/src/status_counter.h b/src/status_counter.h index 431bd9c..210fe85 100644 --- a/src/status_counter.h +++ b/src/status_counter.h @@ -11,4 +11,4 @@ int status_counter_inc(server *srv, const char *s, size_t len); int status_counter_dec(server *srv, const char *s, size_t len); int status_counter_set(server *srv, const char *s, size_t len, int val); -#endif +#endif diff --git a/src/stream.c b/src/stream.c index ecaadc1..aac6cf7 100644 --- a/src/stream.c +++ b/src/stream.c @@ -1,7 +1,7 @@ #include <sys/types.h> #include <sys/stat.h> -#include <unistd.h> +#include <unistd.h> #include <fcntl.h> #include "stream.h" @@ -25,33 +25,33 @@ int stream_open(stream *f, buffer *fn) { #endif f->start = NULL; - + if (-1 == stat(fn->ptr, &st)) { return -1; } - + f->size = st.st_size; #ifdef HAVE_MMAP if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) { return -1; } - + f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0); - + close(fd); - + if (MAP_FAILED == f->start) { return -1; } #elif defined __WIN32 - fh = CreateFile(fn->ptr, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_READONLY, + fh = CreateFile(fn->ptr, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_READONLY, NULL); if (!fh) return -1; @@ -66,7 +66,7 @@ int stream_open(stream *f, buffer *fn) { if (!mh) { LPVOID lpMsgBuf; FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), @@ -76,7 +76,7 @@ int stream_open(stream *f, buffer *fn) { return -1; } - + p = MapViewOfFile(mh, FILE_MAP_READ, 0, @@ -87,9 +87,9 @@ int stream_open(stream *f, buffer *fn) { f->start = p; #else -# error no mmap found +# error no mmap found #endif - + return 0; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 584d9c9..c83026a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -48,7 +48,7 @@ CONFS=fastcgi-10.conf \ cachable.t -TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) +TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir) EXTRA_DIST=wrapper.sh lighttpd.conf \ lighttpd.user \ @@ -62,7 +62,7 @@ leak-check: for i in $(TESTS); do \ $(srcdir)/$$i; \ echo $$?; \ - done + done clean-local: rm -f *.out diff --git a/tests/Makefile.in b/tests/Makefile.in index 93ac0f6..4ba1431 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -134,7 +134,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -167,6 +166,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ @@ -262,7 +262,7 @@ CONFS = fastcgi-10.conf \ lowercase.conf \ cachable.t -TESTS_ENVIRONMENT = $(srcdir)/wrapper.sh $(srcdir) $(top_builddir) +TESTS_ENVIRONMENT = $(srcdir)/wrapper.sh $(srcdir) $(top_builddir) EXTRA_DIST = wrapper.sh lighttpd.conf \ lighttpd.user \ lighttpd.htpasswd \ @@ -707,7 +707,7 @@ leak-check: for i in $(TESTS); do \ $(srcdir)/$$i; \ echo $$?; \ - done + done clean-local: rm -f *.out diff --git a/tests/bug-06.conf b/tests/bug-06.conf index b094e88..3cc7525 100644 --- a/tests/bug-06.conf +++ b/tests/bug-06.conf @@ -13,7 +13,7 @@ server.name = "www.example.org" server.tag = "Apache 1.3.29" -## +## ## Format: <errorfile-prefix><status>.html ## -> ..../status-404.html for 'File not found' #server.errorfile-prefix = "/home/weigon/projects/lighttpd/doc/status-" @@ -24,24 +24,24 @@ server.dir-listing = "enable" #server.event-handler = "linux-rtsig" #server.modules.path = "" -server.modules = ( +server.modules = ( "mod_rewrite", "mod_setenv", - "mod_access", + "mod_access", "mod_auth", # "mod_httptls", - "mod_status", + "mod_status", "mod_expire", "mod_simple_vhost", - "mod_redirect", + "mod_redirect", # "mod_evhost", # "mod_localizer", "mod_fastcgi", "mod_cgi", "mod_compress", - "mod_accesslog" ) + "mod_accesslog" ) -server.indexfiles = ( "index.html", +server.indexfiles = ( "index.html", "index.htm", "default.htm", "index.php" ) #,-- only root can use these options @@ -53,7 +53,7 @@ server.indexfiles = ( "index.html", #|# change uid to <uid> (default: don't care) #| server.groupid wwwrun #| -#`-- +#`-- ######################## MODULE CONFIG ############################ @@ -61,7 +61,7 @@ server.indexfiles = ( "index.html", accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log" -mimetype.assign = ( ".png" => "image/png", +mimetype.assign = ( ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", @@ -85,8 +85,8 @@ setenv.add-request-header = ( "FOO" => "foo") setenv.add-response-header = ( "BAR" => "foo") fastcgi.debug = 0 -fastcgi.server = ( ".php" => ( - "grisu" => ( +fastcgi.server = ( ".php" => ( + "grisu" => ( "host" => "127.0.0.1", "port" => 1026, # "mode" => "authorizer", @@ -94,12 +94,12 @@ fastcgi.server = ( ".php" => ( ) ) ) - + cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".py" => "/usr/bin/python" ) - + ssl.engine = "disable" @@ -113,22 +113,22 @@ auth.backend.ldap.hostname = "localhost" auth.backend.ldap.base-dn = "dc=my-domain,dc=com" auth.backend.ldap.filter = "(uid=$)" -auth.require = ( "/server-status" => - ( +auth.require = ( "/server-status" => + ( "method" => "digest", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "host=192.168.2.10") "require" => "group=www|user=jan|host=192.168.2.10" ), - "/auth.php" => - ( + "/auth.php" => + ( "method" => "basic", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "host=192.168.2.10") "require" => "user=jan" ), - "/server-config" => - ( + "/server-config" => + ( "method" => "basic", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "user=weigon", "host=192.168.2.10") diff --git a/tests/bug-12.conf b/tests/bug-12.conf index 49aa16b..cd72bf8 100644 --- a/tests/bug-12.conf +++ b/tests/bug-12.conf @@ -13,7 +13,7 @@ server.name = "www.example.org" server.tag = "Apache 1.3.29" -## +## ## Format: <errorfile-prefix><status>.html ## -> ..../status-404.html for 'File not found' #server.errorfile-prefix = "/home/weigon/projects/lighttpd/doc/status-" @@ -24,24 +24,24 @@ server.dir-listing = "enable" #server.event-handler = "linux-rtsig" #server.modules.path = "" -server.modules = ( +server.modules = ( "mod_rewrite", "mod_setenv", - "mod_access", + "mod_access", "mod_auth", # "mod_httptls", - "mod_status", + "mod_status", "mod_expire", "mod_simple_vhost", - "mod_redirect", + "mod_redirect", # "mod_evhost", # "mod_localizer", "mod_fastcgi", "mod_cgi", "mod_compress", - "mod_accesslog" ) + "mod_accesslog" ) -server.indexfiles = ( "index.html", +server.indexfiles = ( "index.html", "index.htm", "default.htm", "index.php" ) server.error-handler-404 = "/indexfile/return-404.php" @@ -55,7 +55,7 @@ server.error-handler-404 = "/indexfile/return-404.php" #|# change uid to <uid> (default: don't care) #| server.groupid wwwrun #| -#`-- +#`-- ######################## MODULE CONFIG ############################ @@ -63,7 +63,7 @@ server.error-handler-404 = "/indexfile/return-404.php" accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log" -mimetype.assign = ( ".png" => "image/png", +mimetype.assign = ( ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", @@ -87,8 +87,8 @@ setenv.add-request-header = ( "FOO" => "foo") setenv.add-response-header = ( "BAR" => "foo") fastcgi.debug = 0 -fastcgi.server = ( ".php" => ( - "grisu" => ( +fastcgi.server = ( ".php" => ( + "grisu" => ( "host" => "127.0.0.1", "port" => 1026, # "mode" => "authorizer", @@ -96,12 +96,12 @@ fastcgi.server = ( ".php" => ( ) ) ) - + cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".py" => "/usr/bin/python" ) - + ssl.engine = "disable" @@ -115,22 +115,22 @@ auth.backend.ldap.hostname = "localhost" auth.backend.ldap.base-dn = "dc=my-domain,dc=com" auth.backend.ldap.filter = "(uid=$)" -auth.require = ( "/server-status" => - ( +auth.require = ( "/server-status" => + ( "method" => "digest", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "host=192.168.2.10") "require" => "group=www|user=jan|host=192.168.2.10" ), - "/auth.php" => - ( + "/auth.php" => + ( "method" => "basic", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "host=192.168.2.10") "require" => "user=jan" ), - "/server-config" => - ( + "/server-config" => + ( "method" => "basic", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "user=weigon", "host=192.168.2.10") diff --git a/tests/cachable.t b/tests/cachable.t index 74d9a4b..9dc1121 100755 --- a/tests/cachable.t +++ b/tests/cachable.t @@ -15,7 +15,7 @@ my $tf = LightyTest->new(); my $t; $tf->{CONFIGFILE} = 'lighttpd.conf'; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); ## check if If-Modified-Since, If-None-Match works diff --git a/tests/condition.conf b/tests/condition.conf index 92c05ad..63b8fad 100644 --- a/tests/condition.conf +++ b/tests/condition.conf @@ -15,9 +15,9 @@ server.name = "www.example.org" server.tag = "Apache 1.3.29" -server.modules = ( +server.modules = ( "mod_redirect", - "mod_accesslog" ) + "mod_accesslog" ) ######################## MODULE CONFIG ############################ diff --git a/tests/core-request.t b/tests/core-request.t index f4db937..27edafa 100755 --- a/tests/core-request.t +++ b/tests/core-request.t @@ -223,7 +223,7 @@ ok($tf->handle_http($t) == 0, 'Content-Length > max-request-size'); $t->{REQUEST} = ( <<EOF POST /12345.txt HTTP/1.0 Host: 123.example.org -Content-Length: +Content-Length: EOF ); $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 411 } ]; diff --git a/tests/core-response.t b/tests/core-response.t index a8fbd00..c7a158c 100755 --- a/tests/core-response.t +++ b/tests/core-response.t @@ -14,7 +14,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); ## Low-Level Response-Header Parsing - HTTP/1.1 diff --git a/tests/core-var-include.t b/tests/core-var-include.t index a6ccbd3..b26790f 100755 --- a/tests/core-var-include.t +++ b/tests/core-var-include.t @@ -37,13 +37,13 @@ my $tests = { "var.myvar" => "/good_var_myvar" . $myvar, "myvar" => "/good_myvar" . $myvar, "env" => "/" . $ENV{"env_test"}, - + "number1" => "/good_number" . "1", "number2" => "1" . "/good_number", "array_append" => "/good_array_append", "string_append" => "/good_" . $mystr, "number_append" => "/good_" . "2", - + "include_shell" => "/good_include_shell_" . "456" }; diff --git a/tests/core.t b/tests/core.t index d8187dd..6de933c 100755 --- a/tests/core.t +++ b/tests/core.t @@ -123,7 +123,7 @@ ok($tf->handle_http($t) == 0, 'no whitespace'); $t->{REQUEST} = ( <<EOF GET / HTTP/1.0 -ABC:foo +ABC:foo bc EOF ); diff --git a/tests/docroot/123/Makefile.am b/tests/docroot/123/Makefile.am index 64712d7..e998042 100644 --- a/tests/docroot/123/Makefile.am +++ b/tests/docroot/123/Makefile.am @@ -1 +1 @@ -EXTRA_DIST=12345.html 12345.txt dummyfile.bla phpinfo.php +EXTRA_DIST=12345.html 12345.txt dummyfile.bla phpinfo.php diff --git a/tests/docroot/123/Makefile.in b/tests/docroot/123/Makefile.in index b777dd1..c187355 100644 --- a/tests/docroot/123/Makefile.in +++ b/tests/docroot/123/Makefile.in @@ -100,7 +100,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -133,6 +132,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ @@ -185,7 +185,7 @@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ -EXTRA_DIST = 12345.html 12345.txt dummyfile.bla phpinfo.php +EXTRA_DIST = 12345.html 12345.txt dummyfile.bla phpinfo.php all: all-am .SUFFIXES: diff --git a/tests/docroot/Makefile.in b/tests/docroot/Makefile.in index de9347d..91435f3 100644 --- a/tests/docroot/Makefile.in +++ b/tests/docroot/Makefile.in @@ -109,7 +109,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -142,6 +141,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ diff --git a/tests/docroot/www/Makefile.in b/tests/docroot/www/Makefile.in index 4936786..89399a0 100644 --- a/tests/docroot/www/Makefile.in +++ b/tests/docroot/www/Makefile.in @@ -109,7 +109,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -142,6 +141,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ diff --git a/tests/docroot/www/cgi-pathinfo.pl b/tests/docroot/www/cgi-pathinfo.pl index af8d4df..7bebb0c 100644 --- a/tests/docroot/www/cgi-pathinfo.pl +++ b/tests/docroot/www/cgi-pathinfo.pl @@ -1,4 +1,4 @@ -#! /usr/bin/perl +#! /usr/bin/perl print "Content-Type: text/html\r\n\r\n"; diff --git a/tests/docroot/www/cgi.php b/tests/docroot/www/cgi.php index d92e52f..f59a840 100755 --- a/tests/docroot/www/cgi.php +++ b/tests/docroot/www/cgi.php @@ -1,4 +1,4 @@ -<?php +<?php #ob_start(/*"ob_gzhandler"*/); print "12345<br />\n"; diff --git a/tests/docroot/www/cgi.pl b/tests/docroot/www/cgi.pl index 9695adf..88ae6d3 100644 --- a/tests/docroot/www/cgi.pl +++ b/tests/docroot/www/cgi.pl @@ -1,4 +1,4 @@ -#! /usr/bin/perl +#! /usr/bin/perl print "Content-Type: text/html\r\n\r\n"; diff --git a/tests/docroot/www/expire/Makefile.in b/tests/docroot/www/expire/Makefile.in index 651ca63..38c6b66 100644 --- a/tests/docroot/www/expire/Makefile.in +++ b/tests/docroot/www/expire/Makefile.in @@ -100,7 +100,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -133,6 +132,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ diff --git a/tests/docroot/www/get-env.php b/tests/docroot/www/get-env.php index 15ac94f..8af72a6 100644 --- a/tests/docroot/www/get-env.php +++ b/tests/docroot/www/get-env.php @@ -1,3 +1,3 @@ -<?php +<?php print $_ENV[$_GET["env"]]; ?> diff --git a/tests/docroot/www/get-server-env.php b/tests/docroot/www/get-server-env.php index 17b4994..64d9312 100644 --- a/tests/docroot/www/get-server-env.php +++ b/tests/docroot/www/get-server-env.php @@ -1,3 +1,3 @@ -<?php +<?php print $_SERVER[$_GET["env"]]; ?> diff --git a/tests/docroot/www/go/Makefile.in b/tests/docroot/www/go/Makefile.in index 29dc6e3..b5c5d62 100644 --- a/tests/docroot/www/go/Makefile.in +++ b/tests/docroot/www/go/Makefile.in @@ -100,7 +100,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -133,6 +132,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ diff --git a/tests/docroot/www/go/cgi.php b/tests/docroot/www/go/cgi.php index d92e52f..f59a840 100755 --- a/tests/docroot/www/go/cgi.php +++ b/tests/docroot/www/go/cgi.php @@ -1,4 +1,4 @@ -<?php +<?php #ob_start(/*"ob_gzhandler"*/); print "12345<br />\n"; diff --git a/tests/docroot/www/indexfile/Makefile.in b/tests/docroot/www/indexfile/Makefile.in index 86181fa..5285d2d 100644 --- a/tests/docroot/www/indexfile/Makefile.in +++ b/tests/docroot/www/indexfile/Makefile.in @@ -100,7 +100,6 @@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ -LUACONFIG = @LUACONFIG@ LUA_CFLAGS = @LUA_CFLAGS@ LUA_LIBS = @LUA_LIBS@ MAINT = @MAINT@ @@ -133,6 +132,7 @@ SQLITE_LIBS = @SQLITE_LIBS@ SSL_LIB = @SSL_LIB@ STRIP = @STRIP@ U = @U@ +UUID_LIBS = @UUID_LIBS@ VERSION = @VERSION@ XML_CFLAGS = @XML_CFLAGS@ XML_LIBS = @XML_LIBS@ diff --git a/tests/docroot/www/indexfile/return-404.php b/tests/docroot/www/indexfile/return-404.php index dd680cc..2adaaea 100644 --- a/tests/docroot/www/indexfile/return-404.php +++ b/tests/docroot/www/indexfile/return-404.php @@ -1,5 +1,5 @@ -<?php - header("Status: 404"); - +<?php + header("Status: 404"); + print $_SERVER["PHP_SELF"]; ?> diff --git a/tests/docroot/www/nph-status.pl b/tests/docroot/www/nph-status.pl index 602cdc7..528791b 100755 --- a/tests/docroot/www/nph-status.pl +++ b/tests/docroot/www/nph-status.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/perl print "HTTP/1.0 30 FooBar\r\n"; print "\r\n"; diff --git a/tests/fastcgi-auth.conf b/tests/fastcgi-auth.conf index a375e93..00b0060 100644 --- a/tests/fastcgi-auth.conf +++ b/tests/fastcgi-auth.conf @@ -16,7 +16,7 @@ server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log server.name = "www.example.org" server.tag = "Apache 1.3.29" -## +## ## Format: <errorfile-prefix><status>.html ## -> ..../status-404.html for 'File not found' #server.errorfile-prefix = "/home/weigon/projects/lighttpd/doc/status-" @@ -27,23 +27,23 @@ server.dir-listing = "enable" #server.event-handler = "linux-rtsig" #server.modules.path = "" -server.modules = ( - "mod_rewrite", - "mod_access", +server.modules = ( + "mod_rewrite", + "mod_access", "mod_auth", # "mod_httptls", - "mod_status", + "mod_status", "mod_expire", # "mod_simple_vhost", - "mod_redirect", + "mod_redirect", # "mod_evhost", # "mod_localizer", "mod_fastcgi", "mod_cgi", "mod_compress", - "mod_accesslog" ) + "mod_accesslog" ) -server.indexfiles = ( "index.php", "index.html", +server.indexfiles = ( "index.php", "index.html", "index.htm", "default.htm" ) #,-- only root can use these options @@ -55,7 +55,7 @@ server.indexfiles = ( "index.php", "index.html", #|# change uid to <uid> (default: don't care) #| server.groupid wwwrun #| -#`-- +#`-- ######################## MODULE CONFIG ############################ @@ -63,7 +63,7 @@ server.indexfiles = ( "index.php", "index.html", accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log" -mimetype.assign = ( ".png" => "image/png", +mimetype.assign = ( ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", @@ -83,23 +83,23 @@ compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/" compress.filetype = ("text/plain", "text/html") fastcgi.debug = 0 -fastcgi.server = ( "/" => ( - "grisu" => ( +fastcgi.server = ( "/" => ( + "grisu" => ( "host" => "127.0.0.1", "port" => 20000, "bin-path" => env.SRCDIR + "/fcgi-auth", "mode" => "authorizer", "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/", - + ) ) ) - + cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".py" => "/usr/bin/python" ) - + ssl.engine = "disable" @@ -113,22 +113,22 @@ auth.backend.ldap.hostname = "localhost" auth.backend.ldap.base-dn = "dc=my-domain,dc=com" auth.backend.ldap.filter = "(uid=$)" -auth.require = ( "/server-status" => - ( +auth.require = ( "/server-status" => + ( "method" => "digest", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "host=192.168.2.10") "require" => "group=www|user=jan|host=192.168.2.10" ), - "/auth.php" => - ( + "/auth.php" => + ( "method" => "basic", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "host=192.168.2.10") "require" => "user=jan" ), - "/server-config" => - ( + "/server-config" => + ( "method" => "basic", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "user=weigon", "host=192.168.2.10") diff --git a/tests/fastcgi-responder.conf b/tests/fastcgi-responder.conf index 65b88bd..be5a97e 100644 --- a/tests/fastcgi-responder.conf +++ b/tests/fastcgi-responder.conf @@ -19,7 +19,7 @@ server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log server.name = "www.example.org" server.tag = "Apache 1.3.29" -## +## ## Format: <errorfile-prefix><status>.html ## -> ..../status-404.html for 'File not found' #server.errorfile-prefix = "/home/weigon/projects/lighttpd/doc/status-" @@ -30,23 +30,23 @@ server.dir-listing = "enable" #server.event-handler = "linux-rtsig" #server.modules.path = "" -server.modules = ( - "mod_rewrite", - "mod_access", +server.modules = ( + "mod_rewrite", + "mod_access", "mod_auth", # "mod_httptls", - "mod_status", + "mod_status", "mod_expire", # "mod_simple_vhost", - "mod_redirect", + "mod_redirect", # "mod_evhost", # "mod_localizer", "mod_fastcgi", "mod_cgi", "mod_compress", - "mod_accesslog" ) + "mod_accesslog" ) -server.indexfiles = ( "index.php", "index.html", +server.indexfiles = ( "index.php", "index.html", "index.htm", "default.htm" ) #,-- only root can use these options @@ -58,7 +58,7 @@ server.indexfiles = ( "index.php", "index.html", #|# change uid to <uid> (default: don't care) #| server.groupid wwwrun #| -#`-- +#`-- ######################## MODULE CONFIG ############################ @@ -66,7 +66,7 @@ server.indexfiles = ( "index.php", "index.html", accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log" -mimetype.assign = ( ".png" => "image/png", +mimetype.assign = ( ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", @@ -86,8 +86,8 @@ compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/" compress.filetype = ("text/plain", "text/html") fastcgi.debug = 0 -fastcgi.server = ( ".fcgi" => ( - "grisu" => ( +fastcgi.server = ( ".fcgi" => ( + "grisu" => ( "host" => "127.0.0.1", "port" => 10000, "bin-path" => env.SRCDIR + "/fcgi-responder", @@ -97,12 +97,12 @@ fastcgi.server = ( ".fcgi" => ( ) ) ) - + cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".py" => "/usr/bin/python" ) - + ssl.engine = "disable" @@ -116,22 +116,22 @@ auth.backend.ldap.hostname = "localhost" auth.backend.ldap.base-dn = "dc=my-domain,dc=com" auth.backend.ldap.filter = "(uid=$)" -auth.require = ( "/server-status" => - ( +auth.require = ( "/server-status" => + ( "method" => "digest", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "host=192.168.2.10") "require" => "group=www|user=jan|host=192.168.2.10" ), - "/auth.php" => - ( + "/auth.php" => + ( "method" => "basic", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "host=192.168.2.10") "require" => "user=jan" ), - "/server-config" => - ( + "/server-config" => + ( "method" => "basic", "realm" => "download archiv", # "require" => ("group=www", "user=jan", "user=weigon", "host=192.168.2.10") diff --git a/tests/fcgi-auth.c b/tests/fcgi-auth.c index ddecddc..bb7ae69 100644 --- a/tests/fcgi-auth.c +++ b/tests/fcgi-auth.c @@ -1,25 +1,30 @@ +#include "config.h" +#ifdef HAVE_FASTCGI_FASTCGI_H +#include <fastcgi/fcgi_stdio.h> +#else #include <fcgi_stdio.h> +#endif #include <stdlib.h> #include <unistd.h> #include <string.h> int main () { char* p; - - while (FCGI_Accept() >= 0) { + + while (FCGI_Accept() >= 0) { /* wait for fastcgi authorizer request */ - + printf("Content-type: text/html\r\n"); - + if (((p = getenv("QUERY_STRING")) == NULL) || strcmp(p, "ok") != 0) { printf("Status: 403 Forbidden\r\n\r\n"); - } else { + } else { printf("\r\n"); /* default Status is 200 - allow access */ } - - printf("foobar\r\n"); + + printf("foobar\r\n"); } return 0; diff --git a/tests/fcgi-responder.c b/tests/fcgi-responder.c index 7fbaf28..9270295 100644 --- a/tests/fcgi-responder.c +++ b/tests/fcgi-responder.c @@ -1,15 +1,20 @@ +#include "config.h" +#ifdef HAVE_FASTCGI_FASTCGI_H +#include <fastcgi/fcgi_stdio.h> +#else #include <fcgi_stdio.h> +#endif #include <stdlib.h> #include <unistd.h> #include <string.h> int main () { int num_requests = 2; - + while (num_requests > 0 && FCGI_Accept() >= 0) { char* p; - + if (NULL != (p = getenv("QUERY_STRING"))) { if (0 == strcmp(p, "lf")) { printf("Status: 200 OK\n\n"); @@ -32,9 +37,9 @@ int main () { } else { printf("Status: 500 Internal Foo\r\n\r\n"); } - + printf("test123"); } - + return 0; } diff --git a/tests/lighttpd.conf b/tests/lighttpd.conf index 2426925..878cb1f 100644 --- a/tests/lighttpd.conf +++ b/tests/lighttpd.conf @@ -21,17 +21,17 @@ server.dir-listing = "enable" #server.event-handler = "linux-rtsig" #server.modules.path = "" -server.modules = ( +server.modules = ( "mod_rewrite", "mod_setenv", "mod_secdownload", - "mod_access", + "mod_access", "mod_auth", # "mod_httptls", - "mod_status", + "mod_status", "mod_expire", "mod_simple_vhost", - "mod_redirect", + "mod_redirect", # "mod_evhost", # "mod_localizer", "mod_fastcgi", @@ -39,9 +39,9 @@ server.modules = ( "mod_compress", "mod_userdir", "mod_ssi", - "mod_accesslog" ) + "mod_accesslog" ) -server.indexfiles = ( "index.php", "index.html", +server.indexfiles = ( "index.php", "index.html", "index.htm", "default.htm" ) @@ -51,7 +51,7 @@ ssi.extension = ( ".shtml" ) accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log" -mimetype.assign = ( ".png" => "image/png", +mimetype.assign = ( ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", @@ -84,12 +84,12 @@ fastcgi.debug = 0 fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ), "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) ) ) - + cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".py" => "/usr/bin/python" ) - + userdir.include-user = ( "jan" ) userdir.path = "/" @@ -106,14 +106,14 @@ auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user" auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd" -auth.require = ( "/server-status" => - ( +auth.require = ( "/server-status" => + ( "method" => "digest", "realm" => "download archiv", "require" => "group=www|user=jan|host=192.168.2.10" ), - "/server-config" => - ( + "/server-config" => + ( "method" => "basic", "realm" => "download archiv", "require" => "valid-user" @@ -125,7 +125,7 @@ url.access-deny = ( "~", ".inc") url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1", "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" ) -expire.url = ( "/expire/access" => "access 2 hours", +expire.url = ( "/expire/access" => "access 2 hours", "/expire/modification" => "access plus 1 seconds 2 minutes") #cache.cache-dir = "/home/weigon/wwwroot/cache/" diff --git a/tests/lowercase.conf b/tests/lowercase.conf index 60eb40f..557a703 100644 --- a/tests/lowercase.conf +++ b/tests/lowercase.conf @@ -12,25 +12,25 @@ server.force-lowercase-filenames = "enable" server.dir-listing = "enable" -server.modules = ( +server.modules = ( "mod_rewrite", "mod_setenv", "mod_secdownload", - "mod_access", + "mod_access", "mod_auth", - "mod_status", + "mod_status", "mod_expire", - "mod_redirect", + "mod_redirect", "mod_fastcgi", - "mod_cgi" ) + "mod_cgi" ) -server.indexfiles = ( "index.php", "index.html", +server.indexfiles = ( "index.php", "index.html", "index.htm", "default.htm" ) ######################## MODULE CONFIG ############################ -mimetype.assign = ( ".png" => "image/png", +mimetype.assign = ( ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", @@ -50,20 +50,20 @@ fastcgi.debug = 0 fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ), "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) ) ) - + cgi.assign = ( ".pl" => "/usr/bin/perl", ".cgi" => "/usr/bin/perl", ".py" => "/usr/bin/python" ) - + auth.backend = "plain" auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user" auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd" $HTTP["host"] == "lowercase-auth" { - auth.require = ( "/image.jpg" => - ( + auth.require = ( "/image.jpg" => + ( "method" => "digest", "realm" => "download archiv", "require" => "valid-user" diff --git a/tests/lowercase.t b/tests/lowercase.t index e127cdd..b9ee8e8 100755 --- a/tests/lowercase.t +++ b/tests/lowercase.t @@ -15,7 +15,7 @@ my $tf = LightyTest->new(); my $t; $tf->{CONFIGFILE} = 'lowercase.conf'; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); ## check if lower-casing works diff --git a/tests/mod-access.t b/tests/mod-access.t index b32dfe0..fb08db4 100755 --- a/tests/mod-access.t +++ b/tests/mod-access.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); $t->{REQUEST} = ( <<EOF diff --git a/tests/mod-auth.t b/tests/mod-auth.t index 8500ced..b0efbde 100755 --- a/tests/mod-auth.t +++ b/tests/mod-auth.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); $t->{REQUEST} = ( <<EOF @@ -83,11 +83,11 @@ ok($tf->handle_http($t) == 0, 'Digest-Auth: missing qop, no crash'); $t->{REQUEST} = ( <<EOF GET /server-status HTTP/1.0 User-Agent: Wget/1.9.1 -Authorization: Digest username="jan", realm="jan", - nonce="b1d12348b4620437c43dd61c50ae4639", - uri="/MJ-BONG.xm.mpc", qop=auth, noncecount=00000001", - cnonce="036FCA5B86F7E7C4965C7F9B8FE714B7", - response="29B32C2953C763C6D033C8A49983B87E" +Authorization: Digest username="jan", realm="jan", + nonce="b1d12348b4620437c43dd61c50ae4639", + uri="/MJ-BONG.xm.mpc", qop=auth, noncecount=00000001", + cnonce="036FCA5B86F7E7C4965C7F9B8FE714B7", + response="29B32C2953C763C6D033C8A49983B87E" EOF ); $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 400 } ]; diff --git a/tests/mod-cgi.t b/tests/mod-cgi.t index b205d8c..a42bcd5 100755 --- a/tests/mod-cgi.t +++ b/tests/mod-cgi.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); # mod-cgi diff --git a/tests/mod-compress.t b/tests/mod-compress.t index e4f110f..f243832 100755 --- a/tests/mod-compress.t +++ b/tests/mod-compress.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); $t->{REQUEST} = ( <<EOF diff --git a/tests/mod-redirect.t b/tests/mod-redirect.t index 666ca80..b26abc9 100755 --- a/tests/mod-redirect.t +++ b/tests/mod-redirect.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); $t->{REQUEST} = ( <<EOF diff --git a/tests/mod-rewrite.t b/tests/mod-rewrite.t index 31c7d1a..a1e2193 100755 --- a/tests/mod-rewrite.t +++ b/tests/mod-rewrite.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + SKIP: { skip "no PHP running on port 1026", 5 unless $tf->listening_on(1026); @@ -27,7 +27,7 @@ EOF ); $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '' } ]; ok($tf->handle_http($t) == 0, 'valid request'); - + $t->{REQUEST} = ( <<EOF GET /rewrite/foo?a=b HTTP/1.0 Host: www.example.org diff --git a/tests/mod-setenv.t b/tests/mod-setenv.t index 1eb32a1..a5c2b7e 100755 --- a/tests/mod-setenv.t +++ b/tests/mod-setenv.t @@ -14,7 +14,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); $t->{REQUEST} = ( <<EOF diff --git a/tests/mod-ssi.t b/tests/mod-ssi.t index 8bc88cc..a6b021b 100755 --- a/tests/mod-ssi.t +++ b/tests/mod-ssi.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); # mod-cgi diff --git a/tests/mod-userdir.t b/tests/mod-userdir.t index 30d546a..13a8e1b 100755 --- a/tests/mod-userdir.t +++ b/tests/mod-userdir.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); # get current user diff --git a/tests/prepare.sh b/tests/prepare.sh index 71816d1..040b6ee 100755 --- a/tests/prepare.sh +++ b/tests/prepare.sh @@ -42,7 +42,7 @@ cp $srcdir/var-include-sub.conf $tmpdir/../ touch $tmpdir/servers/www.example.org/pages/image.jpg \ $tmpdir/servers/www.example.org/pages/image.JPG \ $tmpdir/servers/www.example.org/pages/Foo.txt \ - $tmpdir/servers/www.example.org/pages/a + $tmpdir/servers/www.example.org/pages/a echo "12345" > $tmpdir/servers/www.example.org/pages/range.pdf printf "%-40s" "preparing infrastructure" diff --git a/tests/request.t b/tests/request.t index 7dd4cc6..64e48cc 100755 --- a/tests/request.t +++ b/tests/request.t @@ -13,7 +13,7 @@ use LightyTest; my $tf = LightyTest->new(); my $t; - + ok($tf->start_proc == 0, "Starting lighttpd") or die(); ## Basic Request-Handling diff --git a/tests/run-tests.pl b/tests/run-tests.pl index 44e76a9..6dae9a8 100755 --- a/tests/run-tests.pl +++ b/tests/run-tests.pl @@ -2,8 +2,8 @@ use strict; -use Test::Harness qw(&runtests $verbose); -$verbose=0; +use Test::Harness qw(&runtests $verbose); +$verbose=0; my $srcdir = (defined $ENV{'srcdir'} ? $ENV{'srcdir'} : '.'); diff --git a/tests/var-include.conf b/tests/var-include.conf index 397c91d..4cf6113 100644 --- a/tests/var-include.conf +++ b/tests/var-include.conf @@ -16,7 +16,7 @@ server.tag = "Apache 1.3.29" server.modules = ( "mod_redirect", - "mod_accesslog" ) + "mod_accesslog" ) ######################## MODULE CONFIG ############################ |