1 --- ../lighttpd-1.4.11/NEWS 2006-03-09 19:34:33.000000000 +0200
2 +++ lighttpd-1.4.12/NEWS 2006-07-16 00:26:05.000000000 +0300
9 + * added handling of Content-Range to PUT requests in mod_webdav
10 + * added handling of ETag and If-Modified-Since to mod_compress if
11 + cache-dir is not set
12 + * added experimental LOCK support for mod_webdav
13 + * added support for X-Sendfile as addition to X-LIGHTTPD-send-file.
14 + This allows compatibility with mod_xsendfile for apache
15 + (http://celebnamer.celebworld.ws/stuff/mod_xsendfile/)
16 + * fixed handling of If-Modified-Since if Etag is not set
17 + * fixed hanging fastcgi connections
18 + * fixed stalling SSL POST requests
19 + * fixed round-robin load-balancing in mod_proxy
20 + * TODO: add fail-over to mod-proxy
21 + * TODO: fix CACHE_HIT/MISS in mod_cml
22 + * TODO: finish LOCK/UNLOCK in mod_webdav
26 * added ability to specify which ip address spawn-fci listens on
27 --- ../lighttpd-1.4.11/configure.in 2006-03-04 16:32:38.000000000 +0200
28 +++ lighttpd-1.4.12/configure.in 2006-07-19 20:02:55.000000000 +0300
31 # Process this file with autoconf to produce a configure script.
33 -AC_INIT(lighttpd, 1.4.11, jan@kneschke.de)
34 +AC_INIT(lighttpd, 1.4.12, jan@kneschke.de)
35 AC_CONFIG_SRCDIR([src/server.c])
42 -AC_CHECK_MEMBER(struct tm.tm_gmtoff,AC_DEFINE([HAVE_STRUCT_TM_GMTOFF],[1],[gmtoff in struct tm]),,[#include <time.h>])
43 +AC_CHECK_MEMBER(struct tm.tm_gmtoff,[AC_DEFINE([HAVE_STRUCT_TM_GMTOFF],[1],[gmtoff in struct tm])],,[#include <time.h>])
44 AC_CHECK_TYPES(struct sockaddr_storage,,,[#include <sys/socket.h>])
45 AC_CHECK_TYPES(socklen_t,,,[#include <sys/types.h>
46 #include <sys/socket.h>])
48 AC_DEFINE([HAVE_SQLITE3], [1], [libsqlite3])
49 AC_DEFINE([HAVE_SQLITE3_H], [1], [sqlite3.h])
52 + AC_MSG_CHECKING(for locks in mod_webdav)
53 + AC_ARG_WITH(webdav-locks, AC_HELP_STRING([--with-webdav-locks],[locks in mod_webdav]),
54 + [WITH_WEBDAV_LOCKS=$withval],[WITH_WEBDAV_LOCKS=no])
55 + AC_MSG_RESULT([$WITH_WEBDAV_LOCKS])
57 + if test "$WITH_WEBDAV_LOCKS" != "no"; then
58 + AC_CHECK_LIB(uuid, uuid_unparse, [
59 + AC_CHECK_HEADERS([uuid/uuid.h],[
61 + AC_DEFINE([HAVE_UUID], [1], [libuuid])
62 + AC_DEFINE([HAVE_UUID_H], [1], [uuid/uuid.h is available])
72 AC_MSG_RESULT($WITH_LUA)
73 if test "$WITH_LUA" != "no"; then
74 - AC_PATH_PROG(LUACONFIG, lua-config)
76 - if test x"$LUACONFIG" != x; then
77 - LUA_CFLAGS=`$LUACONFIG --include`
78 - LUA_LIBS=`$LUACONFIG --libs --extralibs`
80 + PKG_CHECK_MODULES(LUA, lua >= 5.1, [
81 AC_DEFINE([HAVE_LUA], [1], [liblua])
82 AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
84 - AC_CHECK_LIB(lua, lua_open, [
85 - AC_CHECK_HEADERS([lua.h],[
86 - LUA_LIBS="-llua -llualib"
87 - AC_DEFINE([HAVE_LUA], [1], [liblua])
88 - AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
93 - if test x"$LUA_LIBS" = x; then
95 - PKG_CHECK_MODULES(LUA, lua, [
96 - AC_DEFINE([HAVE_LUA], [1], [liblua])
97 - AC_DEFINE([HAVE_LUA_H], [1], [lua.h])
107 AC_CHECK_FUNCS([dup2 getcwd inet_ntoa inet_ntop memset mmap munmap strchr \
108 - strdup strerror strstr strtol sendfile getopt socket \
109 - gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot \
110 + strdup strerror strstr strtol sendfile getopt socket lstat \
111 + gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot strptime \
112 getuid select signal pathconf madvise posix_fadvise posix_madvise \
113 writev sigaction sendfile64 send_file kqueue port_create localtime_r])
118 if test "${GCC}" = "yes"; then
119 - CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic"
120 + CFLAGS="${CFLAGS} -Wall -W -Wshadow -pedantic -std=gnu99"
128 -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"
129 +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"
131 plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
132 features="regex-conditionals"
134 disable_feature="$disable_feature $features"
137 +features="webdav-locks"
138 +if test "x$UUID_LIB" \!= x; then
139 + enable_feature="$enable_feature $features"
141 + disable_feature="$disable_feature $features"
148 --- ../lighttpd-1.4.11/cygwin/lighttpd.README 2006-03-07 14:22:19.000000000 +0200
149 +++ lighttpd-1.4.12/cygwin/lighttpd.README 2006-07-19 20:09:00.000000000 +0300
152 -------------------------------------------
\r
153 -A fast, secure and flexible webserver
\r
155 -Runtime requirements:
\r
156 - cygwin-1.5.10 or newer
\r
157 - crypt-1.1 or newer
\r
158 - libbz2_1-1.0.2 or newer
\r
159 - libpcre0-4.5 or newer
\r
160 - openssl-0.9.7d or newer
\r
161 - zlib-1.2.1 or newer
\r
163 -Build requirements:
\r
164 - cygwin-1.5.10 or newer
\r
165 - gcc-3.3.1-3 or newer
\r
166 - binutils-20030901-1 or newer
\r
175 -Canonical homepage:
\r
176 - http://jan.kneschke.de/projects/lighttpd/
\r
178 -Canonical download:
\r
179 - http://jan.kneschke.de/projects/lighttpd/download
\r
181 -------------------------------------
\r
183 -Build instructions:
\r
184 - unpack lighttpd-1.4.11-<REL>-src.tar.bz2
\r
185 - if you use setup to install this src package, it will be
\r
186 - unpacked under /usr/src automatically
\r
188 - ./lighttpd-1.4.11-<REL>.sh all
\r
191 - /usr/src/lighttpd-1.4.11-<REL>.tar.bz2
\r
192 - /usr/src/lighttpd-1.4.11-<REL>-src.tar.bz2
\r
194 -Or use './lighttpd-1.4.11-<REL>.sh prep' to get a patched source directory
\r
196 --------------------------------------------
\r
198 -Files included in the binary distribution:
\r
200 - /etc/lighttpd/lighttpd.conf.default
\r
201 - /usr/lib/cyglightcomp.dll
\r
202 - /usr/lib/lighttpd/mod_access.dll
\r
203 - /usr/lib/lighttpd/mod_accesslog.dll
\r
204 - /usr/lib/lighttpd/mod_auth.dll
\r
205 - /usr/lib/lighttpd/mod_cgi.dll
\r
206 - /usr/lib/lighttpd/mod_compress.dll
\r
207 - /usr/lib/lighttpd/mod_evhost.dll
\r
208 - /usr/lib/lighttpd/mod_expire.dll
\r
209 - /usr/lib/lighttpd/mod_fastcgi.dll
\r
210 - /usr/lib/lighttpd/mod_httptls.dll
\r
211 - /usr/lib/lighttpd/mod_maps.dll
\r
212 - /usr/lib/lighttpd/mod_proxy.dll
\r
213 - /usr/lib/lighttpd/mod_redirect.dll
\r
214 - /usr/lib/lighttpd/mod_rewrite.dll
\r
215 - /usr/lib/lighttpd/mod_rrdtool.dll
\r
216 - /usr/lib/lighttpd/mod_secdownload.dll
\r
217 - /usr/lib/lighttpd/mod_simple_vhost.dll
\r
218 - /usr/lib/lighttpd/mod_ssi.dll
\r
219 - /usr/lib/lighttpd/mod_status.dll
\r
220 - /usr/lib/lighttpd/mod_usertrack.dll
\r
221 - /usr/sbin/lighttpd.exe
\r
222 - /usr/share/doc/Cygwin/lighttpd-1.3.0.README
\r
223 - /usr/share/doc/lighttpd-1.3.0/accesslog.txt
\r
224 - /usr/share/doc/lighttpd-1.3.0/authentification.txt
\r
225 - /usr/share/doc/lighttpd-1.3.0/AUTHORS
\r
226 - /usr/share/doc/lighttpd-1.3.0/cgi.txt
\r
227 - /usr/share/doc/lighttpd-1.3.0/ChangeLog
\r
228 - /usr/share/doc/lighttpd-1.3.0/compress.txt
\r
229 - /usr/share/doc/lighttpd-1.3.0/configuration.txt
\r
230 - /usr/share/doc/lighttpd-1.3.0/COPYING
\r
231 - /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
\r
232 - /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
\r
233 - /usr/share/doc/lighttpd-1.3.0/features.txt
\r
234 - /usr/share/doc/lighttpd-1.3.0/INSTALL
\r
235 - /usr/share/doc/lighttpd-1.3.0/NEWS
\r
236 - /usr/share/doc/lighttpd-1.3.0/performance.txt
\r
237 - /usr/share/doc/lighttpd-1.3.0/plugins.txt
\r
238 - /usr/share/doc/lighttpd-1.3.0/proxy.txt
\r
239 - /usr/share/doc/lighttpd-1.3.0/README
\r
240 - /usr/share/doc/lighttpd-1.3.0/redirect.txt
\r
241 - /usr/share/doc/lighttpd-1.3.0/rewrite.txt
\r
242 - /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
\r
243 - /usr/share/doc/lighttpd-1.3.0/secdownload.txt
\r
244 - /usr/share/doc/lighttpd-1.3.0/security.txt
\r
245 - /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
\r
246 - /usr/share/doc/lighttpd-1.3.0/skeleton.txt
\r
247 - /usr/share/doc/lighttpd-1.3.0/ssi.txt
\r
248 - /usr/share/doc/lighttpd-1.3.0/state.txt
\r
249 - /usr/share/man/man1/lighttpd.1.gz
\r
251 -------------------
\r
255 ----------- lighttpd-1.3.1-1 -----------
\r
259 ----------- lighttpd-1.3.0-1 -----------
\r
262 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
\r
263 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
\r
266 +------------------------------------------
267 +A fast, secure and flexible webserver
269 +Runtime requirements:
270 + cygwin-1.5.10 or newer
272 + libbz2_1-1.0.2 or newer
273 + libpcre0-4.5 or newer
274 + openssl-0.9.7d or newer
275 + zlib-1.2.1 or newer
278 + cygwin-1.5.10 or newer
279 + gcc-3.3.1-3 or newer
280 + binutils-20030901-1 or newer
290 + http://jan.kneschke.de/projects/lighttpd/
293 + http://jan.kneschke.de/projects/lighttpd/download
295 +------------------------------------
298 + unpack lighttpd-1.4.12-<REL>-src.tar.bz2
299 + if you use setup to install this src package, it will be
300 + unpacked under /usr/src automatically
302 + ./lighttpd-1.4.12-<REL>.sh all
305 + /usr/src/lighttpd-1.4.12-<REL>.tar.bz2
306 + /usr/src/lighttpd-1.4.12-<REL>-src.tar.bz2
308 +Or use './lighttpd-1.4.12-<REL>.sh prep' to get a patched source directory
310 +-------------------------------------------
312 +Files included in the binary distribution:
314 + /etc/lighttpd/lighttpd.conf.default
315 + /usr/lib/cyglightcomp.dll
316 + /usr/lib/lighttpd/mod_access.dll
317 + /usr/lib/lighttpd/mod_accesslog.dll
318 + /usr/lib/lighttpd/mod_auth.dll
319 + /usr/lib/lighttpd/mod_cgi.dll
320 + /usr/lib/lighttpd/mod_compress.dll
321 + /usr/lib/lighttpd/mod_evhost.dll
322 + /usr/lib/lighttpd/mod_expire.dll
323 + /usr/lib/lighttpd/mod_fastcgi.dll
324 + /usr/lib/lighttpd/mod_httptls.dll
325 + /usr/lib/lighttpd/mod_maps.dll
326 + /usr/lib/lighttpd/mod_proxy.dll
327 + /usr/lib/lighttpd/mod_redirect.dll
328 + /usr/lib/lighttpd/mod_rewrite.dll
329 + /usr/lib/lighttpd/mod_rrdtool.dll
330 + /usr/lib/lighttpd/mod_secdownload.dll
331 + /usr/lib/lighttpd/mod_simple_vhost.dll
332 + /usr/lib/lighttpd/mod_ssi.dll
333 + /usr/lib/lighttpd/mod_status.dll
334 + /usr/lib/lighttpd/mod_usertrack.dll
335 + /usr/sbin/lighttpd.exe
336 + /usr/share/doc/Cygwin/lighttpd-1.3.0.README
337 + /usr/share/doc/lighttpd-1.3.0/accesslog.txt
338 + /usr/share/doc/lighttpd-1.3.0/authentification.txt
339 + /usr/share/doc/lighttpd-1.3.0/AUTHORS
340 + /usr/share/doc/lighttpd-1.3.0/cgi.txt
341 + /usr/share/doc/lighttpd-1.3.0/ChangeLog
342 + /usr/share/doc/lighttpd-1.3.0/compress.txt
343 + /usr/share/doc/lighttpd-1.3.0/configuration.txt
344 + /usr/share/doc/lighttpd-1.3.0/COPYING
345 + /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
346 + /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
347 + /usr/share/doc/lighttpd-1.3.0/features.txt
348 + /usr/share/doc/lighttpd-1.3.0/INSTALL
349 + /usr/share/doc/lighttpd-1.3.0/NEWS
350 + /usr/share/doc/lighttpd-1.3.0/performance.txt
351 + /usr/share/doc/lighttpd-1.3.0/plugins.txt
352 + /usr/share/doc/lighttpd-1.3.0/proxy.txt
353 + /usr/share/doc/lighttpd-1.3.0/README
354 + /usr/share/doc/lighttpd-1.3.0/redirect.txt
355 + /usr/share/doc/lighttpd-1.3.0/rewrite.txt
356 + /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
357 + /usr/share/doc/lighttpd-1.3.0/secdownload.txt
358 + /usr/share/doc/lighttpd-1.3.0/security.txt
359 + /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
360 + /usr/share/doc/lighttpd-1.3.0/skeleton.txt
361 + /usr/share/doc/lighttpd-1.3.0/ssi.txt
362 + /usr/share/doc/lighttpd-1.3.0/state.txt
363 + /usr/share/man/man1/lighttpd.1.gz
369 +---------- lighttpd-1.3.1-1 -----------
373 +---------- lighttpd-1.3.0-1 -----------
376 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
377 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
379 --- ../lighttpd-1.4.11/cygwin/lighttpd.README.in 2005-08-11 01:26:59.000000000 +0300
380 +++ lighttpd-1.4.12/cygwin/lighttpd.README.in 2006-07-16 00:26:04.000000000 +0300
383 -------------------------------------------
\r
384 -A fast, secure and flexible webserver
\r
386 -Runtime requirements:
\r
387 - cygwin-1.5.10 or newer
\r
388 - crypt-1.1 or newer
\r
389 - libbz2_1-1.0.2 or newer
\r
390 - libpcre0-4.5 or newer
\r
391 - openssl-0.9.7d or newer
\r
392 - zlib-1.2.1 or newer
\r
394 -Build requirements:
\r
395 - cygwin-1.5.10 or newer
\r
396 - gcc-3.3.1-3 or newer
\r
397 - binutils-20030901-1 or newer
\r
406 -Canonical homepage:
\r
407 - http://jan.kneschke.de/projects/lighttpd/
\r
409 -Canonical download:
\r
410 - http://jan.kneschke.de/projects/lighttpd/download
\r
412 -------------------------------------
\r
414 -Build instructions:
\r
415 - unpack lighttpd-@VERSION@-<REL>-src.tar.bz2
\r
416 - if you use setup to install this src package, it will be
\r
417 - unpacked under /usr/src automatically
\r
419 - ./lighttpd-@VERSION@-<REL>.sh all
\r
422 - /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
\r
423 - /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
\r
425 -Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
\r
427 --------------------------------------------
\r
429 -Files included in the binary distribution:
\r
431 - /etc/lighttpd/lighttpd.conf.default
\r
432 - /usr/lib/cyglightcomp.dll
\r
433 - /usr/lib/lighttpd/mod_access.dll
\r
434 - /usr/lib/lighttpd/mod_accesslog.dll
\r
435 - /usr/lib/lighttpd/mod_auth.dll
\r
436 - /usr/lib/lighttpd/mod_cgi.dll
\r
437 - /usr/lib/lighttpd/mod_compress.dll
\r
438 - /usr/lib/lighttpd/mod_evhost.dll
\r
439 - /usr/lib/lighttpd/mod_expire.dll
\r
440 - /usr/lib/lighttpd/mod_fastcgi.dll
\r
441 - /usr/lib/lighttpd/mod_httptls.dll
\r
442 - /usr/lib/lighttpd/mod_maps.dll
\r
443 - /usr/lib/lighttpd/mod_proxy.dll
\r
444 - /usr/lib/lighttpd/mod_redirect.dll
\r
445 - /usr/lib/lighttpd/mod_rewrite.dll
\r
446 - /usr/lib/lighttpd/mod_rrdtool.dll
\r
447 - /usr/lib/lighttpd/mod_secdownload.dll
\r
448 - /usr/lib/lighttpd/mod_simple_vhost.dll
\r
449 - /usr/lib/lighttpd/mod_ssi.dll
\r
450 - /usr/lib/lighttpd/mod_status.dll
\r
451 - /usr/lib/lighttpd/mod_usertrack.dll
\r
452 - /usr/sbin/lighttpd.exe
\r
453 - /usr/share/doc/Cygwin/lighttpd-1.3.0.README
\r
454 - /usr/share/doc/lighttpd-1.3.0/accesslog.txt
\r
455 - /usr/share/doc/lighttpd-1.3.0/authentification.txt
\r
456 - /usr/share/doc/lighttpd-1.3.0/AUTHORS
\r
457 - /usr/share/doc/lighttpd-1.3.0/cgi.txt
\r
458 - /usr/share/doc/lighttpd-1.3.0/ChangeLog
\r
459 - /usr/share/doc/lighttpd-1.3.0/compress.txt
\r
460 - /usr/share/doc/lighttpd-1.3.0/configuration.txt
\r
461 - /usr/share/doc/lighttpd-1.3.0/COPYING
\r
462 - /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
\r
463 - /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
\r
464 - /usr/share/doc/lighttpd-1.3.0/features.txt
\r
465 - /usr/share/doc/lighttpd-1.3.0/INSTALL
\r
466 - /usr/share/doc/lighttpd-1.3.0/NEWS
\r
467 - /usr/share/doc/lighttpd-1.3.0/performance.txt
\r
468 - /usr/share/doc/lighttpd-1.3.0/plugins.txt
\r
469 - /usr/share/doc/lighttpd-1.3.0/proxy.txt
\r
470 - /usr/share/doc/lighttpd-1.3.0/README
\r
471 - /usr/share/doc/lighttpd-1.3.0/redirect.txt
\r
472 - /usr/share/doc/lighttpd-1.3.0/rewrite.txt
\r
473 - /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
\r
474 - /usr/share/doc/lighttpd-1.3.0/secdownload.txt
\r
475 - /usr/share/doc/lighttpd-1.3.0/security.txt
\r
476 - /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
\r
477 - /usr/share/doc/lighttpd-1.3.0/skeleton.txt
\r
478 - /usr/share/doc/lighttpd-1.3.0/ssi.txt
\r
479 - /usr/share/doc/lighttpd-1.3.0/state.txt
\r
480 - /usr/share/man/man1/lighttpd.1.gz
\r
482 -------------------
\r
486 ----------- lighttpd-1.3.1-1 -----------
\r
490 ----------- lighttpd-1.3.0-1 -----------
\r
493 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
\r
494 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
\r
497 +------------------------------------------
498 +A fast, secure and flexible webserver
500 +Runtime requirements:
501 + cygwin-1.5.10 or newer
503 + libbz2_1-1.0.2 or newer
504 + libpcre0-4.5 or newer
505 + openssl-0.9.7d or newer
506 + zlib-1.2.1 or newer
509 + cygwin-1.5.10 or newer
510 + gcc-3.3.1-3 or newer
511 + binutils-20030901-1 or newer
521 + http://jan.kneschke.de/projects/lighttpd/
524 + http://jan.kneschke.de/projects/lighttpd/download
526 +------------------------------------
529 + unpack lighttpd-@VERSION@-<REL>-src.tar.bz2
530 + if you use setup to install this src package, it will be
531 + unpacked under /usr/src automatically
533 + ./lighttpd-@VERSION@-<REL>.sh all
536 + /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
537 + /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
539 +Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
541 +-------------------------------------------
543 +Files included in the binary distribution:
545 + /etc/lighttpd/lighttpd.conf.default
546 + /usr/lib/cyglightcomp.dll
547 + /usr/lib/lighttpd/mod_access.dll
548 + /usr/lib/lighttpd/mod_accesslog.dll
549 + /usr/lib/lighttpd/mod_auth.dll
550 + /usr/lib/lighttpd/mod_cgi.dll
551 + /usr/lib/lighttpd/mod_compress.dll
552 + /usr/lib/lighttpd/mod_evhost.dll
553 + /usr/lib/lighttpd/mod_expire.dll
554 + /usr/lib/lighttpd/mod_fastcgi.dll
555 + /usr/lib/lighttpd/mod_httptls.dll
556 + /usr/lib/lighttpd/mod_maps.dll
557 + /usr/lib/lighttpd/mod_proxy.dll
558 + /usr/lib/lighttpd/mod_redirect.dll
559 + /usr/lib/lighttpd/mod_rewrite.dll
560 + /usr/lib/lighttpd/mod_rrdtool.dll
561 + /usr/lib/lighttpd/mod_secdownload.dll
562 + /usr/lib/lighttpd/mod_simple_vhost.dll
563 + /usr/lib/lighttpd/mod_ssi.dll
564 + /usr/lib/lighttpd/mod_status.dll
565 + /usr/lib/lighttpd/mod_usertrack.dll
566 + /usr/sbin/lighttpd.exe
567 + /usr/share/doc/Cygwin/lighttpd-1.3.0.README
568 + /usr/share/doc/lighttpd-1.3.0/accesslog.txt
569 + /usr/share/doc/lighttpd-1.3.0/authentification.txt
570 + /usr/share/doc/lighttpd-1.3.0/AUTHORS
571 + /usr/share/doc/lighttpd-1.3.0/cgi.txt
572 + /usr/share/doc/lighttpd-1.3.0/ChangeLog
573 + /usr/share/doc/lighttpd-1.3.0/compress.txt
574 + /usr/share/doc/lighttpd-1.3.0/configuration.txt
575 + /usr/share/doc/lighttpd-1.3.0/COPYING
576 + /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
577 + /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
578 + /usr/share/doc/lighttpd-1.3.0/features.txt
579 + /usr/share/doc/lighttpd-1.3.0/INSTALL
580 + /usr/share/doc/lighttpd-1.3.0/NEWS
581 + /usr/share/doc/lighttpd-1.3.0/performance.txt
582 + /usr/share/doc/lighttpd-1.3.0/plugins.txt
583 + /usr/share/doc/lighttpd-1.3.0/proxy.txt
584 + /usr/share/doc/lighttpd-1.3.0/README
585 + /usr/share/doc/lighttpd-1.3.0/redirect.txt
586 + /usr/share/doc/lighttpd-1.3.0/rewrite.txt
587 + /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
588 + /usr/share/doc/lighttpd-1.3.0/secdownload.txt
589 + /usr/share/doc/lighttpd-1.3.0/security.txt
590 + /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
591 + /usr/share/doc/lighttpd-1.3.0/skeleton.txt
592 + /usr/share/doc/lighttpd-1.3.0/ssi.txt
593 + /usr/share/doc/lighttpd-1.3.0/state.txt
594 + /usr/share/man/man1/lighttpd.1.gz
600 +---------- lighttpd-1.3.1-1 -----------
604 +---------- lighttpd-1.3.0-1 -----------
607 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
608 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
610 --- ../lighttpd-1.4.11/doc/authentication.txt 2006-01-12 20:34:26.000000000 +0200
611 +++ lighttpd-1.4.12/doc/authentication.txt 2006-07-16 00:26:05.000000000 +0300
615 :Author: Jan Kneschke
617 -:Revision: $Revision$
619 +:Revision: $Revision$
622 The auth module provides ...
623 --- ../lighttpd-1.4.11/doc/compress.txt 2005-08-11 01:26:16.000000000 +0300
624 +++ lighttpd-1.4.12/doc/compress.txt 2006-07-16 00:26:05.000000000 +0300
628 Output compression reduces the network load and can improve the overall
629 -throughput of the webserver.
630 +throughput of the webserver. All major http-clients support compression by
631 +announcing it in the Accept-Encoding header. This is used to negotiate the
632 +most suitable compression method. We support deflate, gzip and bzip2.
634 -Only static content is supported up to now.
635 +deflate (RFC1950, RFC1951) and gzip (RFC1952) depend on zlib while bzip2
636 +depends on libbzip2. bzip2 is only supported by lynx and some other console
639 -The server negotiates automaticly which compression method is used.
640 -Supported are gzip, deflate, bzip.
641 +Currently we limit to compression support to static files.
646 +mod_compress can stored compressed files on disk to optimized the compression
647 +on a second request away. As soon as compress.cache-dir is set the files are
650 +The names of the cache files are made of the filename, the compression method
651 +and the etag associated to the file.
653 +Cleaning the cache is left to the user. A cron job deleting files older than
654 +10 days should do fine.
659 +The module limits the compression of files to files larger than 128 Byte and
660 +smaller than 128 MByte.
662 +The lower limit is set as small files tend to become larger by compressing due
663 +to the compression headers, the upper limit is set to work sensable with
664 +memory and cpu-time.
669 Default: not set, compress the file for every request
672 - mimetypes where might get compressed
673 + mimetypes which might get compressed
677 compress.filetype = ("text/plain", "text/html")
679 + Keep in mind that compressed JavaScript and CSS files are broken in some
684 +compress.max-file-size
685 + maximum size of the original file to be compressed kBytes.
687 + This is meant to protect the server against DoSing as compressing large
688 + (let's say 1Gbyte) takes a lot of time and would delay the whole operation
691 + There is a hard upper limit of 128Mbyte.
693 + Default: unlimited (== hard-limit of 128MByte)
695 Compressing Dynamic Content
696 ===========================
698 --- ../lighttpd-1.4.11/doc/configuration.txt 2006-03-09 02:10:40.000000000 +0200
699 +++ lighttpd-1.4.12/doc/configuration.txt 2006-07-16 00:26:05.000000000 +0300
703 :Author: Jan Kneschke
705 -:Revision: $Revision$
707 +:Revision: $Revision$
710 the layout of the configuration file
713 debug.log-request-handling
716 +debug.log-condition-handling
719 +debug.log-condition-cache-handling
720 + for developers only
722 --- ../lighttpd-1.4.11/doc/fastcgi.txt 2006-02-16 17:03:52.000000000 +0200
723 +++ lighttpd-1.4.12/doc/fastcgi.txt 2006-07-16 00:26:05.000000000 +0300
725 PHP can extract PATH_INFO from it (default: disabled)
726 :"disable-time": time to wait before a disabled backend is checked
728 - :"allow-x-send-file": controls if X-LIGHTTPD-send-file headers
730 + :"allow-x-send-file": controls if X-LIGHTTPD-send-file and X-Sendfile
731 + headers are allowed
735 --- ../lighttpd-1.4.11/doc/lighttpd.conf 2006-03-04 14:41:12.000000000 +0200
736 +++ lighttpd-1.4.12/doc/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
737 @@ -172,10 +172,11 @@
738 #dir-listing.activate = "enable"
741 -#debug.log-request-header = "enable"
742 -#debug.log-response-header = "enable"
743 -#debug.log-request-handling = "enable"
744 -#debug.log-file-not-found = "enable"
745 +#debug.log-request-header = "enable"
746 +#debug.log-response-header = "enable"
747 +#debug.log-request-handling = "enable"
748 +#debug.log-file-not-found = "enable"
749 +#debug.log-condition-handling = "enable"
751 ### only root can use these options
753 --- ../lighttpd-1.4.11/doc/performance.txt 2006-02-02 13:01:08.000000000 +0200
754 +++ lighttpd-1.4.12/doc/performance.txt 2006-07-16 00:26:05.000000000 +0300
757 server.stat-cache-engine = "fam" # either fam, simple or disabled
759 +See http://oss.sgi.com/projects/fam/faq.html for information about FAM.
760 +See http://www.gnome.org/~veillard/gamin/overview.html for information about gamin.
762 Platform-Specific Notes
763 =======================
764 --- ../lighttpd-1.4.11/doc/secdownload.txt 2005-12-20 15:58:58.000000000 +0200
765 +++ lighttpd-1.4.12/doc/secdownload.txt 2006-07-16 00:26:05.000000000 +0300
767 $secret = "verysecret";
768 $uri_prefix = "/dl/";
771 + # filename, make sure it's started with a "/" or you'll get 404 in the browser
772 $f = "/secret-file.txt";
775 --- ../lighttpd-1.4.11/lighttpd.spec 2006-03-07 14:22:18.000000000 +0200
776 +++ lighttpd-1.4.12/lighttpd.spec 2006-07-19 20:09:00.000000000 +0300
778 Summary: A fast webserver with minimal memory-footprint (lighttpd)
783 Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz
784 Packager: Jan Kneschke <jan@kneschke.de>
785 --- ../lighttpd-1.4.11/openwrt/control 2006-03-07 14:22:19.000000000 +0200
786 +++ lighttpd-1.4.12/openwrt/control 2006-07-19 20:09:00.000000000 +0300
792 Maintainer: Jan Kneschke <jan@kneschke.de>
793 -Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.11.tar.gz
794 +Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.12.tar.gz
798 --- ../lighttpd-1.4.11/openwrt/lighttpd.mk 2006-03-07 14:22:19.000000000 +0200
799 +++ lighttpd-1.4.12/openwrt/lighttpd.mk 2006-07-19 20:09:00.000000000 +0300
802 # For this example we'll use a fairly simple package that compiles easily
803 # and has sources available for download at sourceforge
804 -LIGHTTPD=lighttpd-1.4.11
805 +LIGHTTPD=lighttpd-1.4.12
806 LIGHTTPD_TARGET=.built
807 LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD)
808 LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk
809 --- ../lighttpd-1.4.11/src/Makefile.am 2006-03-07 14:20:20.000000000 +0200
810 +++ lighttpd-1.4.12/src/Makefile.am 2006-07-19 20:02:55.000000000 +0300
813 configparser.y: lemon
814 mod_ssi_exprparser.y: lemon
815 +http_resp_parser.y: lemon
817 configparser.c configparser.h: configparser.y
819 - $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
820 + $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
822 +http_resp_parser.c http_resp_parser.h: http_resp_parser.y
823 + rm -f http_resp_parser.h
824 + $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
826 mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y
827 rm -f mod_ssi_exprparser.h
828 - $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
829 + $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
832 configfile.c: configparser.h
833 mod_ssi_expr.c: mod_ssi_exprparser.h
834 +http_resp.c: http_resp_parser.h
836 common_src=buffer.c log.c \
839 fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
840 data_config.c bitset.c \
841 inet_ntop_cache.c crc32.c \
842 - connections-glue.c \
843 - configfile-glue.c \
844 + connections-glue.c iosocket.c \
845 + configfile-glue.c status_counter.c \
847 network_write.c network_linux_sendfile.c \
848 network_freebsd_sendfile.c network_writev.c \
849 network_solaris_sendfilev.c network_openssl.c \
851 + splaytree.c http_resp.c http_resp_parser.c
853 src = server.c response.c connections.c network.c \
854 configfile.c configparser.c request.c proc_open.c
857 lib_LTLIBRARIES += mod_webdav.la
858 mod_webdav_la_SOURCES = mod_webdav.c
859 -mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
860 +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
861 mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
862 -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
863 +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB)
865 lib_LTLIBRARIES += mod_cml.la
866 mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
868 mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
869 mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
871 +lib_LTLIBRARIES += mod_sql_vhost_core.la
872 +mod_sql_vhost_core_la_SOURCES = mod_sql_vhost_core.c
873 +mod_sql_vhost_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
874 +mod_sql_vhost_core_la_LIBADD = $(common_libadd)
876 lib_LTLIBRARIES += mod_cgi.la
877 mod_cgi_la_SOURCES = mod_cgi.c
878 mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
880 mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
881 mod_proxy_la_LIBADD = $(common_libadd)
883 +lib_LTLIBRARIES += mod_proxy_core.la
884 +mod_proxy_core_la_SOURCES = mod_proxy_core.c mod_proxy_core_pool.c \
885 + mod_proxy_core_backend.c mod_proxy_core_address.c \
886 + mod_proxy_core_backlog.c mod_proxy_core_rewrites.c
887 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
888 +mod_proxy_core_la_LIBADD = $(common_libadd) $(PCRE_LIB)
891 lib_LTLIBRARIES += mod_ssi.la
892 mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
893 mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
895 mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
896 configparser.h mod_ssi_exprparser.h \
897 sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
898 - splaytree.h proc_open.h
899 + splaytree.h proc_open.h http_resp.h mod_sql_vhost_core.h \
900 + sys-files.h sys-process.h sys-strings.h http_resp_parser.h \
901 + iosocket.h array-static.h \
902 + mod_proxy_core_address.h mod_proxy_core_backend.h \
903 + mod_proxy_core_backlog.h mod_proxy_core.h \
904 + mod_proxy_core_pool.h mod_proxy_core_rewrites.h \
907 DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
912 noinst_HEADERS = $(hdr)
913 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
914 +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c http_resp_parser.y
915 --- ../lighttpd-1.4.11/src/array-static.h 1970-01-01 03:00:00.000000000 +0300
916 +++ lighttpd-1.4.12/src/array-static.h 2006-07-18 13:03:40.000000000 +0300
918 +#ifndef _ARRAY_STATIC_H_
919 +#define _ARRAY_STATIC_H_
921 +/* define a generic array of <type>
924 +#define ARRAY_STATIC_DEF(name, type, extra) \
932 +/* all append operations need a 'resize' for the +1 */
934 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
935 + if (a->size == 0) { \
937 + a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
938 + } else if (a->size == a->used) { \
940 + a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
943 +#define FOREACH(array, element, func) \
944 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
946 +#define STRUCT_INIT(type, var) \
948 + var = calloc(1, sizeof(*var))
951 --- ../lighttpd-1.4.11/src/array.c 2005-11-18 13:58:32.000000000 +0200
952 +++ lighttpd-1.4.12/src/array.c 2006-07-16 00:26:03.000000000 +0300
955 array *array_init(void) {
959 a = calloc(1, sizeof(*a));
963 a->next_power_of_2 = 1;
970 void array_free(array *a) {
975 if (!a->is_weakref) {
976 for (i = 0; i < a->size; i++) {
977 if (a->data[i]) a->data[i]->free(a->data[i]);
982 if (a->data) free(a->data);
983 if (a->sorted) free(a->sorted);
989 void array_reset(array *a) {
994 if (!a->is_weakref) {
995 for (i = 0; i < a->used; i++) {
996 a->data[i]->reset(a->data[i]);
1005 static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
1010 if (key == NULL) return -1;
1013 /* try to find the string */
1014 for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1020 } else if (pos >= (int)a->used) {
1023 cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1028 ndx = a->sorted[pos];
1029 @@ -110,46 +110,46 @@
1035 if (rndx) *rndx = pos;
1041 data_unset *array_get_element(array *a, const char *key) {
1045 if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1046 /* found, leave here */
1049 return a->data[ndx];
1057 data_unset *array_get_unused_element(array *a, data_type_t t) {
1058 data_unset *ds = NULL;
1063 if (a->size == 0) return NULL;
1066 if (a->used == a->size) return NULL;
1068 if (a->data[a->used]) {
1069 ds = a->data[a->used];
1072 a->data[a->used] = NULL;
1079 /* replace or insert data, return the old one with the same key */
1080 data_unset *array_replace(array *a, data_unset *du) {
1084 if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1085 array_insert_unique(a, du);
1087 @@ -164,13 +164,13 @@
1092 - /* generate unique index if neccesary */
1094 + /* generate unique index if necessary */
1095 if (str->key->used == 0 || str->is_index_key) {
1096 buffer_copy_long(str->key, a->unique_ndx++);
1097 str->is_index_key = 1;
1101 /* try to find the string */
1102 if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1103 /* found, leave here */
1104 @@ -181,14 +181,14 @@
1113 if (a->used+1 > INT_MAX) {
1114 /* we can't handle more then INT_MAX entries: see array_get_index() */
1121 a->data = malloc(sizeof(*a->data) * a->size);
1122 @@ -204,27 +204,27 @@
1124 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1128 ndx = (int) a->used;
1131 a->data[a->used++] = str;
1137 buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1141 - /* move everything on step to the right */
1144 + /* move everything one step to the right */
1146 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1151 a->sorted[pos] = ndx;
1154 if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1171 array_print_indent(depth);
1172 fprintf(stderr, ")");
1178 @@ -323,47 +323,47 @@
1190 ds = data_string_init();
1191 buffer_copy_string(ds->key, "abc");
1192 buffer_copy_string(ds->value, "alfrag");
1195 array_insert_unique(a, (data_unset *)ds);
1198 ds = data_string_init();
1199 buffer_copy_string(ds->key, "abc");
1200 buffer_copy_string(ds->value, "hameplman");
1203 array_insert_unique(a, (data_unset *)ds);
1206 ds = data_string_init();
1207 buffer_copy_string(ds->key, "123");
1208 buffer_copy_string(ds->value, "alfrag");
1211 array_insert_unique(a, (data_unset *)ds);
1214 dc = data_count_init();
1215 buffer_copy_string(dc->key, "def");
1218 array_insert_unique(a, (data_unset *)dc);
1221 dc = data_count_init();
1222 buffer_copy_string(dc->key, "def");
1225 array_insert_unique(a, (data_unset *)dc);
1234 fprintf(stderr, "%d\n",
1235 buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1241 --- ../lighttpd-1.4.11/src/array.h 2005-09-23 21:24:18.000000000 +0300
1242 +++ lighttpd-1.4.12/src/array.h 2006-07-16 00:26:03.000000000 +0300
1244 #define DATA_UNSET \
1247 - int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1248 + int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1249 struct data_unset *(*copy)(const struct data_unset *src); \
1250 void (* free)(struct data_unset *p); \
1251 void (* reset)(struct data_unset *p); \
1268 size_t next_power_of_2;
1269 int is_weakref; /* data is weakref, don't bother the data */
1298 COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1301 -/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
1302 +/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
1303 * for print: comp_key op string
1304 * for compare: comp cond string/regex
1307 typedef struct _data_config data_config;
1308 struct _data_config {
1323 int context_ndx; /* more or less like an id */
1327 /* for chaining only */
1344 @@ -120,13 +120,13 @@
1350 unsigned short port;
1357 int usage; /* fair-balancing needs the no. of connections active on this host */
1358 int last_used_ndx; /* round robin */
1360 --- ../lighttpd-1.4.11/src/base.h 2006-01-11 16:51:04.000000000 +0200
1361 +++ lighttpd-1.4.12/src/base.h 2006-07-19 20:02:55.000000000 +0300
1365 #include <sys/types.h>
1366 -#include <sys/time.h>
1367 #include <sys/stat.h>
1369 #ifdef HAVE_CONFIG_H
1371 #include "sys-socket.h"
1372 #include "splaytree.h"
1375 #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1376 # define USE_OPENSSL
1377 -# include <openssl/ssl.h>
1378 +# include <openssl/ssl.h>
1386 -#ifndef O_LARGEFILE
1387 -# define O_LARGEFILE 0
1392 # define SIZE_MAX SIZE_T_MAX
1395 /* solaris and NetBSD 1.3.x again */
1396 #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1397 -# define uint32_t u_int32_t
1398 +/* # define uint32_t u_int32_t */
1399 +typedef unsigned __int32 uint32_t;
1405 #include "settings.h"
1407 -typedef enum { T_CONFIG_UNSET,
1413 +typedef enum { T_CONFIG_UNSET,
1420 } config_values_type_t;
1422 -typedef enum { T_CONFIG_SCOPE_UNSET,
1423 - T_CONFIG_SCOPE_SERVER,
1424 +typedef enum { T_CONFIG_SCOPE_UNSET,
1425 + T_CONFIG_SCOPE_SERVER,
1426 T_CONFIG_SCOPE_CONNECTION
1427 } config_scope_type_t;
1434 config_values_type_t type;
1435 config_scope_type_t scope;
1437 @@ -118,18 +113,6 @@
1444 - struct sockaddr_in6 ipv6;
1446 - struct sockaddr_in ipv4;
1447 -#ifdef HAVE_SYS_UN_H
1448 - struct sockaddr_un un;
1450 - struct sockaddr plain;
1453 /* fcgi_response_header contains ... */
1454 #define HTTP_STATUS BV(0)
1455 #define HTTP_CONNECTION BV(1)
1456 @@ -142,40 +125,40 @@
1457 /* the request-line */
1465 http_method_t http_method;
1466 http_version_t http_version;
1469 buffer *request_line;
1472 /* strings to the header */
1473 buffer *http_host; /* not alloced */
1474 const char *http_range;
1475 const char *http_content_type;
1476 const char *http_if_modified_since;
1477 const char *http_if_none_match;
1484 size_t content_length; /* returned by strtoul() */
1487 /* internal representation */
1488 int accept_encoding;
1496 off_t content_length;
1497 - int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1499 + int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1506 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1507 } transfer_encoding;
1509 @@ -191,21 +174,21 @@
1512 buffer *basedir; /* path = "(basedir)(.*)" */
1515 buffer *doc_root; /* path = doc_root + rel_path */
1536 @@ -215,20 +198,20 @@
1540 - splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1542 + splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1544 buffer *dir_name; /* for building the dirname from the filename */
1546 splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1558 /* virtual-servers */
1559 buffer *document_root;
1560 buffer *server_name;
1563 buffer *dirlist_encoding;
1564 buffer *errorfile_prefix;
1567 unsigned short max_keep_alive_requests;
1568 unsigned short max_keep_alive_idle;
1569 unsigned short max_read_idle;
1570 @@ -244,16 +227,17 @@
1571 unsigned short use_xattr;
1572 unsigned short follow_symlink;
1573 unsigned short range_requests;
1579 unsigned short log_file_not_found;
1580 unsigned short log_request_header;
1581 unsigned short log_request_handling;
1582 unsigned short log_response_header;
1583 unsigned short log_condition_handling;
1586 + unsigned short log_condition_cache_handling;
1590 buffer *ssl_pemfile;
1591 buffer *ssl_ca_file;
1592 @@ -268,22 +252,22 @@
1594 unsigned short global_kbytes_per_second; /* */
1596 - off_t global_bytes_per_second_cnt;
1597 + off_t global_bytes_per_second_cnt;
1598 /* server-wide traffic-shaper
1601 * each context has the counter which is inited once
1602 - * a second by the global_kbytes_per_second config-var
1603 + * per second by the global_kbytes_per_second config-var
1605 * as soon as global_kbytes_per_second gets below 0
1606 * the connected conns are "offline" a little bit
1609 - * we somehow have to loose our "we are writable" signal
1610 + * we somehow have to lose our "we are writable" signal
1615 off_t *global_bytes_per_second_cnt_ptr; /* */
1621 @@ -291,18 +275,18 @@
1623 /* the order of the items should be the same as they are processed
1624 * read before write as we use this later */
1626 - CON_STATE_CONNECT,
1627 - CON_STATE_REQUEST_START,
1629 - CON_STATE_REQUEST_END,
1630 - CON_STATE_READ_POST,
1631 - CON_STATE_HANDLE_REQUEST,
1632 - CON_STATE_RESPONSE_START,
1634 - CON_STATE_RESPONSE_END,
1638 + CON_STATE_CONNECT,
1639 + CON_STATE_REQUEST_START,
1641 + CON_STATE_REQUEST_END,
1642 + CON_STATE_READ_POST,
1643 + CON_STATE_HANDLE_REQUEST,
1644 + CON_STATE_RESPONSE_START,
1646 + CON_STATE_RESPONSE_END,
1649 } connection_state_t;
1651 typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1652 @@ -315,91 +299,86 @@
1655 connection_state_t state;
1659 time_t read_idle_ts;
1660 time_t close_timeout_ts;
1661 time_t write_request_ts;
1664 time_t connection_start;
1665 time_t request_start;
1668 struct timeval start_tv;
1671 size_t request_count; /* number of requests handled in this connection */
1672 size_t loops_per_request; /* to catch endless loops in a single request
1675 * used by mod_rewrite, mod_fastcgi, ... and others
1676 * this is self-protection
1679 - int fd; /* the FD for this connection */
1680 - int fde_ndx; /* index for the fdevent-handler */
1683 int ndx; /* reverse mapping to server->connection[ndx] */
1690 - int keep_alive; /* only request.c can enable it, all other just disable */
1693 + int keep_alive; /* only request.c can enable it, all others just disable */
1699 chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1700 chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */
1701 chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1704 int traffic_limit_reached;
1707 off_t bytes_written; /* used by mod_accesslog, mod_rrd */
1708 off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1709 off_t bytes_read; /* used by mod_accesslog, mod_rrd */
1717 buffer *dst_addr_buf;
1720 buffer *parse_request;
1721 unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1726 - physical physical;
1727 + physical physical;
1734 buffer *authed_user;
1735 array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1745 connection_type mode;
1748 void **plugin_ctx; /* plugin connection specific config */
1751 specific_config conf; /* global connection specific config */
1752 cond_cache_t *cond_cache;
1755 buffer *server_name;
1759 buffer *error_handler;
1760 int error_handler_saved_status;
1761 int in_error_handler;
1764 void *srv_socket; /* reference to the server-socket (typecast to server_socket) */
1772 @@ -439,55 +418,63 @@
1777 + NETWORK_STATUS_UNSET,
1778 + NETWORK_STATUS_SUCCESS,
1779 + NETWORK_STATUS_FATAL_ERROR,
1780 + NETWORK_STATUS_CONNECTION_CLOSE,
1781 + NETWORK_STATUS_WAIT_FOR_EVENT,
1782 + NETWORK_STATUS_INTERRUPTED
1783 +} network_status_t;
1786 unsigned short port;
1789 - buffer *errorlog_file;
1790 - unsigned short errorlog_use_syslog;
1793 unsigned short dont_daemonize;
1802 buffer *event_handler;
1805 buffer *modules_dir;
1806 buffer *network_backend;
1808 array *upload_tempdirs;
1811 unsigned short max_worker;
1812 unsigned short max_fds;
1813 unsigned short max_conns;
1814 unsigned short max_request_size;
1817 unsigned short log_request_header_on_error;
1818 unsigned short log_state_handling;
1820 - enum { STAT_CACHE_ENGINE_UNSET,
1821 - STAT_CACHE_ENGINE_NONE,
1822 - STAT_CACHE_ENGINE_SIMPLE,
1823 - STAT_CACHE_ENGINE_FAM
1825 + enum { STAT_CACHE_ENGINE_UNSET,
1826 + STAT_CACHE_ENGINE_NONE,
1827 + STAT_CACHE_ENGINE_SIMPLE,
1828 + STAT_CACHE_ENGINE_FAM
1829 } stat_cache_engine;
1830 unsigned short enable_cores;
1832 + buffer *errorlog_file;
1833 + unsigned short errorlog_use_syslog;
1843 buffer *ssl_pemfile;
1844 buffer *ssl_ca_file;
1845 unsigned short use_ipv6;
1846 unsigned short is_ssl;
1855 @@ -495,37 +482,32 @@
1858 server_socket **ptr;
1863 } server_socket_array;
1865 typedef struct server {
1866 server_socket_array srv_sockets;
1868 - /* the errorlog */
1870 - enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1871 - buffer *errorlog_buf;
1874 fdevents *ev, *ev_ins;
1877 buffer_plugin plugins;
1891 int max_fds; /* max possible fds */
1892 int cur_fds; /* currently used fds */
1893 int want_fds; /* waiting fds */
1894 int sockets_disabled;
1900 @@ -533,13 +515,13 @@
1901 buffer *response_header;
1902 buffer *response_range;
1906 buffer *tmp_chunk_len;
1909 buffer *empty_string; /* is necessary for cond_match */
1911 buffer *cond_check_buf;
1916 inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
1917 @@ -547,59 +529,46 @@
1918 mtime_cache_type mtime_cache[FILE_CACHE_MAX];
1925 time_t last_generated_date_ts;
1926 time_t last_generated_debug_ts;
1930 buffer *ts_debug_str;
1931 buffer *ts_date_str;
1936 array *config_touched;
1939 array *config_context;
1940 specific_config **config_storage;
1943 server_config srvconf;
1946 int config_deprecated;
1950 connections *joblist;
1951 connections *fdwaitqueue;
1954 stat_cache *stat_cache;
1957 - * The status array can carry all the status information you want
1958 - * the key to the array is <module-prefix>.<name>
1959 - * and the values are counters
1962 - * fastcgi.backends = 10
1963 - * fastcgi.active-backends = 6
1964 - * fastcgi.backend.<key>.load = 24
1965 - * fastcgi.backend.<key>....
1967 - * fastcgi.backend.<key>.disconnects = ...
1971 fdevent_handler_t event_handler;
1973 - int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1974 - int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1975 + network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1976 + network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1978 - int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1979 - int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1980 + network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1981 + network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1991 --- ../lighttpd-1.4.11/src/bitset.c 2005-08-22 01:54:12.000000000 +0300
1992 +++ lighttpd-1.4.12/src/bitset.c 2006-07-18 13:03:40.000000000 +0300
1999 #define BITSET_BITS \
2000 ( CHAR_BIT * sizeof(size_t) )
2001 --- ../lighttpd-1.4.11/src/buffer.c 2006-01-13 00:00:45.000000000 +0200
2002 +++ lighttpd-1.4.12/src/buffer.c 2006-07-18 13:03:40.000000000 +0300
2013 buffer* buffer_init(void) {
2017 b = malloc(sizeof(*b));
2039 void buffer_free(buffer *b) {
2042 void buffer_reset(buffer *b) {
2046 /* limit don't reuse buffer larger than ... bytes */
2047 if (b->size > BUFFER_MAX_REUSE_SIZE) {
2060 - * allocate (if neccessary) enough space for 'size' bytes and
2062 + * allocate (if necessary) enough space for 'size' bytes and
2063 * set the 'used' counter to 0
2068 #define BUFFER_PIECE_SIZE 64
2070 int buffer_prepare_copy(buffer *b, size_t size) {
2073 - if ((0 == b->size) ||
2075 + if ((0 == b->size) ||
2077 if (b->size) free(b->ptr);
2082 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2084 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2085 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2088 b->ptr = malloc(b->size);
2096 - * increase the internal buffer (if neccessary) to append another 'size' byte
2098 + * increase the internal buffer (if necessary) to append another 'size' byte
2099 * ->used isn't changed
2104 int buffer_prepare_append(buffer *b, size_t size) {
2111 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2113 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2114 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2117 b->ptr = malloc(b->size);
2120 } else if (b->used + size > b->size) {
2123 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2125 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2126 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2129 b->ptr = realloc(b->ptr, b->size);
2134 int buffer_copy_string(buffer *b, const char *s) {
2138 if (!s || !b) return -1;
2140 s_len = strlen(s) + 1;
2141 @@ -136,26 +136,26 @@
2143 int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2144 if (!s || !b) return -1;
2146 - /* removed optimization as we have to keep the empty string
2148 + /* removed optimization as we have to keep the empty string
2149 * in some cases for the config handling
2152 * url.access-deny = ( "" )
2154 if (s_len == 0) return 0;
2157 buffer_prepare_copy(b, s_len + 1);
2160 memcpy(b->ptr, s, s_len);
2161 b->ptr[s_len] = '\0';
2162 b->used = s_len + 1;
2168 int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2169 if (!src) return -1;
2172 if (src->used == 0) {
2175 @@ -201,10 +201,10 @@
2178 * append a string to the end of the buffer
2180 - * the resulting buffer is terminated with a '\0'
2181 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2184 + * the resulting buffer is terminated with a '\0'
2185 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2188 * @param s the string
2189 * @param s_len size of the string (without the terminating \0)
2191 int buffer_append_string_buffer(buffer *b, const buffer *src) {
2192 if (!src) return -1;
2193 if (src->used == 0) return 0;
2196 return buffer_append_string_len(b, src->ptr, src->used - 1);
2201 int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2202 if (!s || !b) return -1;
2208 return buffer_append_memory(b, s, s_len);
2211 @@ -402,46 +402,115 @@
2217 + * init the ptr buffer
2220 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2222 + buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2229 + * free the buffer_array
2232 +void buffer_ptr_free(buffer_ptr *l)
2235 + buffer_ptr_clear(l);
2240 +void buffer_ptr_clear(buffer_ptr *l)
2242 + assert(NULL != l);
2244 + if (l->free && l->used) {
2246 + for (i = 0; i < l->used; i ++) {
2247 + l->free(l->ptr[i]);
2259 +void buffer_ptr_append(buffer_ptr* l, void *item)
2261 + assert(NULL != l);
2262 + if (l->ptr == NULL) {
2264 + l->ptr = (void **)malloc(sizeof(void *) * l->size);
2266 + else if (l->used == l->size) {
2268 + l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2270 + l->ptr[l->used++] = item;
2273 +void *buffer_ptr_pop(buffer_ptr* l)
2275 + assert(NULL != l && l->used > 0);
2276 + return l->ptr[--l->used];
2279 +void *buffer_ptr_top(buffer_ptr* l)
2281 + assert(NULL != l && l->used > 0);
2282 + return l->ptr[l->used-1];
2290 buffer_array* buffer_array_init(void) {
2294 b = malloc(sizeof(*b));
2306 void buffer_array_reset(buffer_array *b) {
2313 /* if they are too large, reduce them */
2314 for (i = 0; i < b->used; i++) {
2315 buffer_reset(b->ptr[i]);
2324 - * free the buffer_array
2326 + * free the buffer_array
2330 void buffer_array_free(buffer_array *b) {
2335 for (i = 0; i < b->size; i++) {
2336 if (b->ptr[i]) buffer_free(b->ptr[i]);
2340 buffer *buffer_array_append_get_buffer(buffer_array *b) {
2346 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2347 @@ -467,13 +536,13 @@
2353 if (b->ptr[b->used] == NULL) {
2354 b->ptr[b->used] = buffer_init();
2358 b->ptr[b->used]->used = 0;
2361 return b->ptr[b->used++];
2364 @@ -482,23 +551,23 @@
2366 if (len == 0) return NULL;
2367 if (needle == NULL) return NULL;
2370 if (b->used < len) return NULL;
2373 for(i = 0; i < b->used - len; i++) {
2374 if (0 == memcmp(b->ptr + i, needle, len)) {
2383 buffer *buffer_init_string(const char *str) {
2384 buffer *b = buffer_init();
2387 buffer_copy_string(b, str);
2397 - * check if two buffer contain the same data
2399 + * check if two buffers contain the same data
2401 * HISTORY: this function was pretty much optimized, but didn't handled
2402 * alignment properly.
2404 @@ -517,105 +586,105 @@
2405 if (a->used != b->used) return 0;
2406 if (a->used == 0) return 1;
2408 - return (0 == strcmp(a->ptr, b->ptr));
2409 + return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2412 int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2420 return buffer_is_equal(a, &b);
2423 /* simple-assumption:
2425 - * most parts are equal and doing a case conversion needs time
2428 + * most parts are equal and doing a case conversion takes time
2431 int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2432 size_t ndx = 0, max_ndx;
2434 size_t mask = sizeof(*al) - 1;
2440 - /* is the alignment correct ? */
2442 + /* is the alignment correct? */
2443 if ( ((size_t)al & mask) == 0 &&
2444 ((size_t)bl & mask) == 0 ) {
2447 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2450 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2451 if (*al != *bl) break;
2465 max_ndx = ((a_len < b_len) ? a_len : b_len);
2468 for (; ndx < max_ndx; ndx++) {
2469 char a1 = *a++, b1 = *b++;
2473 if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2475 else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2477 if ((a1 - b1) != 0) return (a1 - b1);
2489 * check if the rightmost bytes of the string are equal.
2496 int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2497 /* no, len -> equal */
2498 if (len == 0) return 1;
2501 /* len > 0, but empty buffers -> not equal */
2502 if (b1->used == 0 || b2->used == 0) return 0;
2505 /* buffers too small -> not equal */
2506 - if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2508 - if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2509 + if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2511 + if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2512 b2->ptr + b2->used - 1 - len, len)) {
2520 int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2525 if (in_len * 2 < in_len) return -1;
2528 buffer_prepare_copy(b, in_len * 2 + 1);
2531 for (i = 0; i < in_len; i++) {
2532 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2533 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2535 b->ptr[b->used++] = '\0';
2542 0 1 2 3 4 5 6 7 8 9 A B C D E F
2544 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2545 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2546 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2547 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, /* 20 - 2F space " # $ % & ' + , / */
2548 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
2549 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2551 0 1 2 3 4 5 6 7 8 9 A B C D E F
2553 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2554 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2555 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2556 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, /* 20 - 2F space " # $ % & ' + , / */
2557 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
2558 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2560 0 1 2 3 4 5 6 7 8 9 A B C D E F
2562 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2563 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2564 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2565 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
2566 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
2567 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2569 0 1 2 3 4 5 6 7 8 9 A B C D E F
2571 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2572 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2573 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2574 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
2575 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
2576 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2577 @@ -712,12 +781,12 @@
2578 0 1 2 3 4 5 6 7 8 9 A B C D E F
2580 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2581 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2582 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
2583 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
2584 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
2585 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
2586 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
2587 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2588 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
2589 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
2590 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
2591 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
2592 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
2593 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 - 7F */
2594 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
2595 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
2596 @@ -734,13 +803,12 @@
2597 unsigned char *ds, *d;
2599 const char *map = NULL;
2602 if (!s || !b) return -1;
2604 - if (b->ptr[b->used - 1] != '\0') {
2608 + if (b->used == 0) return -1;
2610 + if (b->ptr[b->used - 1] != '\0') return -1;
2612 if (s_len == 0) return 0;
2615 @@ -760,12 +828,12 @@
2616 map = encoded_chars_hex;
2618 case ENCODING_UNSET:
2620 + return buffer_append_string_len(b, s, s_len);
2623 assert(map != NULL);
2625 - /* count to-be-encoded-characters */
2627 + /* count to-be-encoded characters */
2628 for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2637 buffer_prepare_append(b, d_len);
2640 for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2643 @@ -820,16 +888,16 @@
2647 - /* terminate buffer and calculate new length */
2648 + /* terminate buffer and calculate new length */
2649 b->ptr[b->used + d_len - 1] = '\0';
2658 -/* decodes url-special-chars inplace.
2659 +/* decodes url-special chars in-place.
2660 * replaces non-printable characters with '_'
2663 @@ -854,10 +922,10 @@
2664 low = hex2int(*(src + 2));
2666 high = (high << 4) | low;
2668 - /* map control-characters out */
2670 + /* map out control characters */
2671 if (high < 32 || high == 127) high = '_';
2678 * /abc/./xyz gets /abc/xyz
2679 * /abc//xyz gets /abc/xyz
2681 - * NOTE: src and dest can point to the same buffer, in which case,
2682 + * NOTE: src and dest can point to the same buffer, in which case
2683 * the operation is performed in-place.
2686 @@ -979,7 +1047,7 @@
2688 int light_isxdigit(int c) {
2689 if (light_isdigit(c)) return 1;
2693 return (c >= 'a' && c <= 'f');
2695 @@ -993,31 +1061,56 @@
2696 return light_isdigit(c) || light_isalpha(c);
2699 +#undef BUFFER_CTYPE_FUNC
2700 +#define BUFFER_CTYPE_FUNC(type) \
2701 + int buffer_is##type(buffer *b) { \
2703 + if (b->used < 2) return 0; \
2705 + len = b->used - 1; \
2706 + /* c-string only */ \
2707 + if (b->ptr[len] != '\0') { \
2710 + /* check on the whole string */ \
2711 + for (i = 0; i < len; i ++) { \
2712 + if (!light_is##type(b->ptr[i])) { \
2719 +BUFFER_CTYPE_FUNC(digit)
2720 +BUFFER_CTYPE_FUNC(xdigit)
2721 +BUFFER_CTYPE_FUNC(alpha)
2722 +BUFFER_CTYPE_FUNC(alnum)
2724 int buffer_to_lower(buffer *b) {
2728 if (b->used == 0) return 0;
2731 for (c = b->ptr; *c; c++) {
2732 if (*c >= 'A' && *c <= 'Z') {
2742 int buffer_to_upper(buffer *b) {
2746 if (b->used == 0) return 0;
2749 for (c = b->ptr; *c; c++) {
2750 if (*c >= 'a' && *c <= 'z') {
2758 --- ../lighttpd-1.4.11/src/buffer.h 2006-01-13 00:00:45.000000000 +0200
2759 +++ lighttpd-1.4.12/src/buffer.h 2006-07-18 13:03:40.000000000 +0300
2770 +typedef void (*buffer_ptr_free_t)(void *p);
2776 + buffer_ptr_free_t free;
2790 - size_t offset; /* input-pointer */
2792 - size_t used; /* output-pointer */
2794 + size_t offset; /* input pointer */
2796 + size_t used; /* output pointer */
2800 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2801 +void buffer_ptr_free(buffer_ptr *b);
2802 +void buffer_ptr_clear(buffer_ptr *b);
2803 +void buffer_ptr_append(buffer_ptr *b, void *item);
2804 +void *buffer_ptr_pop(buffer_ptr *b);
2805 +void *buffer_ptr_top(buffer_ptr *b);
2807 buffer_array* buffer_array_init(void);
2808 void buffer_array_free(buffer_array *b);
2809 void buffer_array_reset(buffer_array *b);
2811 buffer* buffer_init_string(const char *str);
2812 void buffer_free(buffer *b);
2813 void buffer_reset(buffer *b);
2816 int buffer_prepare_copy(buffer *b, size_t size);
2817 int buffer_prepare_append(buffer *b, size_t size);
2823 - ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2824 - ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2825 - ENCODING_HTML, /* & becomes & and so on */
2826 + ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2827 + ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2828 + ENCODING_HTML, /* "&" becomes "&" and so on */
2829 ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2830 ENCODING_HEX /* encode string as hex */
2831 } buffer_encoding_t;
2832 @@ -111,20 +127,23 @@
2833 int light_isalpha(int c);
2834 int light_isalnum(int c);
2836 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2837 +BUFFER_CTYPE_FUNC(digit)
2838 +BUFFER_CTYPE_FUNC(xdigit)
2839 +BUFFER_CTYPE_FUNC(alpha)
2840 +BUFFER_CTYPE_FUNC(alnum)
2842 +#define BUF_STR(x) x->ptr
2843 #define BUFFER_APPEND_STRING_CONST(x, y) \
2844 buffer_append_string_len(x, y, sizeof(y) - 1)
2846 #define BUFFER_COPY_STRING_CONST(x, y) \
2847 buffer_copy_string_len(x, y, sizeof(y) - 1)
2849 -#define BUFFER_APPEND_SLASH(x) \
2850 - if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2852 #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2853 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2854 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2857 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2859 #define UNUSED(x) ( (void)(x) )
2862 --- ../lighttpd-1.4.11/src/chunk.c 2005-11-18 15:18:19.000000000 +0200
2863 +++ lighttpd-1.4.12/src/chunk.c 2006-07-18 13:03:40.000000000 +0300
2866 * the network chunk-API
2873 #include <sys/types.h>
2874 #include <sys/stat.h>
2875 -#include <sys/mman.h>
2879 -#include <unistd.h>
2887 +#include "sys-mmap.h"
2888 +#include "sys-files.h"
2890 chunkqueue *chunkqueue_init(void) {
2894 cq = calloc(1, sizeof(*cq));
2907 static chunk *chunk_init(void) {
2911 c = calloc(1, sizeof(*c));
2914 c->mem = buffer_init();
2915 c->file.name = buffer_init();
2917 c->file.mmap.start = MAP_FAILED;
2924 static void chunk_free(chunk *c) {
2928 buffer_free(c->mem);
2929 buffer_free(c->file.name);
2933 static void chunk_reset(chunk *c) {
2937 buffer_reset(c->mem);
2939 if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
2940 unlink(c->file.name->ptr);
2944 buffer_reset(c->file.name);
2946 if (c->file.fd != -1) {
2949 void chunkqueue_free(chunkqueue *cq) {
2956 for (c = cq->first; c; ) {
2963 for (c = cq->unused; c; ) {
2973 static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
2976 - /* check if we have a unused chunk */
2978 + /* check if we have an unused chunk */
2982 @@ -109,18 +110,18 @@
2984 cq->unused_chunks--;
2991 static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
2992 c->next = cq->first;
2996 if (cq->last == NULL) {
3004 @@ -129,19 +130,19 @@
3010 if (cq->first == NULL) {
3018 void chunkqueue_reset(chunkqueue *cq) {
3020 /* move everything to the unused queue */
3022 - /* mark all read written */
3024 + /* mark all read written */
3025 for (c = cq->first; c; c = c->next) {
3030 c->offset = c->file.length;
3037 @@ -162,93 +163,93 @@
3039 int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3043 if (len == 0) return 0;
3046 c = chunkqueue_get_unused_chunk(cq);
3049 c->type = FILE_CHUNK;
3052 buffer_copy_string_buffer(c->file.name, fn);
3053 c->file.start = offset;
3054 c->file.length = len;
3058 chunkqueue_append_chunk(cq, c);
3064 int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3068 if (mem->used == 0) return 0;
3071 c = chunkqueue_get_unused_chunk(cq);
3072 c->type = MEM_CHUNK;
3074 buffer_copy_string_buffer(c->mem, mem);
3077 chunkqueue_append_chunk(cq, c);
3083 int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3087 if (mem->used == 0) return 0;
3090 c = chunkqueue_get_unused_chunk(cq);
3091 c->type = MEM_CHUNK;
3093 buffer_copy_string_buffer(c->mem, mem);
3096 chunkqueue_prepend_chunk(cq, c);
3102 int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3106 if (len == 0) return 0;
3109 c = chunkqueue_get_unused_chunk(cq);
3110 c->type = MEM_CHUNK;
3112 buffer_copy_string_len(c->mem, mem, len - 1);
3115 chunkqueue_append_chunk(cq, c);
3121 buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3125 c = chunkqueue_get_unused_chunk(cq);
3128 c->type = MEM_CHUNK;
3130 buffer_reset(c->mem);
3133 chunkqueue_prepend_chunk(cq, c);
3139 buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3143 c = chunkqueue_get_unused_chunk(cq);
3146 c->type = MEM_CHUNK;
3148 buffer_reset(c->mem);
3151 chunkqueue_append_chunk(cq, c);
3158 chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3160 buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3163 c = chunkqueue_get_unused_chunk(cq);
3165 c->type = FILE_CHUNK;
3166 @@ -273,12 +274,12 @@
3169 /* we have several tempdirs, only if all of them fail we jump out */
3172 for (i = 0; i < cq->tempdirs->used; i++) {
3173 data_string *ds = (data_string *)cq->tempdirs->data[i];
3175 buffer_copy_string_buffer(template, ds->value);
3176 - BUFFER_APPEND_SLASH(template);
3177 + PATHNAME_APPEND_SLASH(template);
3178 BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3180 if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3182 chunkqueue_append_chunk(cq, c);
3184 buffer_free(template);
3191 off_t chunkqueue_length(chunkqueue *cq) {
3196 for (c = cq->first; c; c = c->next) {
3199 @@ -321,14 +322,14 @@
3208 off_t chunkqueue_written(chunkqueue *cq) {
3213 for (c = cq->first; c; c = c->next) {
3225 @@ -355,12 +356,13 @@
3229 + if (c->mem->used == 0) is_finished = 1;
3230 if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3233 - if (c->offset == c->file.length) is_finished = 1;
3234 + if (c->offset == c->file.length) is_finished = 1;
3241 @@ -383,3 +385,50 @@
3246 +void chunkqueue_print(chunkqueue *cq) {
3249 + for (c = cq->first; c; c = c->next) {
3250 + fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3252 + fprintf(stderr, "\r\n");
3257 + * remove the last chunk if it is empty
3260 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3262 + if (!cq->last) return;
3263 + if (!cq->first) return;
3265 + if (cq->first == cq->last) {
3268 + if (c->type != MEM_CHUNK) return;
3269 + if (c->mem->used == 0) {
3271 + cq->first = cq->last = NULL;
3276 + for (c = cq->first; c->next; c = c->next) {
3277 + if (c->type != MEM_CHUNK) continue;
3278 + if (c->mem->used != 0) continue;
3280 + if (c->next == cq->last) {
3283 + chunk_free(c->next);
3292 --- ../lighttpd-1.4.11/src/chunk.h 2005-11-01 09:32:21.000000000 +0200
3293 +++ lighttpd-1.4.12/src/chunk.h 2006-07-18 13:03:40.000000000 +0300
3296 typedef struct chunk {
3297 enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3300 buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3304 off_t length; /* octets to send from the starting offset */
3309 char *start; /* the start pointer of the mmap'ed area */
3310 size_t length; /* size of the mmap'ed area */
3311 - off_t offset; /* start is <n> octet away from the start of the file */
3312 + off_t offset; /* start is <n> octets away from the start of the file */
3315 - int is_temp; /* file is temporary and will be deleted if on cleanup */
3316 + int is_temp; /* file is temporary and will be deleted on cleanup */
3319 - off_t offset; /* octets sent from this chunk
3320 - the size of the chunk is either
3322 + off_t offset; /* octets sent from this chunk
3323 + the size of the chunk is either
3324 - mem-chunk: mem->used - 1
3325 - file-chunk: file.length
3338 size_t unused_chunks;
3341 buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3342 buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3343 chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3344 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3346 int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3350 int chunkqueue_is_empty(chunkqueue *c);
3352 +void chunkqueue_print(chunkqueue *cq);
3355 --- ../lighttpd-1.4.11/src/configfile-glue.c 2006-03-03 20:14:56.000000000 +0200
3356 +++ lighttpd-1.4.12/src/configfile-glue.c 2006-07-16 00:26:03.000000000 +0300
3364 * are the external interface of lighttpd. The functions
3365 * are used by the server itself and the plugins.
3367 - * The main-goal is to have a small library in the end
3368 - * which is linked against both and which will define
3369 + * The main-goal is to have a small library in the end
3370 + * which is linked against both and which will define
3371 * the interface itself in the end.
3378 int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3383 for (i = 0; cv[i].key; i++) {
3386 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3394 switch (cv[i].type) {
3395 case T_CONFIG_ARRAY:
3396 if (du->type == TYPE_ARRAY) {
3398 data_array *da = (data_array *)du;
3401 for (j = 0; j < da->value->used; j++) {
3402 if (da->value->data[j]->type == TYPE_STRING) {
3403 data_string *ds = data_string_init();
3406 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3407 if (!da->is_index_key) {
3408 /* the id's were generated automaticly, as we copy now we might have to renumber them
3409 - * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3410 + * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3411 * before mod_fastcgi and friends */
3412 buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3416 array_insert_unique(cv[i].destination, (data_unset *)ds);
3418 - log_error_write(srv, __FILE__, __LINE__, "sssd",
3419 - "the key of and array can only be a string or a integer, variable:",
3420 - cv[i].key, "type:", da->value->data[j]->type);
3422 + log_error_write(srv, __FILE__, __LINE__, "sssd",
3423 + "the key of and array can only be a string or a integer, variable:",
3424 + cv[i].key, "type:", da->value->data[j]->type);
3430 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3436 case T_CONFIG_STRING:
3437 if (du->type == TYPE_STRING) {
3438 data_string *ds = (data_string *)du;
3441 buffer_copy_string_buffer(cv[i].destination, ds->value);
3442 + } else if (du->type == TYPE_INTEGER) {
3443 + data_integer *di = (data_integer *)du;
3445 + buffer_copy_long(cv[i].destination, di->value);
3447 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3455 case TYPE_INTEGER: {
3456 data_integer *di = (data_integer *)du;
3459 *((unsigned short *)(cv[i].destination)) = di->value;
3463 data_string *ds = (data_string *)du;
3466 + if (buffer_isdigit(ds->value)) {
3467 + *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3471 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3477 @@ -100,19 +110,19 @@
3478 case T_CONFIG_BOOLEAN:
3479 if (du->type == TYPE_STRING) {
3480 data_string *ds = (data_string *)du;
3483 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3484 *((unsigned short *)(cv[i].destination)) = 1;
3485 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3486 *((unsigned short *)(cv[i].destination)) = 0;
3488 log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3494 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3502 case T_CONFIG_DEPRECATED:
3503 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3506 srv->config_deprecated = 1;
3512 @@ -133,25 +143,25 @@
3513 int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3518 for (i = 0; cv[i].key; i++) {
3519 data_string *touched;
3522 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3531 touched = data_string_init();
3534 buffer_copy_string(touched->value, "");
3535 buffer_copy_string_buffer(touched->key, du->key);
3538 array_insert_unique(srv->config_touched, (data_unset *)touched);
3542 return config_insert_values_internal(srv, ca, cv);
3545 @@ -191,25 +201,25 @@
3548 /* pass the rules */
3552 case COMP_HTTP_HOST: {
3553 char *ck_colon = NULL, *val_colon = NULL;
3556 if (!buffer_is_empty(con->uri.authority)) {
3561 * append server-port to the HTTP_POST if necessary
3565 l = con->uri.authority;
3569 case CONFIG_COND_NE:
3570 case CONFIG_COND_EQ:
3571 ck_colon = strchr(dc->string->ptr, ':');
3572 val_colon = strchr(l->ptr, ':');
3575 if (ck_colon == val_colon) {
3576 /* nothing to do with it */
3578 @@ -230,21 +240,21 @@
3583 + l = srv->empty_string;
3587 case COMP_HTTP_REMOTEIP: {
3589 - /* handle remoteip limitations
3591 + /* handle remoteip limitations
3593 * "10.0.0.1" is provided for all comparisions
3596 * only for == and != we support
3603 if ((dc->cond == CONFIG_COND_EQ ||
3604 dc->cond == CONFIG_COND_NE) &&
3605 (con->dst_addr.plain.sa_family == AF_INET) &&
3606 @@ -253,41 +263,48 @@
3609 struct in_addr val_inp;
3612 + if (con->conf.log_condition_handling) {
3613 + l = srv->empty_string;
3615 + log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
3616 + "(", l, ") compare to", dc->string);
3619 if (*(nm_slash+1) == '\0') {
3620 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3623 return COND_RESULT_FALSE;
3627 nm_bits = strtol(nm_slash + 1, &err, 10);
3631 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3634 return COND_RESULT_FALSE;
3638 /* take IP convert to the native */
3639 buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3642 if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3643 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3646 return COND_RESULT_FALSE;
3650 if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3651 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3654 return COND_RESULT_FALSE;
3660 nm = htonl(~((1 << (32 - nm_bits)) - 1));
3663 if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3664 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3668 case COMP_HTTP_REFERER: {
3672 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3677 return COND_RESULT_FALSE;
3682 if (con->conf.log_condition_handling) {
3683 log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
3684 @@ -346,10 +363,10 @@
3686 return COND_RESULT_FALSE;
3690 if (con->conf.log_condition_handling) {
3691 log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
3692 - "(", l, ") compare to ", dc->string);
3693 + "(", l, ") compare to", dc->string);
3696 case CONFIG_COND_NE:
3697 @@ -365,13 +382,13 @@
3698 case CONFIG_COND_MATCH: {
3699 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3704 #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3706 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3707 cache->matches, elementsof(cache->matches));
3710 cache->patterncount = n;
3712 cache->comp_value = l;
3719 return COND_RESULT_FALSE;
3723 cond_cache_t *caches = con->cond_cache;
3725 if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3726 + if (con->conf.log_condition_handling) {
3727 + log_error_write(srv, __FILE__, __LINE__, "sds", "=== start of", dc->context_ndx, "condition block ===");
3729 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3732 @@ -409,11 +429,11 @@
3734 if (con->conf.log_condition_handling) {
3735 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3736 - "(uncached) result:",
3738 caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3741 - if (con->conf.log_condition_handling) {
3742 + if (con->conf.log_condition_cache_handling) {
3743 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3745 caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3749 int config_check_cond(server *srv, connection *con, data_config *dc) {
3750 - if (con->conf.log_condition_handling) {
3751 - log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
3753 return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3756 @@ -443,3 +460,85 @@
3760 +/* return <0 on error
3761 + * return 0-x if matched (and replaced)
3763 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3767 + pcre_extra *extra;
3768 + const char *pattern;
3769 + size_t pattern_len;
3772 + pcre_keyvalue *kv;
3776 + for (i = 0; i < kvb->used; i++) {
3780 + extra = kv->key_extra;
3781 + pattern = kv->value->ptr;
3782 + pattern_len = kv->value->used - 1;
3784 + if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3785 + if (n != PCRE_ERROR_NOMATCH) {
3789 + const char **list;
3790 + size_t start, end;
3794 + pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3796 + /* search for $[0-9] */
3798 + buffer_reset(result);
3800 + start = 0; end = pattern_len;
3801 + for (k = 0; k < pattern_len; k++) {
3802 + if ((pattern[k] == '$' || pattern[k] == '%') &&
3803 + isdigit((unsigned char)pattern[k + 1])) {
3806 + size_t num = pattern[k + 1] - '0';
3810 + buffer_append_string_len(result, pattern + start, end - start);
3812 + if (pattern[k] == '$') {
3813 + /* n is always > 0 */
3814 + if (num < (size_t)n) {
3815 + buffer_append_string(result, list[num]);
3818 + config_append_cond_match_buffer(con, context, result, num);
3826 + buffer_append_string_len(result, pattern + start, pattern_len - start);
3834 + return PCRE_ERROR_NOMATCH;
3842 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3843 +++ lighttpd-1.4.12/src/configfile.c 2006-07-18 13:03:40.000000000 +0300
3848 -#include <unistd.h>
3857 -#include "license.h"
3860 #include "configparser.h"
3861 #include "configfile.h"
3862 #include "proc_open.h"
3864 +#include "sys-files.h"
3865 +#include "sys-process.h"
3869 +#define PATH_MAX 64
3872 static int config_insert(server *srv) {
3875 buffer *stat_cache_string;
3877 - config_values_t cv[] = {
3879 + config_values_t cv[] = {
3880 { "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
3881 { "server.errorlog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 */
3882 { "server.errorfile-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 */
3884 { "server.tag", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
3885 { "server.use-ipv6", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
3886 { "server.modules", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 9 */
3889 { "server.event-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 */
3890 { "server.pid-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 */
3891 { "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
3893 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
3894 { "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
3895 { "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
3898 { "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
3899 { "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
3900 { "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
3902 { "mimetype.use-xattr", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
3903 { "mimetype.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 28 */
3904 { "ssl.pemfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 29 */
3907 { "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 30 */
3910 { "debug.log-file-not-found", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 31 */
3911 { "debug.log-request-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 32 */
3912 { "debug.log-response-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 33 */
3913 { "debug.log-request-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 34 */
3916 { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */
3917 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
3918 { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
3919 { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */
3922 { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 39 */
3923 { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
3924 { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
3926 { "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
3927 { "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
3928 { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
3930 + { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 46 */
3932 { "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3933 { "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3934 { "server.virtual-root", "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3936 { "server.groupid", "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3937 { "server.use-keep-alive", "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3938 { "server.force-lower-case-files", "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3941 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
3947 cv[0].destination = srv->srvconf.bindhost;
3948 cv[1].destination = srv->srvconf.errorlog_file;
3949 @@ -102,33 +105,33 @@
3950 cv[4].destination = srv->srvconf.username;
3951 cv[5].destination = srv->srvconf.groupname;
3952 cv[6].destination = &(srv->srvconf.port);
3955 cv[9].destination = srv->srvconf.modules;
3956 cv[10].destination = srv->srvconf.event_handler;
3957 cv[11].destination = srv->srvconf.pid_file;
3960 cv[13].destination = &(srv->srvconf.max_worker);
3961 cv[23].destination = &(srv->srvconf.max_fds);
3962 cv[36].destination = &(srv->srvconf.log_request_header_on_error);
3963 cv[37].destination = &(srv->srvconf.log_state_handling);
3966 cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
3969 stat_cache_string = buffer_init();
3970 cv[41].destination = stat_cache_string;
3971 cv[43].destination = srv->srvconf.network_backend;
3972 cv[44].destination = srv->srvconf.upload_tempdirs;
3973 cv[45].destination = &(srv->srvconf.enable_cores);
3976 cv[42].destination = &(srv->srvconf.max_conns);
3977 cv[12].destination = &(srv->srvconf.max_request_size);
3978 srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
3980 assert(srv->config_storage);
3983 for (i = 0; i < srv->config_context->used; i++) {
3987 s = calloc(1, sizeof(specific_config));
3989 s->document_root = buffer_init();
3990 @@ -154,17 +157,18 @@
3991 s->global_kbytes_per_second = 0;
3992 s->global_bytes_per_second_cnt = 0;
3993 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
3996 cv[2].destination = s->errorfile_prefix;
3999 cv[7].destination = s->server_tag;
4000 cv[8].destination = &(s->use_ipv6);
4006 cv[14].destination = s->document_root;
4007 cv[15].destination = &(s->force_lowercase_filenames);
4008 cv[16].destination = &(s->log_condition_handling);
4009 + cv[46].destination = &(s->log_condition_cache_handling);
4010 cv[17].destination = &(s->max_keep_alive_requests);
4011 cv[18].destination = s->server_name;
4012 cv[19].destination = &(s->max_keep_alive_idle);
4013 @@ -179,23 +183,23 @@
4014 cv[28].destination = s->mimetypes;
4015 cv[29].destination = s->ssl_pemfile;
4016 cv[30].destination = &(s->is_ssl);
4019 cv[31].destination = &(s->log_file_not_found);
4020 cv[32].destination = &(s->log_request_handling);
4021 cv[33].destination = &(s->log_response_header);
4022 cv[34].destination = &(s->log_request_header);
4025 cv[35].destination = &(s->allow_http11);
4026 cv[38].destination = s->ssl_ca_file;
4027 cv[40].destination = &(s->range_requests);
4030 srv->config_storage[i] = s;
4033 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4039 if (buffer_is_empty(stat_cache_string)) {
4040 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4041 } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4042 @@ -205,22 +209,22 @@
4043 } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4044 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4046 - log_error_write(srv, __FILE__, __LINE__, "sb",
4047 + log_error_write(srv, __FILE__, __LINE__, "sb",
4048 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4049 ret = HANDLER_ERROR;
4053 buffer_free(stat_cache_string);
4062 -#define PATCH(x) con->conf.x = s->x
4064 + con->conf.x = s->x
4065 int config_setup_connection(server *srv, connection *con) {
4066 specific_config *s = srv->config_storage[0];
4069 PATCH(allow_http11);
4071 PATCH(document_root);
4072 @@ -236,20 +240,21 @@
4073 PATCH(kbytes_per_second);
4074 PATCH(global_kbytes_per_second);
4075 PATCH(global_bytes_per_second_cnt);
4078 con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4079 buffer_copy_string_buffer(con->server_name, s->server_name);
4082 PATCH(log_request_header);
4083 PATCH(log_response_header);
4084 PATCH(log_request_handling);
4085 PATCH(log_condition_handling);
4086 + PATCH(log_condition_cache_handling);
4087 PATCH(log_file_not_found);
4090 PATCH(range_requests);
4091 PATCH(force_lowercase_filenames);
4098 @@ -257,22 +262,22 @@
4100 int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4104 /* skip the first, the global context */
4105 for (i = 1; i < srv->config_context->used; i++) {
4106 data_config *dc = (data_config *)srv->config_context->data[i];
4107 specific_config *s = srv->config_storage[i];
4111 if (comp != dc->comp) continue;
4114 /* condition didn't match */
4115 if (!config_check_cond(srv, con, dc)) continue;
4119 for (j = 0; j < dc->value->used; j++) {
4120 data_unset *du = dc->value->data[j];
4123 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4124 PATCH(document_root);
4125 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4126 @@ -315,11 +320,13 @@
4127 PATCH(log_response_header);
4128 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4129 PATCH(log_condition_handling);
4130 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4131 + PATCH(log_condition_cache_handling);
4132 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4133 PATCH(log_file_not_found);
4134 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4135 PATCH(allow_http11);
4136 - } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4137 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4138 PATCH(force_lowercase_filenames);
4139 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4140 PATCH(global_kbytes_per_second);
4150 @@ -336,15 +343,15 @@
4156 const buffer *source;
4172 if (0 != stream_open(&(t->s), t->file)) {
4173 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4174 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4175 "opening configfile ", t->file, "failed:", strerror(errno));
4176 buffer_free(t->file);
4179 t->size = t->s.size;
4188 static int config_skip_comment(tokenizer_t *t) {
4190 assert(t->input[t->offset] == '#');
4191 - for (i = 1; t->input[t->offset + i] &&
4192 + for (i = 1; t->input[t->offset + i] &&
4193 (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4196 @@ -411,44 +418,44 @@
4197 static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4202 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4203 char c = t->input[t->offset];
4204 const char *start = NULL;
4211 if (t->input[t->offset + 1] == '>') {
4215 buffer_copy_string(token, "=>");
4218 tid = TK_ARRAY_ASSIGN;
4220 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4221 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4222 "source:", t->source,
4223 - "line:", t->line, "pos:", t->line_pos,
4224 + "line:", t->line, "pos:", t->line_pos,
4225 "use => for assignments in arrays");
4228 } else if (t->in_cond) {
4229 if (t->input[t->offset + 1] == '=') {
4233 buffer_copy_string(token, "==");
4237 } else if (t->input[t->offset + 1] == '~') {
4241 buffer_copy_string(token, "=~");
4246 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4247 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4248 "source:", t->source,
4249 - "line:", t->line, "pos:", t->line_pos,
4250 + "line:", t->line, "pos:", t->line_pos,
4251 "only =~ and == are allowed in the condition");
4254 @@ -456,51 +463,51 @@
4256 } else if (t->in_key) {
4260 buffer_copy_string_len(token, t->input + t->offset, 1);
4266 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4267 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4268 "source:", t->source,
4269 - "line:", t->line, "pos:", t->line_pos,
4270 + "line:", t->line, "pos:", t->line_pos,
4271 "unexpected equal-sign: =");
4280 if (t->input[t->offset + 1] == '=') {
4284 buffer_copy_string(token, "!=");
4288 } else if (t->input[t->offset + 1] == '~') {
4292 buffer_copy_string(token, "!~");
4297 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4298 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4299 "source:", t->source,
4300 - "line:", t->line, "pos:", t->line_pos,
4301 + "line:", t->line, "pos:", t->line_pos,
4302 "only !~ and != are allowed in the condition");
4308 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4309 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4310 "source:", t->source,
4311 - "line:", t->line, "pos:", t->line_pos,
4312 + "line:", t->line, "pos:", t->line_pos,
4313 "unexpected exclamation-marks: !");
4321 @@ -546,10 +553,10 @@
4323 if (t->in_brace > 0) {
4327 buffer_copy_string(token, "(COMMA)");
4334 @@ -557,70 +564,70 @@
4335 /* search for the terminating " */
4336 start = t->input + t->offset + 1;
4337 buffer_copy_string(token, "");
4340 for (i = 1; t->input[t->offset + i]; i++) {
4341 if (t->input[t->offset + i] == '\\' &&
4342 t->input[t->offset + i + 1] == '"') {
4345 buffer_append_string_len(token, start, t->input + t->offset + i - start);
4348 start = t->input + t->offset + i + 1;
4359 if (t->input[t->offset + i] == '"') {
4363 buffer_append_string_len(token, start, t->input + t->offset + i - start);
4370 if (t->input[t->offset + i] == '\0') {
4373 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4375 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4376 "source:", t->source,
4377 - "line:", t->line, "pos:", t->line_pos,
4378 + "line:", t->line, "pos:", t->line_pos,
4379 "missing closing quote");
4387 t->line_pos += i + 1;
4399 buffer_copy_string(token, "(");
4409 buffer_copy_string(token, ")");
4420 buffer_copy_string(token, "$");
4426 @@ -637,115 +644,107 @@
4435 buffer_copy_string(token, "{");
4448 buffer_copy_string(token, "}");
4460 buffer_copy_string(token, "[");
4473 buffer_copy_string(token, "]");
4478 t->line_pos += config_skip_comment(t);
4484 - for (i = 0; t->input[t->offset + i] &&
4485 + for (i = 0; t->input[t->offset + i] &&
4486 (isalpha((unsigned char)t->input[t->offset + i])
4490 if (i && t->input[t->offset + i]) {
4491 tid = TK_SRVVARNAME;
4492 buffer_copy_string_len(token, t->input + t->offset, i);
4499 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4500 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4501 "source:", t->source,
4502 - "line:", t->line, "pos:", t->line_pos,
4503 + "line:", t->line, "pos:", t->line_pos,
4504 "invalid character in condition");
4507 } else if (isdigit((unsigned char)c)) {
4508 /* take all digits */
4509 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++);
4512 /* was there it least a digit ? */
4513 - if (i && t->input[t->offset + i]) {
4518 buffer_copy_string_len(token, t->input + t->offset, i);
4525 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4526 - "source:", t->source,
4527 - "line:", t->line, "pos:", t->line_pos,
4528 - "unexpected EOF");
4533 /* the key might consist of [-.0-9a-z] */
4534 - for (i = 0; t->input[t->offset + i] &&
4535 - (isalnum((unsigned char)t->input[t->offset + i]) ||
4536 + for (i = 0; t->input[t->offset + i] &&
4537 + (isalnum((unsigned char)t->input[t->offset + i]) ||
4538 t->input[t->offset + i] == '.' ||
4539 t->input[t->offset + i] == '_' || /* for env.* */
4540 t->input[t->offset + i] == '-'
4544 if (i && t->input[t->offset + i]) {
4545 buffer_copy_string_len(token, t->input + t->offset, i);
4547 - if (strcmp(token->ptr, "include") == 0) {
4549 + if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4551 - } else if (strcmp(token->ptr, "include_shell") == 0) {
4552 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4553 tid = TK_INCLUDE_SHELL;
4554 - } else if (strcmp(token->ptr, "global") == 0) {
4555 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4557 - } else if (strcmp(token->ptr, "else") == 0) {
4558 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4569 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4570 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4571 "source:", t->source,
4572 - "line:", t->line, "pos:", t->line_pos,
4573 + "line:", t->line, "pos:", t->line_pos,
4574 "invalid character in variable name");
4577 @@ -753,16 +752,16 @@
4586 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4587 + log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4588 "source:", t->source,
4589 "line:", t->line, "pos:", t->line_pos,
4590 token, token->used - 1, tid);
4595 } else if (t->offset < t->size) {
4596 fprintf(stderr, "%s.%d: %d, %s\n",
4597 @@ -781,10 +780,11 @@
4598 pParser = configparserAlloc( malloc );
4599 lasttoken = buffer_init();
4600 token = buffer_init();
4602 while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4603 buffer_copy_string_buffer(lasttoken, token);
4604 configparser(pParser, token_id, token, context);
4607 token = buffer_init();
4610 @@ -797,14 +797,14 @@
4613 configparserFree(pParser, free);
4617 - log_error_write(srv, __FILE__, __LINE__, "sb",
4618 + log_error_write(srv, __FILE__, __LINE__, "sb",
4619 "configfile parser failed:", lasttoken);
4620 } else if (context->ok == 0) {
4621 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4622 + log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4623 "source:", t->source,
4624 - "line:", t->line, "pos:", t->line_pos,
4625 + "line:", t->line, "pos:", t->line_pos,
4626 "parser failed somehow near here:", lasttoken);
4641 if (0 != stream_open(&s, filename)) {
4642 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4643 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4644 "opening configfile ", filename, "failed:", strerror(errno));
4648 char oldpwd[PATH_MAX];
4650 if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4651 - log_error_write(srv, __FILE__, __LINE__, "s",
4652 + log_error_write(srv, __FILE__, __LINE__, "s",
4653 "cannot get cwd", strerror(errno));
4659 if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4660 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4661 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4662 "opening", source, "failed:", strerror(errno));
4665 @@ -896,13 +896,12 @@
4666 static void context_init(server *srv, config_t *context) {
4669 - context->configs_stack = array_init();
4670 - context->configs_stack->is_weakref = 1;
4671 + context->configs_stack = buffer_ptr_init(NULL);
4672 context->basedir = buffer_init();
4675 static void context_free(config_t *context) {
4676 - array_free(context->configs_stack);
4677 + buffer_ptr_free(context->configs_stack);
4678 buffer_free(context->basedir);
4681 @@ -918,18 +917,15 @@
4682 context_init(srv, &context);
4683 context.all_configs = srv->config_context;
4692 + /* use the current dir as basedir for all other includes
4694 + pos = strrchr(fn, DIR_SEPERATOR);
4697 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4702 dc = data_config_init();
4703 buffer_copy_string(dc->key, "global");
4706 dpid->value = getpid();
4707 buffer_copy_string(dpid->key, "var.PID");
4708 array_insert_unique(srv->config, (data_unset *)dpid);
4711 dcwd = data_string_init();
4712 buffer_prepare_copy(dcwd->value, 1024);
4713 if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4720 if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4722 data_array *prepends;
4723 @@ -1026,22 +1022,23 @@
4724 buffer_copy_string(modules->key, "server.modules");
4725 array_insert_unique(srv->config, (data_unset *)modules);
4730 if (0 != config_insert(srv)) {
4739 int config_set_defaults(server *srv) {
4741 specific_config *s = srv->config_storage[0];
4742 struct stat st1, st2;
4744 - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4747 + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4749 /* - poll is most reliable
4750 * - select works everywhere
4751 * - linux-* are experimental
4752 @@ -1067,20 +1064,21 @@
4754 { FDEVENT_HANDLER_UNSET, NULL }
4758 - if (buffer_is_empty(s->document_root)) {
4759 - log_error_write(srv, __FILE__, __LINE__, "s",
4760 - "a default document-root has to be set");
4766 + if (buffer_is_empty(s->document_root)) {
4767 + log_error_write(srv, __FILE__, __LINE__, "s",
4768 + "a default document-root has to be set");
4773 if (buffer_is_empty(srv->srvconf.changeroot)) {
4774 - if (-1 == stat(s->document_root->ptr, &st1)) {
4775 - log_error_write(srv, __FILE__, __LINE__, "sb",
4776 + pathname_unix2local(s->document_root);
4777 + if (-1 == stat(s->document_root->ptr, &st1)) {
4778 + log_error_write(srv, __FILE__, __LINE__, "sbs",
4779 "base-docroot doesn't exist:",
4780 - s->document_root);
4781 + s->document_root, strerror(errno));
4785 @@ -1088,18 +1086,18 @@
4786 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4787 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4789 - if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4790 - log_error_write(srv, __FILE__, __LINE__, "sb",
4791 + if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4792 + log_error_write(srv, __FILE__, __LINE__, "sb",
4793 "base-docroot doesn't exist:",
4802 - buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4804 - buffer_to_lower(srv->tmp_buf);
4805 + buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4807 + buffer_to_lower(srv->tmp_buf);
4809 if (0 == stat(srv->tmp_buf->ptr, &st1)) {
4811 @@ -1107,68 +1105,68 @@
4812 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
4814 /* lower-case existed, check upper-case */
4815 - buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4816 + buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4818 - buffer_to_upper(srv->tmp_buf);
4819 + buffer_to_upper(srv->tmp_buf);
4821 /* we have to handle the special case that upper and lower-casing results in the same filename
4822 * as in server.document-root = "/" or "/12345/" */
4824 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
4825 - /* lower-casing and upper-casing didn't result in
4826 - * an other filename, no need to stat(),
4827 + /* lower-casing and upper-casing didn't result in
4828 + * an other filename, no need to stat(),
4829 * just assume it is case-sensitive. */
4831 s->force_lowercase_filenames = 0;
4832 - } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4833 + } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4835 + /* upper case exists too, doesn't the FS handle this ? */
4837 + /* upper and lower have the same inode -> case-insensitve FS */
4839 + if (st1.st_ino == st2.st_ino) {
4840 + /* upper and lower have the same inode -> case-insensitve FS */
4842 + s->force_lowercase_filenames = 1;
4847 - /* upper case exists too, doesn't the FS handle this ? */
4849 - /* upper and lower have the same inode -> case-insensitve FS */
4851 - if (st1.st_ino == st2.st_ino) {
4852 - /* upper and lower have the same inode -> case-insensitve FS */
4854 - s->force_lowercase_filenames = 1;
4859 if (srv->srvconf.port == 0) {
4860 srv->srvconf.port = s->is_ssl ? 443 : 80;
4864 if (srv->srvconf.event_handler->used == 0) {
4865 /* choose a good default
4867 - * the event_handler list is sorted by 'goodness'
4869 + * the event_handler list is sorted by 'goodness'
4870 * taking the first available should be the best solution
4872 srv->event_handler = event_handlers[0].et;
4875 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4876 - log_error_write(srv, __FILE__, __LINE__, "s",
4877 + log_error_write(srv, __FILE__, __LINE__, "s",
4878 "sorry, there is no event handler for this system");
4889 for (i = 0; event_handlers[i].name; i++) {
4890 if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
4891 srv->event_handler = event_handlers[i].et;
4897 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4898 - log_error_write(srv, __FILE__, __LINE__, "sb",
4899 - "the selected event-handler in unknown or not supported:",
4900 + log_error_write(srv, __FILE__, __LINE__, "sb",
4901 + "the selected event-handler in unknown or not supported:",
4902 srv->srvconf.event_handler );
4908 @@ -1176,19 +1174,19 @@
4910 if (buffer_is_empty(s->ssl_pemfile)) {
4911 /* PEM file is require */
4913 - log_error_write(srv, __FILE__, __LINE__, "s",
4915 + log_error_write(srv, __FILE__, __LINE__, "s",
4916 "ssl.pemfile has to be set");
4922 - log_error_write(srv, __FILE__, __LINE__, "s",
4923 + log_error_write(srv, __FILE__, __LINE__, "s",
4924 "ssl support is missing, recompile with --with-openssl");
4934 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
4935 +++ lighttpd-1.4.12/src/configfile.h 2006-07-16 00:26:03.000000000 +0300
4940 - array *configs_stack; /* to parse nested block */
4941 + buffer_ptr *configs_stack; /* to parse nested block */
4942 data_config *current; /* current started with { */
4945 --- ../lighttpd-1.4.11/src/configparser.c 2006-02-01 19:51:15.000000000 +0200
4946 +++ lighttpd-1.4.12/src/configparser.c 2006-07-17 22:02:23.000000000 +0300
4948 dc->parent = ctx->current;
4949 array_insert_unique(dc->parent->childs, (data_unset *)dc);
4951 - array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
4952 + buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
4956 static data_config *configparser_pop(config_t *ctx) {
4957 data_config *old = ctx->current;
4958 - ctx->current = (data_config *) array_pop(ctx->configs_stack);
4959 + ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
4963 /* return a copied variable */
4964 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
4965 - if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
4968 - if (NULL != (env = getenv(key->ptr + 4))) {
4970 - ds = data_string_init();
4971 - buffer_append_string(ds->value, env);
4972 - return (data_unset *)ds;
4975 - fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
4986 - fprintf(stderr, "get var %s\n", key->ptr);
4987 + fprintf(stderr, "get var %s\n", key->ptr);
4989 - for (dc = ctx->current; dc; dc = dc->parent) {
4990 + for (dc = ctx->current; dc; dc = dc->parent) {
4992 - fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4993 - array_print(dc->value, 0);
4994 + fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4995 + array_print(dc->value, 0);
4997 - if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4998 - return du->copy(du);
5000 + if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5001 + return du->copy(du);
5003 - fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5010 /* op1 is to be eat/return by this function, op1->key is not cared
5011 @@ -124,14 +106,14 @@
5015 -#line 128 "configparser.c"
5016 +#line 110 "configparser.c"
5017 /* Next is all token values, in a form suitable for use by makeheaders.
5018 ** This section will be null unless lemon is run with the -m switch.
5022 ** These constants (all generated automatically by the parser generator)
5023 ** specify the various kinds of tokens (terminals) that the parser
5027 ** Each symbol here is a terminal symbol in the grammar.
5030 ** and nonterminals. "int" is used otherwise.
5031 ** YYNOCODE is a number of type YYCODETYPE which corresponds
5032 ** to no legal terminal or nonterminal number. This
5033 -** number is used to fill in empty slots of the hash
5034 +** number is used to fill in empty slots of the hash
5036 ** YYFALLBACK If defined, this indicates that one or more tokens
5037 ** have fall-back values which should be used if the
5039 ** and nonterminal numbers. "unsigned char" is
5040 ** used if there are fewer than 250 rules and
5041 ** states combined. "int" is used otherwise.
5042 -** configparserTOKENTYPE is the data type used for minor tokens given
5043 +** configparserTOKENTYPE is the data type used for minor tokens given
5044 ** directly to the parser from the tokenizer.
5045 ** YYMINORTYPE is the data type used for all minor tokens.
5046 ** This is typically a union of many types, one of
5048 #define configparserARG_PDECL ,config_t *ctx
5049 #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5050 #define configparserARG_STORE yypParser->ctx = ctx
5051 -#define YYNSTATE 62
5053 +#define YYNSTATE 63
5055 #define YYERRORSYMBOL 26
5056 #define YYERRSYMDT yy95
5057 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
5059 /* Next are that tables used to determine what action to take based on the
5060 ** current state and lookahead token. These tables are used to implement
5061 ** functions that take a state number and lookahead value and return an
5065 ** Suppose the action integer is N. Then the action is determined as
5068 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5069 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5070 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5071 -** and that yy_default[S] should be used instead.
5072 +** and that yy_default[S] should be used instead.
5074 ** The formula above is for computing the action when the lookahead is
5075 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
5076 @@ -248,67 +230,69 @@
5077 ** yy_default[] Default action for each state.
5079 static YYACTIONTYPE yy_action[] = {
5080 - /* 0 */ 2, 3, 4, 5, 13, 14, 62, 15, 7, 44,
5081 - /* 10 */ 20, 86, 16, 45, 28, 48, 40, 10, 39, 25,
5082 - /* 20 */ 22, 49, 45, 8, 15, 102, 1, 20, 28, 18,
5083 - /* 30 */ 57, 59, 19, 25, 22, 39, 19, 61, 98, 45,
5084 - /* 40 */ 20, 6, 23, 24, 26, 28, 35, 57, 59, 12,
5085 - /* 50 */ 25, 22, 28, 27, 36, 87, 29, 25, 22, 33,
5086 - /* 60 */ 15, 30, 31, 20, 28, 38, 9, 17, 37, 25,
5087 - /* 70 */ 22, 39, 42, 43, 10, 45, 11, 53, 54, 55,
5088 - /* 80 */ 56, 28, 52, 57, 59, 34, 25, 22, 28, 27,
5089 - /* 90 */ 32, 88, 41, 25, 22, 33, 28, 48, 46, 28,
5090 - /* 100 */ 48, 25, 22, 58, 25, 22, 60, 21, 19, 47,
5091 - /* 110 */ 51, 50, 25, 22, 88, 88, 93,
5092 + /* 0 */ 2, 3, 4, 5, 13, 14, 63, 15, 7, 45,
5093 + /* 10 */ 20, 88, 16, 46, 28, 49, 41, 10, 40, 25,
5094 + /* 20 */ 22, 50, 46, 8, 15, 104, 1, 20, 28, 18,
5095 + /* 30 */ 58, 60, 6, 25, 22, 40, 47, 62, 11, 46,
5096 + /* 40 */ 20, 9, 23, 24, 26, 29, 89, 58, 60, 10,
5097 + /* 50 */ 17, 38, 28, 27, 37, 19, 30, 25, 22, 34,
5098 + /* 60 */ 15, 100, 20, 20, 23, 24, 26, 12, 19, 31,
5099 + /* 70 */ 32, 40, 19, 44, 43, 46, 95, 35, 90, 89,
5100 + /* 80 */ 28, 49, 42, 58, 60, 25, 22, 59, 28, 27,
5101 + /* 90 */ 33, 48, 52, 25, 22, 34, 28, 49, 51, 28,
5102 + /* 100 */ 36, 25, 22, 61, 25, 22, 89, 28, 39, 89,
5103 + /* 110 */ 89, 89, 25, 22, 54, 55, 56, 57, 89, 28,
5104 + /* 120 */ 53, 21, 89, 89, 25, 22, 25, 22,
5106 static YYCODETYPE yy_lookahead[] = {
5107 /* 0 */ 29, 30, 31, 32, 33, 34, 0, 1, 44, 38,
5108 /* 10 */ 4, 15, 41, 16, 35, 36, 45, 46, 12, 40,
5109 /* 20 */ 41, 42, 16, 15, 1, 27, 28, 4, 35, 36,
5110 - /* 30 */ 24, 25, 5, 40, 41, 12, 5, 14, 11, 16,
5111 - /* 40 */ 4, 1, 6, 7, 8, 35, 36, 24, 25, 28,
5112 - /* 50 */ 40, 41, 35, 36, 37, 15, 39, 40, 41, 42,
5113 - /* 60 */ 1, 9, 10, 4, 35, 36, 38, 2, 3, 40,
5114 - /* 70 */ 41, 12, 28, 14, 46, 16, 13, 20, 21, 22,
5115 - /* 80 */ 23, 35, 36, 24, 25, 11, 40, 41, 35, 36,
5116 - /* 90 */ 37, 13, 13, 40, 41, 42, 35, 36, 17, 35,
5117 - /* 100 */ 36, 40, 41, 42, 40, 41, 42, 35, 5, 18,
5118 - /* 110 */ 43, 19, 40, 41, 47, 47, 13,
5119 + /* 30 */ 24, 25, 1, 40, 41, 12, 17, 14, 13, 16,
5120 + /* 40 */ 4, 38, 6, 7, 8, 9, 15, 24, 25, 46,
5121 + /* 50 */ 2, 3, 35, 36, 37, 5, 39, 40, 41, 42,
5122 + /* 60 */ 1, 11, 4, 4, 6, 7, 8, 28, 5, 9,
5123 + /* 70 */ 10, 12, 5, 14, 28, 16, 13, 11, 13, 47,
5124 + /* 80 */ 35, 36, 13, 24, 25, 40, 41, 42, 35, 36,
5125 + /* 90 */ 37, 18, 43, 40, 41, 42, 35, 36, 19, 35,
5126 + /* 100 */ 36, 40, 41, 42, 40, 41, 47, 35, 36, 47,
5127 + /* 110 */ 47, 47, 40, 41, 20, 21, 22, 23, 47, 35,
5128 + /* 120 */ 36, 35, 47, 47, 40, 41, 40, 41,
5130 #define YY_SHIFT_USE_DFLT (-5)
5131 static signed char yy_shift_ofst[] = {
5132 - /* 0 */ -5, 6, -5, -5, -5, 40, -4, 8, -3, -5,
5133 - /* 10 */ 63, -5, 23, -5, -5, -5, 65, 36, 31, 36,
5134 - /* 20 */ -5, -5, -5, -5, -5, -5, 36, 27, -5, 52,
5135 - /* 30 */ -5, 36, -5, 74, 36, 31, -5, 36, 31, 78,
5136 - /* 40 */ 79, -5, 59, -5, -5, 81, 91, 36, 31, 92,
5137 - /* 50 */ 57, 36, 103, -5, -5, -5, -5, 36, -5, 36,
5139 + /* 0 */ -5, 6, -5, -5, -5, 31, -4, 8, -3, -5,
5140 + /* 10 */ 25, -5, 23, -5, -5, -5, 48, 58, 67, 58,
5141 + /* 20 */ -5, -5, -5, -5, -5, -5, 36, 50, -5, -5,
5142 + /* 30 */ 60, -5, 58, -5, 66, 58, 67, -5, 58, 67,
5143 + /* 40 */ 65, 69, -5, 59, -5, -5, 19, 73, 58, 67,
5144 + /* 50 */ 79, 94, 58, 63, -5, -5, -5, -5, 58, -5,
5145 + /* 60 */ 58, -5, -5,
5147 #define YY_REDUCE_USE_DFLT (-37)
5148 static signed char yy_reduce_ofst[] = {
5149 - /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 28, -37,
5150 - /* 10 */ -37, 21, -29, -37, -37, -37, -37, -7, -37, 72,
5151 + /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 3, -37,
5152 + /* 10 */ -37, 39, -29, -37, -37, -37, -37, -7, -37, 86,
5153 /* 20 */ -37, -37, -37, -37, -37, -37, 17, -37, -37, -37,
5154 - /* 30 */ -37, 53, -37, -37, 10, -37, -37, 29, -37, -37,
5155 - /* 40 */ -37, 44, -29, -37, -37, -37, -37, -21, -37, -37,
5156 - /* 50 */ 67, 46, -37, -37, -37, -37, -37, 61, -37, 64,
5157 - /* 60 */ -37, -37,
5158 + /* 30 */ -37, -37, 53, -37, -37, 64, -37, -37, 72, -37,
5159 + /* 40 */ -37, -37, 46, -29, -37, -37, -37, -37, -21, -37,
5160 + /* 50 */ -37, 49, 84, -37, -37, -37, -37, -37, 45, -37,
5161 + /* 60 */ 61, -37, -37,
5163 static YYACTIONTYPE yy_default[] = {
5164 - /* 0 */ 64, 101, 63, 65, 66, 101, 67, 101, 101, 90,
5165 - /* 10 */ 101, 64, 101, 68, 69, 70, 101, 101, 71, 101,
5166 - /* 20 */ 73, 74, 76, 77, 78, 79, 101, 84, 75, 101,
5167 - /* 30 */ 80, 82, 81, 101, 101, 85, 83, 101, 72, 101,
5168 - /* 40 */ 101, 64, 101, 89, 91, 101, 101, 101, 98, 101,
5169 - /* 50 */ 101, 101, 101, 94, 95, 96, 97, 101, 99, 101,
5171 + /* 0 */ 65, 103, 64, 66, 67, 103, 68, 103, 103, 92,
5172 + /* 10 */ 103, 65, 103, 69, 70, 71, 103, 103, 72, 103,
5173 + /* 20 */ 74, 75, 77, 78, 79, 80, 103, 86, 76, 81,
5174 + /* 30 */ 103, 82, 84, 83, 103, 103, 87, 85, 103, 73,
5175 + /* 40 */ 103, 103, 65, 103, 91, 93, 103, 103, 103, 100,
5176 + /* 50 */ 103, 103, 103, 103, 96, 97, 98, 99, 103, 101,
5177 + /* 60 */ 103, 102, 94,
5179 #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5181 /* The next table maps tokens into fallback tokens. If a construct
5182 ** like the following:
5185 ** %fallback ID X Y Z.
5187 ** appears in the grammer, then ID becomes a fallback token for X, Y,
5188 @@ -359,10 +343,10 @@
5194 ** Turn parser tracing on by giving a stream to which to write the trace
5195 ** and a prompt to preface each trace message. Tracing is turned off
5196 -** by making either argument NULL
5197 +** by making either argument NULL
5203 /* For tracing shifts, the names of all terminals and nonterminals
5204 ** are required. The following table supplies these names */
5205 -static const char *yyTokenName[] = {
5206 +static const char *yyTokenName[] = {
5207 "$", "EOL", "ASSIGN", "APPEND",
5208 "LKEY", "PLUS", "STRING", "INTEGER",
5209 "LPARAN", "RPARAN", "COMMA", "ARRAY_ASSIGN",
5210 @@ -425,27 +409,28 @@
5211 /* 15 */ "value ::= STRING",
5212 /* 16 */ "value ::= INTEGER",
5213 /* 17 */ "value ::= array",
5214 - /* 18 */ "array ::= LPARAN aelements RPARAN",
5215 - /* 19 */ "aelements ::= aelements COMMA aelement",
5216 - /* 20 */ "aelements ::= aelements COMMA",
5217 - /* 21 */ "aelements ::= aelement",
5218 - /* 22 */ "aelement ::= expression",
5219 - /* 23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5220 - /* 24 */ "eols ::= EOL",
5221 - /* 25 */ "eols ::=",
5222 - /* 26 */ "globalstart ::= GLOBAL",
5223 - /* 27 */ "global ::= globalstart LCURLY metalines RCURLY",
5224 - /* 28 */ "condlines ::= condlines eols ELSE condline",
5225 - /* 29 */ "condlines ::= condline",
5226 - /* 30 */ "condline ::= context LCURLY metalines RCURLY",
5227 - /* 31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5228 - /* 32 */ "cond ::= EQ",
5229 - /* 33 */ "cond ::= MATCH",
5230 - /* 34 */ "cond ::= NE",
5231 - /* 35 */ "cond ::= NOMATCH",
5232 - /* 36 */ "stringop ::= expression",
5233 - /* 37 */ "include ::= INCLUDE stringop",
5234 - /* 38 */ "include_shell ::= INCLUDE_SHELL stringop",
5235 + /* 18 */ "array ::= LPARAN RPARAN",
5236 + /* 19 */ "array ::= LPARAN aelements RPARAN",
5237 + /* 20 */ "aelements ::= aelements COMMA aelement",
5238 + /* 21 */ "aelements ::= aelements COMMA",
5239 + /* 22 */ "aelements ::= aelement",
5240 + /* 23 */ "aelement ::= expression",
5241 + /* 24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5242 + /* 25 */ "eols ::= EOL",
5243 + /* 26 */ "eols ::=",
5244 + /* 27 */ "globalstart ::= GLOBAL",
5245 + /* 28 */ "global ::= globalstart LCURLY metalines RCURLY",
5246 + /* 29 */ "condlines ::= condlines eols ELSE condline",
5247 + /* 30 */ "condlines ::= condline",
5248 + /* 31 */ "condline ::= context LCURLY metalines RCURLY",
5249 + /* 32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5250 + /* 33 */ "cond ::= EQ",
5251 + /* 34 */ "cond ::= MATCH",
5252 + /* 35 */ "cond ::= NE",
5253 + /* 36 */ "cond ::= NOMATCH",
5254 + /* 37 */ "stringop ::= expression",
5255 + /* 38 */ "include ::= INCLUDE stringop",
5256 + /* 39 */ "include_shell ::= INCLUDE_SHELL stringop",
5266 ** This function allocates a new parser.
5267 ** The only argument is a pointer to a function which works like
5270 /* Here is inserted the actions which take place when a
5271 ** terminal or non-terminal is destroyed. This can happen
5272 ** when the symbol is popped from the stack during a
5273 - ** reduce or during error processing or when a parser is
5274 + ** reduce or during error processing or when a parser is
5275 ** being destroyed before it is finished parsing.
5277 ** Note: during a reduce, the only symbols destroyed are those
5278 @@ -528,44 +513,44 @@
5282 -#line 160 "./configparser.y"
5283 +#line 143 "./configparser.y"
5284 { buffer_free((yypminor->yy0)); }
5285 -#line 533 "configparser.c"
5286 +#line 518 "configparser.c"
5289 -#line 151 "./configparser.y"
5290 +#line 134 "./configparser.y"
5291 { (yypminor->yy41)->free((yypminor->yy41)); }
5292 -#line 538 "configparser.c"
5293 +#line 523 "configparser.c"
5296 -#line 152 "./configparser.y"
5297 +#line 135 "./configparser.y"
5298 { (yypminor->yy41)->free((yypminor->yy41)); }
5299 -#line 543 "configparser.c"
5300 +#line 528 "configparser.c"
5303 -#line 153 "./configparser.y"
5304 +#line 136 "./configparser.y"
5305 { (yypminor->yy41)->free((yypminor->yy41)); }
5306 -#line 548 "configparser.c"
5307 +#line 533 "configparser.c"
5310 -#line 154 "./configparser.y"
5311 +#line 137 "./configparser.y"
5312 { array_free((yypminor->yy40)); }
5313 -#line 553 "configparser.c"
5314 +#line 538 "configparser.c"
5317 -#line 155 "./configparser.y"
5318 +#line 138 "./configparser.y"
5319 { array_free((yypminor->yy40)); }
5320 -#line 558 "configparser.c"
5321 +#line 543 "configparser.c"
5324 -#line 156 "./configparser.y"
5325 +#line 139 "./configparser.y"
5326 { buffer_free((yypminor->yy43)); }
5327 -#line 563 "configparser.c"
5328 +#line 548 "configparser.c"
5331 -#line 157 "./configparser.y"
5332 +#line 140 "./configparser.y"
5333 { buffer_free((yypminor->yy43)); }
5334 -#line 568 "configparser.c"
5335 +#line 553 "configparser.c"
5337 default: break; /* If no destructor action specified: do nothing */
5345 ** Deallocate and destroy a parser. Destructors are all called for
5346 ** all stack elements before shutting the parser down.
5351 int stateno = pParser->yystack[pParser->yyidx].stateno;
5354 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
5355 i = yy_shift_ofst[stateno];
5356 if( i==YY_SHIFT_USE_DFLT ){
5360 int stateno = pParser->yystack[pParser->yyidx].stateno;
5363 i = yy_reduce_ofst[stateno];
5364 if( i==YY_REDUCE_USE_DFLT ){
5365 return yy_default[stateno];
5375 configparserARG_FETCH;
5376 yymsp = &yypParser->yystack[yypParser->yyidx];
5378 - if( yyTraceFILE && yyruleno>=0
5379 + if( yyTraceFILE && yyruleno>=0
5380 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5381 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5382 yyRuleName[yyruleno]);
5384 /* No destructor defined for global */
5387 -#line 134 "./configparser.y"
5388 +#line 116 "./configparser.y"
5389 { yymsp[-1].minor.yy78 = NULL; }
5390 -#line 837 "configparser.c"
5391 +#line 823 "configparser.c"
5392 yy_destructor(1,&yymsp[0].minor);
5395 @@ -847,10 +833,15 @@
5396 yy_destructor(1,&yymsp[0].minor);
5399 -#line 162 "./configparser.y"
5400 +#line 145 "./configparser.y"
5402 buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5403 - if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5404 + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5405 + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5406 + ctx->current->context_ndx,
5407 + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5409 + } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5410 array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5411 yymsp[0].minor.yy41 = NULL;
5413 @@ -864,16 +855,21 @@
5414 buffer_free(yymsp[-2].minor.yy43);
5415 yymsp[-2].minor.yy43 = NULL;
5417 -#line 867 "configparser.c"
5418 +#line 858 "configparser.c"
5419 yy_destructor(2,&yymsp[-1].minor);
5422 -#line 179 "./configparser.y"
5423 +#line 167 "./configparser.y"
5425 array *vars = ctx->current->value;
5428 - if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5429 + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5430 + fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5431 + ctx->current->context_ndx,
5432 + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5434 + } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5435 /* exists in current block */
5436 du = configparser_merge_data(du, yymsp[0].minor.yy41);
5439 buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5440 array_replace(vars, du);
5442 + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5443 } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5444 du = configparser_merge_data(du, yymsp[0].minor.yy41);
5446 @@ -892,22 +889,20 @@
5447 buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5448 array_insert_unique(ctx->current->value, du);
5450 + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5452 - fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
5453 - ctx->current->context_ndx,
5454 - ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5456 + buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5457 + array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5459 buffer_free(yymsp[-2].minor.yy43);
5460 yymsp[-2].minor.yy43 = NULL;
5461 - yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5462 yymsp[0].minor.yy41 = NULL;
5464 -#line 906 "configparser.c"
5465 +#line 901 "configparser.c"
5466 yy_destructor(3,&yymsp[-1].minor);
5469 -#line 214 "./configparser.y"
5470 +#line 206 "./configparser.y"
5472 if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5473 yygotominor.yy43 = buffer_init_string("var.");
5474 @@ -919,10 +914,10 @@
5475 yymsp[0].minor.yy0 = NULL;
5478 -#line 922 "configparser.c"
5479 +#line 917 "configparser.c"
5482 -#line 226 "./configparser.y"
5483 +#line 218 "./configparser.y"
5485 yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5486 if (NULL == yygotominor.yy41) {
5487 @@ -932,21 +927,38 @@
5488 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5489 yymsp[0].minor.yy41 = NULL;
5491 -#line 935 "configparser.c"
5492 +#line 930 "configparser.c"
5493 yy_destructor(5,&yymsp[-1].minor);
5496 -#line 236 "./configparser.y"
5497 +#line 228 "./configparser.y"
5499 yygotominor.yy41 = yymsp[0].minor.yy41;
5500 yymsp[0].minor.yy41 = NULL;
5502 -#line 944 "configparser.c"
5503 +#line 939 "configparser.c"
5506 -#line 241 "./configparser.y"
5507 +#line 233 "./configparser.y"
5509 - yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5510 + if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5513 + if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5515 + ds = data_string_init();
5516 + buffer_append_string(ds->value, env);
5517 + yygotominor.yy41 = (data_unset *)ds;
5520 + yygotominor.yy41 = NULL;
5521 + fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5524 + } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5525 + fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5528 if (!yygotominor.yy41) {
5529 /* make a dummy so it won't crash */
5530 yygotominor.yy41 = (data_unset *)data_string_init();
5531 @@ -954,50 +966,59 @@
5532 buffer_free(yymsp[0].minor.yy43);
5533 yymsp[0].minor.yy43 = NULL;
5535 -#line 957 "configparser.c"
5536 +#line 969 "configparser.c"
5539 -#line 251 "./configparser.y"
5540 +#line 260 "./configparser.y"
5542 yygotominor.yy41 = (data_unset *)data_string_init();
5543 buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5544 buffer_free(yymsp[0].minor.yy0);
5545 yymsp[0].minor.yy0 = NULL;
5547 -#line 967 "configparser.c"
5548 +#line 979 "configparser.c"
5551 -#line 258 "./configparser.y"
5552 +#line 267 "./configparser.y"
5554 yygotominor.yy41 = (data_unset *)data_integer_init();
5555 ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5556 buffer_free(yymsp[0].minor.yy0);
5557 yymsp[0].minor.yy0 = NULL;
5559 -#line 977 "configparser.c"
5560 +#line 989 "configparser.c"
5563 -#line 264 "./configparser.y"
5564 +#line 273 "./configparser.y"
5566 yygotominor.yy41 = (data_unset *)data_array_init();
5567 array_free(((data_array *)(yygotominor.yy41))->value);
5568 ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5569 yymsp[0].minor.yy40 = NULL;
5571 -#line 987 "configparser.c"
5572 +#line 999 "configparser.c"
5575 -#line 270 "./configparser.y"
5576 +#line 279 "./configparser.y"
5578 + yygotominor.yy40 = array_init();
5580 +#line 1006 "configparser.c"
5581 + yy_destructor(8,&yymsp[-1].minor);
5582 + yy_destructor(9,&yymsp[0].minor);
5585 +#line 282 "./configparser.y"
5587 yygotominor.yy40 = yymsp[-1].minor.yy40;
5588 yymsp[-1].minor.yy40 = NULL;
5590 -#line 995 "configparser.c"
5591 +#line 1016 "configparser.c"
5592 yy_destructor(8,&yymsp[-2].minor);
5593 yy_destructor(9,&yymsp[0].minor);
5596 -#line 275 "./configparser.y"
5598 +#line 287 "./configparser.y"
5600 if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5601 NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5602 @@ -1014,37 +1035,37 @@
5603 yygotominor.yy40 = yymsp[-2].minor.yy40;
5604 yymsp[-2].minor.yy40 = NULL;
5606 -#line 1017 "configparser.c"
5607 +#line 1038 "configparser.c"
5608 yy_destructor(10,&yymsp[-1].minor);
5611 -#line 292 "./configparser.y"
5613 +#line 304 "./configparser.y"
5615 yygotominor.yy40 = yymsp[-1].minor.yy40;
5616 yymsp[-1].minor.yy40 = NULL;
5618 -#line 1026 "configparser.c"
5619 +#line 1047 "configparser.c"
5620 yy_destructor(10,&yymsp[0].minor);
5623 -#line 297 "./configparser.y"
5625 +#line 309 "./configparser.y"
5627 yygotominor.yy40 = array_init();
5628 array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5629 yymsp[0].minor.yy41 = NULL;
5631 -#line 1036 "configparser.c"
5632 +#line 1057 "configparser.c"
5635 -#line 303 "./configparser.y"
5637 +#line 315 "./configparser.y"
5639 yygotominor.yy41 = yymsp[0].minor.yy41;
5640 yymsp[0].minor.yy41 = NULL;
5642 -#line 1044 "configparser.c"
5643 +#line 1065 "configparser.c"
5646 -#line 307 "./configparser.y"
5648 +#line 319 "./configparser.y"
5650 buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5651 buffer_free(yymsp[-2].minor.yy43);
5652 @@ -1053,27 +1074,27 @@
5653 yygotominor.yy41 = yymsp[0].minor.yy41;
5654 yymsp[0].minor.yy41 = NULL;
5656 -#line 1056 "configparser.c"
5657 +#line 1077 "configparser.c"
5658 yy_destructor(11,&yymsp[-1].minor);
5661 - yy_destructor(1,&yymsp[0].minor);
5664 + yy_destructor(1,&yymsp[0].minor);
5667 -#line 319 "./configparser.y"
5670 +#line 331 "./configparser.y"
5673 dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5675 configparser_push(ctx, dc, 0);
5677 -#line 1072 "configparser.c"
5678 +#line 1093 "configparser.c"
5679 yy_destructor(12,&yymsp[0].minor);
5682 -#line 326 "./configparser.y"
5684 +#line 338 "./configparser.y"
5688 @@ -1082,16 +1103,16 @@
5690 assert(cur && ctx->current);
5692 - yygotominor.yy0 = cur;
5693 + yygotominor.yy78 = cur;
5695 -#line 1087 "configparser.c"
5696 +#line 1108 "configparser.c"
5697 /* No destructor defined for globalstart */
5698 yy_destructor(13,&yymsp[-2].minor);
5699 /* No destructor defined for metalines */
5700 yy_destructor(14,&yymsp[0].minor);
5703 -#line 337 "./configparser.y"
5705 +#line 349 "./configparser.y"
5707 assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5708 yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5709 @@ -1100,20 +1121,20 @@
5710 yymsp[-3].minor.yy78 = NULL;
5711 yymsp[0].minor.yy78 = NULL;
5713 -#line 1103 "configparser.c"
5714 +#line 1124 "configparser.c"
5715 /* No destructor defined for eols */
5716 yy_destructor(15,&yymsp[-1].minor);
5719 -#line 346 "./configparser.y"
5721 +#line 358 "./configparser.y"
5723 yygotominor.yy78 = yymsp[0].minor.yy78;
5724 yymsp[0].minor.yy78 = NULL;
5726 -#line 1113 "configparser.c"
5727 +#line 1134 "configparser.c"
5730 -#line 351 "./configparser.y"
5732 +#line 363 "./configparser.y"
5736 @@ -1124,14 +1145,14 @@
5738 yygotominor.yy78 = cur;
5740 -#line 1127 "configparser.c"
5741 +#line 1148 "configparser.c"
5742 /* No destructor defined for context */
5743 yy_destructor(13,&yymsp[-2].minor);
5744 /* No destructor defined for metalines */
5745 yy_destructor(14,&yymsp[0].minor);
5748 -#line 362 "./configparser.y"
5750 +#line 374 "./configparser.y"
5753 buffer *b, *rvalue, *op;
5754 @@ -1266,45 +1287,45 @@
5755 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5756 yymsp[0].minor.yy41 = NULL;
5758 -#line 1269 "configparser.c"
5759 +#line 1290 "configparser.c"
5760 yy_destructor(16,&yymsp[-6].minor);
5761 yy_destructor(18,&yymsp[-4].minor);
5762 yy_destructor(19,&yymsp[-2].minor);
5765 -#line 496 "./configparser.y"
5767 +#line 508 "./configparser.y"
5769 yygotominor.yy27 = CONFIG_COND_EQ;
5771 -#line 1279 "configparser.c"
5772 +#line 1300 "configparser.c"
5773 yy_destructor(20,&yymsp[0].minor);
5776 -#line 499 "./configparser.y"
5778 +#line 511 "./configparser.y"
5780 yygotominor.yy27 = CONFIG_COND_MATCH;
5782 -#line 1287 "configparser.c"
5783 +#line 1308 "configparser.c"
5784 yy_destructor(21,&yymsp[0].minor);
5787 -#line 502 "./configparser.y"
5789 +#line 514 "./configparser.y"
5791 yygotominor.yy27 = CONFIG_COND_NE;
5793 -#line 1295 "configparser.c"
5794 +#line 1316 "configparser.c"
5795 yy_destructor(22,&yymsp[0].minor);
5798 -#line 505 "./configparser.y"
5800 +#line 517 "./configparser.y"
5802 yygotominor.yy27 = CONFIG_COND_NOMATCH;
5804 -#line 1303 "configparser.c"
5805 +#line 1324 "configparser.c"
5806 yy_destructor(23,&yymsp[0].minor);
5809 -#line 509 "./configparser.y"
5811 +#line 521 "./configparser.y"
5813 yygotominor.yy43 = NULL;
5815 @@ -1321,10 +1342,10 @@
5816 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5817 yymsp[0].minor.yy41 = NULL;
5819 -#line 1324 "configparser.c"
5820 +#line 1345 "configparser.c"
5823 -#line 526 "./configparser.y"
5825 +#line 538 "./configparser.y"
5828 if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5829 @@ -1334,11 +1355,11 @@
5830 yymsp[0].minor.yy43 = NULL;
5833 -#line 1337 "configparser.c"
5834 +#line 1358 "configparser.c"
5835 yy_destructor(24,&yymsp[-1].minor);
5838 -#line 536 "./configparser.y"
5840 +#line 548 "./configparser.y"
5843 if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5844 @@ -1348,7 +1369,7 @@
5845 yymsp[0].minor.yy43 = NULL;
5848 -#line 1351 "configparser.c"
5849 +#line 1372 "configparser.c"
5850 yy_destructor(25,&yymsp[-1].minor);
5853 @@ -1378,11 +1399,11 @@
5854 while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
5855 /* Here code is inserted which will be executed whenever the
5857 -#line 125 "./configparser.y"
5858 +#line 107 "./configparser.y"
5862 -#line 1385 "configparser.c"
5863 +#line 1406 "configparser.c"
5864 configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
5867 @@ -1489,7 +1510,7 @@
5868 #ifdef YYERRORSYMBOL
5869 /* A syntax error has occurred.
5870 ** The response to an error depends upon whether or not the
5871 - ** grammar defines an error token "ERROR".
5872 + ** grammar defines an error token "ERROR".
5874 ** This is what we do if the grammar does define ERROR:
5876 --- ../lighttpd-1.4.11/src/configparser.y 2006-01-26 18:46:25.000000000 +0200
5877 +++ lighttpd-1.4.12/src/configparser.y 2006-07-16 00:26:04.000000000 +0300
5879 dc->parent = ctx->current;
5880 array_insert_unique(dc->parent->childs, (data_unset *)dc);
5882 - array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5883 + buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5887 static data_config *configparser_pop(config_t *ctx) {
5888 data_config *old = ctx->current;
5889 - ctx->current = (data_config *) array_pop(ctx->configs_stack);
5890 + ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5894 /* return a copied variable */
5895 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5896 - if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5899 - if (NULL != (env = getenv(key->ptr + 4))) {
5901 - ds = data_string_init();
5902 - buffer_append_string(ds->value, env);
5903 - return (data_unset *)ds;
5906 - fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5917 - fprintf(stderr, "get var %s\n", key->ptr);
5918 + fprintf(stderr, "get var %s\n", key->ptr);
5920 - for (dc = ctx->current; dc; dc = dc->parent) {
5921 + for (dc = ctx->current; dc; dc = dc->parent) {
5923 - fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5924 - array_print(dc->value, 0);
5925 + fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5926 + array_print(dc->value, 0);
5928 - if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5929 - return du->copy(du);
5931 + if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5932 + return du->copy(du);
5934 - fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5941 /* op1 is to be eat/return by this function, op1->key is not cared
5943 %type aelement {data_unset *}
5944 %type condline {data_config *}
5945 %type condlines {data_config *}
5946 +%type global {data_config *}
5947 %type aelements {array *}
5948 %type array {array *}
5949 %type key {buffer *}
5950 @@ -161,7 +144,12 @@
5952 varline ::= key(A) ASSIGN expression(B). {
5953 buffer_copy_string_buffer(B->key, A);
5954 - if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5955 + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5956 + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5957 + ctx->current->context_ndx,
5958 + ctx->current->key->ptr, A->ptr);
5960 + } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5961 array_insert_unique(ctx->current->value, B);
5964 @@ -180,7 +168,12 @@
5965 array *vars = ctx->current->value;
5968 - if (NULL != (du = array_get_element(vars, A->ptr))) {
5969 + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5970 + fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5971 + ctx->current->context_ndx,
5972 + ctx->current->key->ptr, A->ptr);
5974 + } else if (NULL != (du = array_get_element(vars, A->ptr))) {
5975 /* exists in current block */
5976 du = configparser_merge_data(du, B);
5979 buffer_copy_string_buffer(du->key, A);
5980 array_replace(vars, du);
5983 } else if (NULL != (du = configparser_get_variable(ctx, A))) {
5984 du = configparser_merge_data(du, B);
5986 @@ -199,15 +193,13 @@
5987 buffer_copy_string_buffer(du->key, A);
5988 array_insert_unique(ctx->current->value, du);
5992 - fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
5993 - ctx->current->context_ndx,
5994 - ctx->current->key->ptr, A->ptr);
5996 + buffer_copy_string_buffer(B->key, A);
5997 + array_insert_unique(ctx->current->value, B);
6005 @@ -239,7 +231,24 @@
6008 value(A) ::= key(B). {
6009 - A = configparser_get_variable(ctx, B);
6010 + if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
6013 + if (NULL != (env = getenv(B->ptr + 4))) {
6015 + ds = data_string_init();
6016 + buffer_append_string(ds->value, env);
6017 + A = (data_unset *)ds;
6021 + fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6024 + } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6025 + fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6029 /* make a dummy so it won't crash */
6030 A = (data_unset *)data_string_init();
6032 ((data_array *)(A))->value = B;
6035 +array(A) ::= LPARAN RPARAN. {
6038 array(A) ::= LPARAN aelements(B) RPARAN. {
6041 --- ../lighttpd-1.4.11/src/connections-glue.c 2005-09-12 10:04:23.000000000 +0300
6042 +++ lighttpd-1.4.12/src/connections-glue.c 2006-07-16 00:26:03.000000000 +0300
6044 case CON_STATE_REQUEST_END: return "req-end";
6045 case CON_STATE_RESPONSE_START: return "resp-start";
6046 case CON_STATE_RESPONSE_END: return "resp-end";
6047 - default: return "(unknown)";
6048 + default: return "(unknown)";
6053 case CON_STATE_REQUEST_END: return "Q";
6054 case CON_STATE_RESPONSE_START: return "s";
6055 case CON_STATE_RESPONSE_END: return "S";
6056 - default: return "x";
6057 + default: return "x";
6061 int connection_set_state(server *srv, connection *con, connection_state_t state) {
6071 --- ../lighttpd-1.4.11/src/connections.c 2006-03-05 22:14:53.000000000 +0200
6072 +++ lighttpd-1.4.12/src/connections.c 2006-07-18 13:03:40.000000000 +0300
6077 -#include <unistd.h>
6082 #include "inet_ntop_cache.h"
6085 -# include <openssl/ssl.h>
6086 -# include <openssl/err.h>
6087 +# include <openssl/ssl.h>
6088 +# include <openssl/err.h>
6091 #ifdef HAVE_SYS_FILIO_H
6095 #include "sys-socket.h"
6096 +#include "sys-files.h"
6103 static connection *connections_get_new_connection(server *srv) {
6104 connections *conns = srv->conns;
6108 if (conns->size == 0) {
6112 } else if (conns->size == conns->used) {
6114 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6117 for (i = conns->used; i < conns->size; i++) {
6118 conns->ptr[i] = connection_init(srv);
6122 connection_reset(srv, conns->ptr[conns->used]);
6124 - fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6125 - for (i = 0; i < conns->used + 1; i++) {
6126 - fprintf(stderr, "%d ", conns->ptr[i]->fd);
6128 - fprintf(stderr, "\n");
6132 conns->ptr[conns->used]->ndx = conns->used;
6133 return conns->ptr[conns->used++];
6135 @@ -77,263 +70,134 @@
6137 connections *conns = srv->conns;
6141 if (con == NULL) return -1;
6144 if (-1 == con->ndx) return -1;
6150 /* not last element */
6153 if (i != conns->used - 1) {
6154 temp = conns->ptr[i];
6155 conns->ptr[i] = conns->ptr[conns->used - 1];
6156 conns->ptr[conns->used - 1] = temp;
6159 conns->ptr[i]->ndx = i;
6160 conns->ptr[conns->used - 1]->ndx = -1;
6169 - fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6170 - for (i = 0; i < conns->used; i++) {
6171 - fprintf(stderr, "%d ", conns->ptr[i]->fd);
6173 - fprintf(stderr, "\n");
6179 int connection_close(server *srv, connection *con) {
6181 server_socket *srv_sock = con->srv_socket;
6186 if (srv_sock->is_ssl) {
6187 - if (con->ssl) SSL_free(con->ssl);
6189 + if (con->sock->ssl) SSL_free(con->sock->ssl);
6190 + con->sock->ssl = NULL;
6194 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6195 - fdevent_unregister(srv->ev, con->fd);
6197 - if (closesocket(con->fd)) {
6198 - log_error_write(srv, __FILE__, __LINE__, "sds",
6199 - "(warning) close:", con->fd, strerror(errno));
6202 - if (close(con->fd)) {
6204 + fdevent_event_del(srv->ev, con->sock);
6205 + fdevent_unregister(srv->ev, con->sock);
6207 + if (closesocket(con->sock->fd)) {
6208 log_error_write(srv, __FILE__, __LINE__, "sds",
6209 - "(warning) close:", con->fd, strerror(errno));
6210 + "(warning) close:", con->sock->fd, strerror(errno));
6217 - log_error_write(srv, __FILE__, __LINE__, "sd",
6218 - "closed()", con->fd);
6222 connection_del(srv, con);
6223 connection_set_state(srv, con, CON_STATE_CONNECT);
6230 static void dump_packet(const unsigned char *data, size_t len) {
6234 if (len == 0) return;
6237 for (i = 0; i < len; i++) {
6238 if (i % 16 == 0) fprintf(stderr, " ");
6241 fprintf(stderr, "%02x ", data[i]);
6244 if ((i + 1) % 16 == 0) {
6245 fprintf(stderr, " ");
6246 for (j = 0; j <= i % 16; j++) {
6250 if (i-15+j >= len) break;
6256 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6260 fprintf(stderr, "\n");
6265 if (len % 16 != 0) {
6266 for (j = i % 16; j < 16; j++) {
6267 fprintf(stderr, " ");
6271 fprintf(stderr, " ");
6272 for (j = i & ~0xf; j < len; j++) {
6277 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6279 fprintf(stderr, "\n");
6284 -static int connection_handle_read(server *srv, connection *con) {
6289 - server_socket *srv_sock = con->srv_socket;
6292 - b = chunkqueue_get_append_buffer(con->read_queue);
6293 - buffer_prepare_copy(b, 4096);
6296 - if (srv_sock->is_ssl) {
6297 - len = SSL_read(con->ssl, b->ptr, b->size - 1);
6299 - if (ioctl(con->fd, FIONREAD, &toread)) {
6300 - log_error_write(srv, __FILE__, __LINE__, "sd",
6301 - "unexpected end-of-file:",
6305 - buffer_prepare_copy(b, toread);
6306 +static network_status_t connection_handle_read(server *srv, connection *con) {
6307 + off_t oldlen, newlen;
6309 - len = read(con->fd, b->ptr, b->size - 1);
6311 -#elif defined(__WIN32)
6312 - len = recv(con->fd, b->ptr, b->size - 1, 0);
6314 - if (ioctl(con->fd, FIONREAD, &toread)) {
6315 - log_error_write(srv, __FILE__, __LINE__, "sd",
6316 - "unexpected end-of-file:",
6320 - buffer_prepare_copy(b, toread);
6321 + oldlen = chunkqueue_length(con->read_queue);
6323 - len = read(con->fd, b->ptr, b->size - 1);
6327 + switch(network_read_chunkqueue(srv, con, con->read_queue)) {
6328 + case NETWORK_STATUS_SUCCESS:
6330 + case NETWORK_STATUS_WAIT_FOR_EVENT:
6331 + con->is_readable = 0;
6332 + return NETWORK_STATUS_WAIT_FOR_EVENT;
6333 + case NETWORK_STATUS_INTERRUPTED:
6334 + con->is_readable = 1;
6335 + return NETWORK_STATUS_WAIT_FOR_EVENT;
6336 + case NETWORK_STATUS_CONNECTION_CLOSE:
6338 + con->is_readable = 0;
6339 + return NETWORK_STATUS_CONNECTION_CLOSE;
6340 + case NETWORK_STATUS_FATAL_ERROR:
6341 con->is_readable = 0;
6344 - if (srv_sock->is_ssl) {
6347 - switch ((r = SSL_get_error(con->ssl, len))) {
6348 - case SSL_ERROR_WANT_READ:
6350 - case SSL_ERROR_SYSCALL:
6352 - * man SSL_get_error()
6354 - * SSL_ERROR_SYSCALL
6355 - * Some I/O error occurred. The OpenSSL error queue may contain more
6356 - * information on the error. If the error queue is empty (i.e.
6357 - * ERR_get_error() returns 0), ret can be used to find out more about
6358 - * the error: If ret == 0, an EOF was observed that violates the
6359 - * protocol. If ret == -1, the underlying BIO reported an I/O error
6360 - * (for socket I/O on Unix systems, consult errno for details).
6363 - while((ssl_err = ERR_get_error())) {
6364 - /* get all errors from the error-queue */
6365 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
6366 - r, ERR_error_string(ssl_err, NULL));
6371 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
6378 - case SSL_ERROR_ZERO_RETURN:
6379 - /* clean shutdown on the remote side */
6382 - /* FIXME: later */
6385 - /* fall thourgh */
6387 - while((ssl_err = ERR_get_error())) {
6388 - /* get all errors from the error-queue */
6389 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
6390 - r, ERR_error_string(ssl_err, NULL));
6395 - if (errno == EAGAIN) return 0;
6396 - if (errno == EINTR) {
6397 - /* we have been interrupted before we could read */
6398 - con->is_readable = 1;
6402 - if (errno != ECONNRESET) {
6403 - /* expected for keep-alive */
6404 - log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6408 - if (errno == EAGAIN) return 0;
6409 - if (errno == EINTR) {
6410 - /* we have been interrupted before we could read */
6411 - con->is_readable = 1;
6415 - if (errno != ECONNRESET) {
6416 - /* expected for keep-alive */
6417 - log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6420 connection_set_state(srv, con, CON_STATE_ERROR);
6423 - } else if (len == 0) {
6424 - con->is_readable = 0;
6425 - /* the other end close the connection -> KEEP-ALIVE */
6426 + return NETWORK_STATUS_FATAL_ERROR;
6433 + newlen = chunkqueue_length(con->read_queue);
6436 - } else if ((size_t)len < b->size - 1) {
6437 - /* we got less then expected, wait for the next fd-event */
6439 - con->is_readable = 0;
6443 - b->ptr[b->used++] = '\0';
6445 - con->bytes_read += len;
6447 - dump_packet(b->ptr, len);
6451 + con->bytes_read += (newlen - oldlen);
6453 + return NETWORK_STATUS_SUCCESS;
6456 static int connection_handle_write_prepare(server *srv, connection *con) {
6458 case HTTP_METHOD_GET:
6459 case HTTP_METHOD_POST:
6460 case HTTP_METHOD_HEAD:
6462 case HTTP_METHOD_PUT:
6463 case HTTP_METHOD_MKCOL:
6464 case HTTP_METHOD_DELETE:
6465 @@ -350,12 +215,14 @@
6466 case HTTP_METHOD_MOVE:
6467 case HTTP_METHOD_PROPFIND:
6468 case HTTP_METHOD_PROPPATCH:
6469 + case HTTP_METHOD_LOCK:
6470 + case HTTP_METHOD_UNLOCK:
6472 case HTTP_METHOD_OPTIONS:
6474 * 400 is coming from the request-parser BEFORE uri.path is set
6475 - * 403 is from the response handler when noone else catched it
6477 + * 403 is from the response handler when noone else catched it
6480 if (con->uri.path->used &&
6481 con->uri.path->ptr[0] != '*') {
6482 @@ -381,55 +248,60 @@
6488 if (con->http_status == 0) {
6489 con->http_status = 403;
6493 switch(con->http_status) {
6494 case 400: /* class: header + custom body */
6512 if (con->mode != DIRECT) break;
6515 con->file_finished = 0;
6518 buffer_reset(con->physical.path);
6521 /* try to send static errorfile */
6522 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6523 stat_cache_entry *sce = NULL;
6526 buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6527 buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6530 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6531 con->file_finished = 1;
6534 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6535 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6539 - if (!con->file_finished) {
6541 + if (!con->file_finished) {
6545 buffer_reset(con->physical.path);
6548 con->file_finished = 1;
6549 b = chunkqueue_get_append_buffer(con->write_queue);
6552 /* build default error-page */
6553 - buffer_copy_string(b,
6554 + buffer_copy_string(b,
6555 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6556 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6557 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6559 buffer_append_long(b, con->http_status);
6560 buffer_append_string(b, " - ");
6561 buffer_append_string(b, get_http_status_name(con->http_status));
6564 buffer_append_string(b,
6567 @@ -448,12 +320,12 @@
6568 buffer_append_long(b, con->http_status);
6569 buffer_append_string(b, " - ");
6570 buffer_append_string(b, get_http_status_name(con->http_status));
6572 - buffer_append_string(b,"</h1>\n"
6574 + buffer_append_string(b,"</h1>\n"
6580 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6583 @@ -463,10 +335,10 @@
6589 case 206: /* write_queue is already prepared */
6590 con->file_finished = 1;
6594 case 205: /* class: header only */
6596 @@ -474,19 +346,19 @@
6597 /* disable chunked encoding again as we have no body */
6598 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6599 chunkqueue_reset(con->write_queue);
6602 con->file_finished = 1;
6608 if (con->file_finished) {
6609 - /* we have all the content and chunked encoding is not used, set a content-length */
6611 - if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6612 + /* we have all the content and chunked encoding is not used, set a content-length */
6614 + if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6615 (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6616 buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6619 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6622 @@ -495,77 +367,79 @@
6623 ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6624 con->keep_alive = 0;
6628 if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6629 /* (f)cgi did'nt send Connection: header
6634 if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6635 (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6636 /* without content_length, no keep-alive */
6639 con->keep_alive = 0;
6642 /* a subrequest disable keep-alive although the client wanted it */
6643 if (con->keep_alive && !con->response.keep_alive) {
6644 con->keep_alive = 0;
6647 /* FIXME: we have to drop the Connection: Header from the subrequest */
6653 if (con->request.http_method == HTTP_METHOD_HEAD) {
6654 chunkqueue_reset(con->write_queue);
6657 http_response_write_header(srv, con);
6663 static int connection_handle_write(server *srv, connection *con) {
6664 switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6666 + case NETWORK_STATUS_SUCCESS:
6667 if (con->file_finished) {
6668 connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6669 joblist_append(srv, con);
6672 - case -1: /* error on our side */
6673 + case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
6674 log_error_write(srv, __FILE__, __LINE__, "sd",
6675 - "connection closed: write failed on fd", con->fd);
6676 + "connection closed: write failed on fd", con->sock->fd);
6677 connection_set_state(srv, con, CON_STATE_ERROR);
6678 joblist_append(srv, con);
6680 - case -2: /* remote close */
6681 + case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
6682 connection_set_state(srv, con, CON_STATE_ERROR);
6683 joblist_append(srv, con);
6686 + case NETWORK_STATUS_WAIT_FOR_EVENT:
6687 con->is_writable = 0;
6690 /* not finished yet -> WRITE */
6692 + case NETWORK_STATUS_INTERRUPTED:
6693 + con->is_writable = 1;
6695 + case NETWORK_STATUS_UNSET:
6705 connection *connection_init(server *srv) {
6711 con = calloc(1, sizeof(*con));
6715 + con->sock = iosocket_init();
6717 - con->fde_ndx = -1;
6718 con->bytes_written = 0;
6719 con->bytes_read = 0;
6720 con->bytes_header = 0;
6721 @@ -573,32 +447,32 @@
6724 con->x = buffer_init();
6728 CLEAN(request.request_line);
6729 CLEAN(request.request);
6730 CLEAN(request.pathinfo);
6733 CLEAN(request.orig_uri);
6737 CLEAN(uri.authority);
6739 CLEAN(uri.path_raw);
6743 CLEAN(physical.doc_root);
6744 CLEAN(physical.path);
6745 CLEAN(physical.basedir);
6746 CLEAN(physical.rel_path);
6747 CLEAN(physical.etag);
6748 CLEAN(parse_request);
6753 CLEAN(error_handler);
6754 CLEAN(dst_addr_buf);
6758 con->write_queue = chunkqueue_init();
6759 con->read_queue = chunkqueue_init();
6760 @@ -608,26 +482,27 @@
6761 con->request.headers = array_init();
6762 con->response.headers = array_init();
6763 con->environment = array_init();
6766 /* init plugin specific connection structures */
6769 con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
6772 con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
6773 config_setup_connection(srv, con);
6779 void connections_free(server *srv) {
6780 connections *conns = srv->conns;
6785 for (i = 0; i < conns->size; i++) {
6786 connection *con = conns->ptr[i];
6789 connection_reset(srv, con);
6791 + iosocket_free(con->sock);
6793 chunkqueue_free(con->write_queue);
6794 chunkqueue_free(con->read_queue);
6795 chunkqueue_free(con->request_content_queue);
6796 @@ -637,27 +512,27 @@
6799 buffer_free(con->x);
6803 CLEAN(request.request_line);
6804 CLEAN(request.request);
6805 CLEAN(request.pathinfo);
6808 CLEAN(request.orig_uri);
6812 CLEAN(uri.authority);
6814 CLEAN(uri.path_raw);
6818 CLEAN(physical.doc_root);
6819 CLEAN(physical.path);
6820 CLEAN(physical.basedir);
6821 CLEAN(physical.etag);
6822 CLEAN(physical.rel_path);
6823 CLEAN(parse_request);
6828 CLEAN(error_handler);
6829 @@ -665,97 +540,97 @@
6831 free(con->plugin_ctx);
6832 free(con->cond_cache);
6843 int connection_reset(server *srv, connection *con) {
6847 plugins_call_connection_reset(srv, con);
6850 con->is_readable = 1;
6851 con->is_writable = 1;
6852 con->http_status = 0;
6853 con->file_finished = 0;
6854 con->file_started = 0;
6855 con->got_response = 0;
6858 con->parsed_response = 0;
6861 con->bytes_written = 0;
6862 con->bytes_written_cur_second = 0;
6863 con->bytes_read = 0;
6864 con->bytes_header = 0;
6865 con->loops_per_request = 0;
6868 con->request.http_method = HTTP_METHOD_UNSET;
6869 con->request.http_version = HTTP_VERSION_UNSET;
6872 con->request.http_if_modified_since = NULL;
6873 con->request.http_if_none_match = NULL;
6876 con->response.keep_alive = 0;
6877 con->response.content_length = -1;
6878 con->response.transfer_encoding = 0;
6885 if (con->x) buffer_reset(con->x);
6889 CLEAN(request.request_line);
6890 CLEAN(request.pathinfo);
6891 CLEAN(request.request);
6894 CLEAN(request.orig_uri);
6898 CLEAN(uri.authority);
6900 CLEAN(uri.path_raw);
6904 CLEAN(physical.doc_root);
6905 CLEAN(physical.path);
6906 CLEAN(physical.basedir);
6907 CLEAN(physical.rel_path);
6908 CLEAN(physical.etag);
6911 CLEAN(parse_request);
6916 CLEAN(error_handler);
6922 - if (con->x) con->x->used = 0;
6924 + if (con->x) con->x->used = 0;
6930 con->request.x = NULL;
6935 CLEAN(http_content_type);
6937 con->request.content_length = 0;
6940 array_reset(con->request.headers);
6941 array_reset(con->response.headers);
6942 array_reset(con->environment);
6945 chunkqueue_reset(con->write_queue);
6946 chunkqueue_reset(con->request_content_queue);
6948 - /* the plugins should cleanup themself */
6949 + /* the plugins should cleanup themself */
6950 for (i = 0; i < srv->plugins.used; i++) {
6951 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
6952 plugin_data *pd = p->data;
6955 con->plugin_ctx[pd->id] = NULL;
6959 #if COND_RESULT_UNSET
6960 for (i = srv->config_context->used - 1; i >= 0; i --) {
6961 con->cond_cache[i].result = COND_RESULT_UNSET;
6962 @@ -777,56 +652,56 @@
6964 memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
6968 con->header_len = 0;
6969 con->in_error_handler = 0;
6972 config_setup_connection(srv, con);
6980 - * search for \r\n\r\n
6983 + * search for \r\n\r\n
6985 * this is a special 32bit version which is using a sliding window for
6986 - * the comparisions
6988 + * the comparisions
6997 * cmpbuf: abcd != cdef
6998 * cmpbuf: bcde != cdef
6999 * cmpbuf: cdef == cdef -> return &c
7001 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
7003 + * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
7004 * maintain cmpbuf and rnrn
7009 char *buffer_search_rnrn(buffer *b) {
7010 uint32_t cmpbuf, rnrn;
7015 if (b->used < 4) return NULL;
7018 rnrn = ('\r' << 24) | ('\n' << 16) |
7019 ('\r' << 8) | ('\n' << 0);
7022 cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7023 (b->ptr[2] << 8) | (b->ptr[3] << 0);
7027 for (i = 0; i < b->used - 4; i++) {
7028 if (cmpbuf == rnrn) return cp - 4;
7031 cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7038 @@ -840,22 +715,25 @@
7040 chunkqueue *cq = con->read_queue;
7041 chunkqueue *dst_cq = con->request_content_queue;
7044 if (con->is_readable) {
7045 con->read_idle_ts = srv->cur_ts;
7048 switch(connection_handle_read(srv, con)) {
7050 + case NETWORK_STATUS_FATAL_ERROR:
7053 + case NETWORK_STATUS_CONNECTION_CLOSE:
7054 /* remote side closed the connection
7055 * if we still have content, handle it, if not leave here */
7057 if (cq->first == cq->last &&
7058 - cq->first->mem->used == 0) {
7059 + (NULL == cq->first ||
7060 + cq->first->mem->used == 0)) {
7062 /* conn-closed, leave here */
7063 connection_set_state(srv, con, CON_STATE_ERROR);
7069 @@ -891,14 +769,14 @@
7070 /* the last node was empty */
7071 if (c->next == NULL) {
7083 /* nothing to handle */
7084 if (cq->first == NULL) return 0;
7086 @@ -906,25 +784,26 @@
7087 case CON_STATE_READ:
7088 /* prepare con->request.request */
7092 /* check if we need the full package */
7093 if (con->request.request->used == 0) {
7097 b.ptr = c->mem->ptr + c->offset;
7098 b.used = c->mem->used - c->offset;
7101 if (NULL != (h_term = buffer_search_rnrn(&b))) {
7103 * - copy everything incl. the terminator to request.request
7106 - buffer_copy_string_len(con->request.request,
7109 + buffer_copy_string_len(con->request.request,
7111 h_term - b.ptr + 4);
7114 /* the buffer has been read up to the terminator */
7115 c->offset += h_term - b.ptr + 4;
7118 /* not found, copy everything */
7119 buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7120 @@ -932,14 +811,14 @@
7123 /* have to take care of overlapping header terminators */
7126 size_t l = con->request.request->used - 2;
7127 char *s = con->request.request->ptr;
7131 b.ptr = c->mem->ptr + c->offset;
7132 b.used = c->mem->used - c->offset;
7135 if (con->request.request->used - 1 > 3 &&
7139 c->mem->ptr[0] == '\n') {
7140 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7144 h_term = con->request.request->ptr;
7145 } else if (con->request.request->used - 1 > 2 &&
7148 c->mem->ptr[1] == '\n') {
7149 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7153 h_term = con->request.request->ptr;
7154 } else if (con->request.request->used - 1 > 1 &&
7156 @@ -968,17 +847,17 @@
7157 c->mem->ptr[2] == '\n') {
7158 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7162 h_term = con->request.request->ptr;
7163 } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7165 * - copy everything incl. the terminator to request.request
7168 - buffer_append_string_len(con->request.request,
7169 - c->mem->ptr + c->offset,
7171 + buffer_append_string_len(con->request.request,
7172 + c->mem->ptr + c->offset,
7173 c->offset + h_term - b.ptr + 4);
7176 /* the buffer has been read up to the terminator */
7177 c->offset += h_term - b.ptr + 4;
7179 @@ -999,16 +878,16 @@
7180 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7183 - case CON_STATE_READ_POST:
7184 + case CON_STATE_READ_POST:
7185 for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7186 off_t weWant, weHave, toRead;
7189 weWant = con->request.content_length - dst_cq->bytes_in;
7192 assert(c->mem->used);
7195 weHave = c->mem->used - c->offset - 1;
7198 toRead = weHave > weWant ? weWant : weHave;
7200 /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7201 @@ -1017,13 +896,13 @@
7202 /* copy everything to max 1Mb sized tempfiles */
7205 - * if the last chunk is
7206 + * if the last chunk is
7207 * - smaller than 1Mb (size < 1Mb)
7208 * - not read yet (offset == 0)
7211 - * -> create a new chunk
7213 + * -> create a new chunk
7218 @@ -1056,14 +935,14 @@
7219 /* we have a chunk, let's write to it */
7221 if (dst_c->file.fd == -1) {
7222 - /* we don't have file to write to,
7223 + /* we don't have file to write to,
7224 * EACCES might be one reason.
7226 * Instead of sending 500 we send 413 and say the request is too large
7229 log_error_write(srv, __FILE__, __LINE__, "sbs",
7230 - "denying upload as opening to temp-file for upload failed:",
7231 + "denying upload as opening to temp-file for upload failed:",
7232 dst_c->file.name, strerror(errno));
7234 con->http_status = 413; /* Request-Entity too large */
7235 @@ -1074,15 +953,15 @@
7238 if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7239 - /* write failed for some reason ... disk full ? */
7240 + /* write failed for some reason ... disk full ? */
7241 log_error_write(srv, __FILE__, __LINE__, "sbs",
7242 - "denying upload as writing to file failed:",
7243 + "denying upload as writing to file failed:",
7244 dst_c->file.name, strerror(errno));
7247 con->http_status = 413; /* Request-Entity too large */
7248 con->keep_alive = 0;
7249 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7252 close(dst_c->file.fd);
7253 dst_c->file.fd = -1;
7255 @@ -1090,7 +969,7 @@
7258 dst_c->file.length += toRead;
7261 if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7262 /* we read everything, close the chunk */
7263 close(dst_c->file.fd);
7264 @@ -1102,7 +981,7 @@
7265 b = chunkqueue_get_append_buffer(dst_cq);
7266 buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7270 c->offset += toRead;
7271 dst_cq->bytes_in += toRead;
7273 @@ -1111,7 +990,7 @@
7274 if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7275 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7282 @@ -1123,100 +1002,104 @@
7283 handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7284 server *srv = (server *)s;
7285 connection *con = context;
7288 joblist_append(srv, con);
7291 if (revents & FDEVENT_IN) {
7292 con->is_readable = 1;
7294 - log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7297 if (revents & FDEVENT_OUT) {
7298 con->is_writable = 1;
7299 /* we don't need the event twice */
7305 if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7306 /* looks like an error */
7309 /* FIXME: revents = 0x19 still means that we should read from the queue */
7310 if (revents & FDEVENT_HUP) {
7311 if (con->state == CON_STATE_CLOSE) {
7312 con->close_timeout_ts = 0;
7314 /* sigio reports the wrong event here
7316 - * there was no HUP at all
7318 + * there was no HUP at all
7320 #ifdef USE_LINUX_SIGIO
7321 if (srv->ev->in_sigio == 1) {
7322 log_error_write(srv, __FILE__, __LINE__, "sd",
7323 - "connection closed: poll() -> HUP", con->fd);
7324 + "connection closed: poll() -> HUP", con->sock->fd);
7326 connection_set_state(srv, con, CON_STATE_ERROR);
7329 connection_set_state(srv, con, CON_STATE_ERROR);
7334 } else if (revents & FDEVENT_ERR) {
7335 #ifndef USE_LINUX_SIGIO
7336 log_error_write(srv, __FILE__, __LINE__, "sd",
7337 - "connection closed: poll() -> ERR", con->fd);
7339 + "connection closed: poll() -> ERR", con->sock->fd);
7341 connection_set_state(srv, con, CON_STATE_ERROR);
7343 log_error_write(srv, __FILE__, __LINE__, "sd",
7344 "connection closed: poll() -> ???", revents);
7350 if (con->state == CON_STATE_READ ||
7351 con->state == CON_STATE_READ_POST) {
7352 connection_handle_read_state(srv, con);
7354 + * if SSL_read() is not readin in the full packet we won't get
7355 + * a fdevent as the low-level has already fetched everything.
7357 + * we have to call the state-engine to read the rest of the packet
7359 + if (con->is_readable) joblist_append(srv, con);
7363 if (con->state == CON_STATE_WRITE &&
7364 !chunkqueue_is_empty(con->write_queue) &&
7368 if (-1 == connection_handle_write(srv, con)) {
7369 connection_set_state(srv, con, CON_STATE_ERROR);
7372 log_error_write(srv, __FILE__, __LINE__, "ds",
7375 "handle write failed.");
7376 } else if (con->state == CON_STATE_WRITE) {
7377 con->write_request_ts = srv->cur_ts;
7382 if (con->state == CON_STATE_CLOSE) {
7383 /* flush the read buffers */
7386 - if (ioctl(con->fd, FIONREAD, &b)) {
7388 + if (ioctl(con->sock->fd, FIONREAD, &b)) {
7389 log_error_write(srv, __FILE__, __LINE__, "ss",
7390 "ioctl() failed", strerror(errno));
7396 log_error_write(srv, __FILE__, __LINE__, "sdd",
7397 - "CLOSE-read()", con->fd, b);
7399 + "CLOSE-read()", con->sock->fd, b);
7402 - read(con->fd, buf, sizeof(buf));
7403 + read(con->sock->fd, buf, sizeof(buf));
7405 /* nothing to read */
7408 con->close_timeout_ts = 0;
7413 return HANDLER_FINISHED;
7416 @@ -1229,63 +1112,68 @@
7419 /* accept it and register the fd */
7422 cnt_len = sizeof(cnt_addr);
7424 - if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7425 + if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7427 + errno = WSAGetLastError();
7429 if ((errno != EAGAIN) &&
7430 + (errno != EWOULDBLOCK) &&
7432 - log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7433 + log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), srv_socket->sock->fd);
7443 /* ok, we have the connection, register it */
7445 log_error_write(srv, __FILE__, __LINE__, "sd",
7451 con = connections_get_new_connection(srv);
7454 - con->fde_ndx = -1;
7456 + con->sock->fd = cnt;
7457 + con->sock->fde_ndx = -1;
7459 gettimeofday(&(con->start_tv), NULL);
7461 - fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7464 + fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7466 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7469 con->connection_start = srv->cur_ts;
7470 con->dst_addr = cnt_addr;
7471 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
7472 con->srv_socket = srv_socket;
7474 - if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
7476 + if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
7477 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
7478 + connection_close(srv, con);
7482 /* connect FD to SSL */
7483 if (srv_socket->is_ssl) {
7484 - if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
7485 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7486 + if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
7487 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7488 ERR_error_string(ERR_get_error(), NULL));
7490 + connection_close(srv, con);
7494 - SSL_set_accept_state(con->ssl);
7496 + SSL_set_accept_state(con->sock->ssl);
7499 - if (1 != (SSL_set_fd(con->ssl, cnt))) {
7500 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7502 + if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
7503 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7504 ERR_error_string(ERR_get_error(), NULL));
7505 + connection_close(srv, con);
7509 @@ -1300,102 +1188,102 @@
7511 server_socket *srv_sock = con->srv_socket;
7515 if (srv->srvconf.log_state_handling) {
7516 - log_error_write(srv, __FILE__, __LINE__, "sds",
7519 + log_error_write(srv, __FILE__, __LINE__, "sds",
7522 connection_get_state(con->state));
7526 size_t ostate = con->state;
7530 switch (con->state) {
7531 case CON_STATE_REQUEST_START: /* transient */
7532 if (srv->srvconf.log_state_handling) {
7533 - log_error_write(srv, __FILE__, __LINE__, "sds",
7534 - "state for fd", con->fd, connection_get_state(con->state));
7535 + log_error_write(srv, __FILE__, __LINE__, "sds",
7536 + "state for fd", con->sock->fd, connection_get_state(con->state));
7540 con->request_start = srv->cur_ts;
7541 con->read_idle_ts = srv->cur_ts;
7544 con->request_count++;
7545 con->loops_per_request = 0;
7548 connection_set_state(srv, con, CON_STATE_READ);
7552 case CON_STATE_REQUEST_END: /* transient */
7553 if (srv->srvconf.log_state_handling) {
7554 - log_error_write(srv, __FILE__, __LINE__, "sds",
7555 - "state for fd", con->fd, connection_get_state(con->state));
7556 + log_error_write(srv, __FILE__, __LINE__, "sds",
7557 + "state for fd", con->sock->fd, connection_get_state(con->state));
7561 if (http_request_parse(srv, con)) {
7562 /* we have to read some data from the POST request */
7565 connection_set_state(srv, con, CON_STATE_READ_POST);
7571 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7575 case CON_STATE_HANDLE_REQUEST:
7578 * the request is parsed
7581 * decided what to do with the request
7591 if (srv->srvconf.log_state_handling) {
7592 - log_error_write(srv, __FILE__, __LINE__, "sds",
7593 - "state for fd", con->fd, connection_get_state(con->state));
7594 + log_error_write(srv, __FILE__, __LINE__, "sds",
7595 + "state for fd", con->sock->fd, connection_get_state(con->state));
7599 switch (r = http_response_prepare(srv, con)) {
7600 case HANDLER_FINISHED:
7601 if (con->http_status == 404 ||
7602 con->http_status == 403) {
7603 /* 404 error-handler */
7605 - if (con->in_error_handler == 0 &&
7607 + if (con->in_error_handler == 0 &&
7608 (!buffer_is_empty(con->conf.error_handler) ||
7609 !buffer_is_empty(con->error_handler))) {
7610 /* call error-handler */
7613 con->error_handler_saved_status = con->http_status;
7614 con->http_status = 0;
7617 if (buffer_is_empty(con->error_handler)) {
7618 buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
7620 buffer_copy_string_buffer(con->request.uri, con->error_handler);
7622 buffer_reset(con->physical.path);
7625 con->in_error_handler = 1;
7628 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7633 } else if (con->in_error_handler) {
7634 /* error-handler is a 404 */
7637 /* continue as normal, status is the same */
7638 - log_error_write(srv, __FILE__, __LINE__, "sb",
7639 + log_error_write(srv, __FILE__, __LINE__, "sb",
7640 "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
7641 - log_error_write(srv, __FILE__, __LINE__, "sd",
7642 + log_error_write(srv, __FILE__, __LINE__, "sd",
7643 "returning the original status", con->error_handler_saved_status);
7644 - log_error_write(srv, __FILE__, __LINE__, "s",
7645 + log_error_write(srv, __FILE__, __LINE__, "s",
7646 "If this is a rails app: check your production.log");
7647 con->http_status = con->error_handler_saved_status;
7649 @@ -1403,73 +1291,73 @@
7650 /* error-handler is back and has generated content */
7651 /* if Status: was set, take it otherwise use 200 */
7655 if (con->http_status == 0) con->http_status = 200;
7658 /* we have something to send, go on */
7659 connection_set_state(srv, con, CON_STATE_RESPONSE_START);
7661 case HANDLER_WAIT_FOR_FD:
7665 fdwaitqueue_append(srv, con);
7668 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7672 case HANDLER_COMEBACK:
7674 case HANDLER_WAIT_FOR_EVENT:
7675 /* come back here */
7676 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7681 /* something went wrong */
7682 connection_set_state(srv, con, CON_STATE_ERROR);
7685 - log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
7686 + log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->sock->fd, r);
7692 case CON_STATE_RESPONSE_START:
7695 * the decision is done
7696 * - create the HTTP-Response-Header
7702 if (srv->srvconf.log_state_handling) {
7703 - log_error_write(srv, __FILE__, __LINE__, "sds",
7704 - "state for fd", con->fd, connection_get_state(con->state));
7705 + log_error_write(srv, __FILE__, __LINE__, "sds",
7706 + "state for fd", con->sock->fd, connection_get_state(con->state));
7710 if (-1 == connection_handle_write_prepare(srv, con)) {
7711 connection_set_state(srv, con, CON_STATE_ERROR);
7718 connection_set_state(srv, con, CON_STATE_WRITE);
7720 case CON_STATE_RESPONSE_END: /* transient */
7721 /* log the request */
7724 if (srv->srvconf.log_state_handling) {
7725 - log_error_write(srv, __FILE__, __LINE__, "sds",
7726 - "state for fd", con->fd, connection_get_state(con->state));
7727 + log_error_write(srv, __FILE__, __LINE__, "sds",
7728 + "state for fd", con->sock->fd, connection_get_state(con->state));
7732 plugins_call_handle_request_done(srv, con);
7738 if (con->keep_alive) {
7739 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7744 con->request_start = srv->cur_ts;
7745 con->read_idle_ts = srv->cur_ts;
7747 @@ -1482,103 +1370,103 @@
7748 log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
7754 if (srv_sock->is_ssl) {
7755 - switch (SSL_shutdown(con->ssl)) {
7756 + switch (SSL_shutdown(con->sock->ssl)) {
7761 - /* wait for fd-event
7763 + /* wait for fd-event
7765 * FIXME: wait for fdevent and call SSL_shutdown again
7773 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7774 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7775 ERR_error_string(ERR_get_error(), NULL));
7779 connection_close(srv, con);
7786 connection_reset(srv, con);
7790 case CON_STATE_CONNECT:
7791 if (srv->srvconf.log_state_handling) {
7792 - log_error_write(srv, __FILE__, __LINE__, "sds",
7793 - "state for fd", con->fd, connection_get_state(con->state));
7794 + log_error_write(srv, __FILE__, __LINE__, "sds",
7795 + "state for fd", con->sock->fd, connection_get_state(con->state));
7799 chunkqueue_reset(con->read_queue);
7802 con->request_count = 0;
7806 case CON_STATE_CLOSE:
7807 if (srv->srvconf.log_state_handling) {
7808 - log_error_write(srv, __FILE__, __LINE__, "sds",
7809 - "state for fd", con->fd, connection_get_state(con->state));
7810 + log_error_write(srv, __FILE__, __LINE__, "sds",
7811 + "state for fd", con->sock->fd, connection_get_state(con->state));
7815 if (con->keep_alive) {
7816 - if (ioctl(con->fd, FIONREAD, &b)) {
7817 + if (ioctl(con->sock->fd, FIONREAD, &b)) {
7818 log_error_write(srv, __FILE__, __LINE__, "ss",
7819 "ioctl() failed", strerror(errno));
7823 log_error_write(srv, __FILE__, __LINE__, "sdd",
7824 - "CLOSE-read()", con->fd, b);
7826 + "CLOSE-read()", con->sock->fd, b);
7829 - read(con->fd, buf, sizeof(buf));
7830 + read(con->sock->fd, buf, sizeof(buf));
7832 /* nothing to read */
7835 con->close_timeout_ts = 0;
7838 con->close_timeout_ts = 0;
7842 if (srv->cur_ts - con->close_timeout_ts > 1) {
7843 connection_close(srv, con);
7846 if (srv->srvconf.log_state_handling) {
7847 - log_error_write(srv, __FILE__, __LINE__, "sd",
7848 - "connection closed for fd", con->fd);
7849 + log_error_write(srv, __FILE__, __LINE__, "sd",
7850 + "connection closed for fd", con->sock->fd);
7856 case CON_STATE_READ_POST:
7857 case CON_STATE_READ:
7858 if (srv->srvconf.log_state_handling) {
7859 - log_error_write(srv, __FILE__, __LINE__, "sds",
7860 - "state for fd", con->fd, connection_get_state(con->state));
7861 + log_error_write(srv, __FILE__, __LINE__, "sds",
7862 + "state for fd", con->sock->fd, connection_get_state(con->state));
7866 connection_handle_read_state(srv, con);
7868 case CON_STATE_WRITE:
7869 if (srv->srvconf.log_state_handling) {
7870 - log_error_write(srv, __FILE__, __LINE__, "sds",
7871 - "state for fd", con->fd, connection_get_state(con->state));
7872 + log_error_write(srv, __FILE__, __LINE__, "sds",
7873 + "state for fd", con->sock->fd, connection_get_state(con->state));
7877 /* only try to write if we have something in the queue */
7878 if (!chunkqueue_is_empty(con->write_queue)) {
7880 log_error_write(srv, __FILE__, __LINE__, "dsd",
7883 "packets to write:",
7884 con->write_queue->used);
7886 @@ -1586,17 +1474,17 @@
7887 if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
7888 if (-1 == connection_handle_write(srv, con)) {
7889 log_error_write(srv, __FILE__, __LINE__, "ds",
7892 "handle write failed.");
7893 connection_set_state(srv, con, CON_STATE_ERROR);
7894 } else if (con->state == CON_STATE_WRITE) {
7895 con->write_request_ts = srv->cur_ts;
7901 case CON_STATE_ERROR: /* transient */
7904 /* even if the connection was drop we still have to write it to the access log */
7905 if (con->http_status) {
7906 plugins_call_handle_request_done(srv, con);
7907 @@ -1604,28 +1492,28 @@
7909 if (srv_sock->is_ssl) {
7911 - switch ((ret = SSL_shutdown(con->ssl))) {
7912 + switch ((ret = SSL_shutdown(con->sock->ssl))) {
7917 - SSL_shutdown(con->ssl);
7918 + SSL_shutdown(con->sock->ssl);
7921 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7922 - SSL_get_error(con->ssl, ret),
7923 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7924 + SSL_get_error(con->sock->ssl, ret),
7925 ERR_error_string(ERR_get_error(), NULL));
7935 - log_error_write(srv, __FILE__, __LINE__, "sd",
7936 - "emergency exit: direct",
7938 + log_error_write(srv, __FILE__, __LINE__, "sd",
7939 + "emergency exit: direct",
7944 @@ -1639,35 +1527,35 @@
7950 connection_reset(srv, con);
7953 /* close the connection */
7954 if ((con->keep_alive == 1) &&
7955 - (0 == shutdown(con->fd, SHUT_WR))) {
7956 + (0 == shutdown(con->sock->fd, SHUT_WR))) {
7957 con->close_timeout_ts = srv->cur_ts;
7958 connection_set_state(srv, con, CON_STATE_CLOSE);
7961 if (srv->srvconf.log_state_handling) {
7962 - log_error_write(srv, __FILE__, __LINE__, "sd",
7963 - "shutdown for fd", con->fd);
7964 + log_error_write(srv, __FILE__, __LINE__, "sd",
7965 + "shutdown for fd", con->sock->fd);
7968 connection_close(srv, con);
7972 con->keep_alive = 0;
7980 - log_error_write(srv, __FILE__, __LINE__, "sdd",
7981 - "unknown state:", con->fd, con->state);
7983 + log_error_write(srv, __FILE__, __LINE__, "sdd",
7984 + "unknown state:", con->sock->fd, con->state);
7992 } else if (ostate == con->state) {
7993 @@ -1676,33 +1564,33 @@
7996 if (srv->srvconf.log_state_handling) {
7997 - log_error_write(srv, __FILE__, __LINE__, "sds",
8000 + log_error_write(srv, __FILE__, __LINE__, "sds",
8003 connection_get_state(con->state));
8007 switch(con->state) {
8008 case CON_STATE_READ_POST:
8009 case CON_STATE_READ:
8010 case CON_STATE_CLOSE:
8011 - fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
8012 + fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
8014 case CON_STATE_WRITE:
8015 - /* request write-fdevent only if we really need it
8016 + /* request write-fdevent only if we really need it
8017 * - if we have data to write
8018 - * - if the socket is not writable yet
8019 + * - if the socket is not writable yet
8021 - if (!chunkqueue_is_empty(con->write_queue) &&
8022 + if (!chunkqueue_is_empty(con->write_queue) &&
8023 (con->is_writable == 0) &&
8024 (con->traffic_limit_reached == 0)) {
8025 - fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8026 + fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8028 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8029 + fdevent_event_del(srv->ev, con->sock);
8033 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8034 + fdevent_event_del(srv->ev, con->sock);
8038 --- ../lighttpd-1.4.11/src/crc32.h 2005-09-30 20:18:59.000000000 +0300
8039 +++ lighttpd-1.4.12/src/crc32.h 2006-07-16 00:26:04.000000000 +0300
8043 #include <sys/types.h>
8044 +#include <stdlib.h>
8046 #if defined HAVE_STDINT_H
8049 #include <inttypes.h>
8053 +#define uint32_t unsigned __int32
8056 uint32_t generate_crc32c(char *string, size_t length);
8059 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8060 +++ lighttpd-1.4.12/src/data_array.c 2006-07-16 00:26:04.000000000 +0300
8063 static void data_array_free(data_unset *d) {
8064 data_array *ds = (data_array *)d;
8067 buffer_free(ds->key);
8068 array_free(ds->value);
8074 static void data_array_reset(data_unset *d) {
8075 data_array *ds = (data_array *)d;
8078 /* reused array elements */
8079 buffer_reset(ds->key);
8080 array_reset(ds->value);
8092 data_array *data_array_init(void) {
8096 ds = calloc(1, sizeof(*ds));
8099 ds->key = buffer_init();
8100 ds->value = array_init();
8103 ds->copy = data_array_copy;
8104 ds->free = data_array_free;
8105 ds->reset = data_array_reset;
8106 ds->insert_dup = data_array_insert_dup;
8107 ds->print = data_array_print;
8108 ds->type = TYPE_ARRAY;
8113 --- ../lighttpd-1.4.11/src/data_config.c 2005-08-17 12:53:19.000000000 +0300
8114 +++ lighttpd-1.4.12/src/data_config.c 2006-07-16 00:26:03.000000000 +0300
8117 static void data_config_free(data_unset *d) {
8118 data_config *ds = (data_config *)d;
8121 buffer_free(ds->key);
8122 buffer_free(ds->op);
8123 buffer_free(ds->comp_key);
8126 array_free(ds->value);
8127 array_free(ds->childs);
8130 if (ds->string) buffer_free(ds->string);
8132 if (ds->regex) pcre_free(ds->regex);
8133 if (ds->regex_study) pcre_free(ds->regex_study);
8140 static void data_config_reset(data_unset *d) {
8141 data_config *ds = (data_config *)d;
8144 /* reused array elements */
8145 buffer_reset(ds->key);
8146 buffer_reset(ds->comp_key);
8149 static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8160 array *a = (array *)ds->value;
8165 if (0 == ds->context_ndx) {
8166 fprintf(stderr, "config {\n");
8168 @@ -117,22 +117,22 @@
8170 data_config *data_config_init(void) {
8174 ds = calloc(1, sizeof(*ds));
8177 ds->key = buffer_init();
8178 ds->op = buffer_init();
8179 ds->comp_key = buffer_init();
8180 ds->value = array_init();
8181 ds->childs = array_init();
8182 ds->childs->is_weakref = 1;
8185 ds->copy = data_config_copy;
8186 ds->free = data_config_free;
8187 ds->reset = data_config_reset;
8188 ds->insert_dup = data_config_insert_dup;
8189 ds->print = data_config_print;
8190 ds->type = TYPE_CONFIG;
8195 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
8196 +++ lighttpd-1.4.12/src/data_count.c 2006-07-16 00:26:03.000000000 +0300
8199 static void data_count_free(data_unset *d) {
8200 data_count *ds = (data_count *)d;
8203 buffer_free(ds->key);
8209 static void data_count_reset(data_unset *d) {
8210 data_count *ds = (data_count *)d;
8213 buffer_reset(ds->key);
8219 static int data_count_insert_dup(data_unset *dst, data_unset *src) {
8220 data_count *ds_dst = (data_count *)dst;
8221 data_count *ds_src = (data_count *)src;
8224 ds_dst->count += ds_src->count;
8233 static void data_count_print(const data_unset *d, int depth) {
8234 data_count *ds = (data_count *)d;
8238 fprintf(stderr, "count(%d)", ds->count);
8242 data_count *data_count_init(void) {
8246 ds = calloc(1, sizeof(*ds));
8249 ds->key = buffer_init();
8253 ds->copy = data_count_copy;
8254 ds->free = data_count_free;
8255 ds->reset = data_count_reset;
8256 ds->insert_dup = data_count_insert_dup;
8257 ds->print = data_count_print;
8258 ds->type = TYPE_COUNT;
8263 --- ../lighttpd-1.4.11/src/data_fastcgi.c 2005-08-23 17:36:12.000000000 +0300
8264 +++ lighttpd-1.4.12/src/data_fastcgi.c 2006-07-16 00:26:04.000000000 +0300
8267 static void data_fastcgi_free(data_unset *d) {
8268 data_fastcgi *ds = (data_fastcgi *)d;
8271 buffer_free(ds->key);
8272 buffer_free(ds->host);
8278 static void data_fastcgi_reset(data_unset *d) {
8279 data_fastcgi *ds = (data_fastcgi *)d;
8282 buffer_reset(ds->key);
8283 buffer_reset(ds->host);
8288 static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
8297 static void data_fastcgi_print(const data_unset *d, int depth) {
8298 data_fastcgi *ds = (data_fastcgi *)d;
8302 fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
8306 data_fastcgi *data_fastcgi_init(void) {
8310 ds = calloc(1, sizeof(*ds));
8313 ds->key = buffer_init();
8314 ds->host = buffer_init();
8316 ds->is_disabled = 0;
8319 ds->copy = data_fastcgi_copy;
8320 ds->free = data_fastcgi_free;
8321 ds->reset = data_fastcgi_reset;
8322 ds->insert_dup = data_fastcgi_insert_dup;
8323 ds->print = data_fastcgi_print;
8324 ds->type = TYPE_FASTCGI;
8329 --- ../lighttpd-1.4.11/src/data_integer.c 2005-08-23 17:36:12.000000000 +0300
8330 +++ lighttpd-1.4.12/src/data_integer.c 2006-07-16 00:26:03.000000000 +0300
8333 static void data_integer_free(data_unset *d) {
8334 data_integer *ds = (data_integer *)d;
8337 buffer_free(ds->key);
8343 static void data_integer_reset(data_unset *d) {
8344 data_integer *ds = (data_integer *)d;
8347 /* reused integer elements */
8348 buffer_reset(ds->key);
8352 static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
8364 data_integer *data_integer_init(void) {
8368 ds = calloc(1, sizeof(*ds));
8371 ds->key = buffer_init();
8375 ds->copy = data_integer_copy;
8376 ds->free = data_integer_free;
8377 ds->reset = data_integer_reset;
8378 ds->insert_dup = data_integer_insert_dup;
8379 ds->print = data_integer_print;
8380 ds->type = TYPE_INTEGER;
8385 --- ../lighttpd-1.4.11/src/data_string.c 2005-08-23 17:36:12.000000000 +0300
8386 +++ lighttpd-1.4.12/src/data_string.c 2006-07-16 00:26:04.000000000 +0300
8389 static void data_string_free(data_unset *d) {
8390 data_string *ds = (data_string *)d;
8393 buffer_free(ds->key);
8394 buffer_free(ds->value);
8400 static void data_string_reset(data_unset *d) {
8401 data_string *ds = (data_string *)d;
8404 /* reused array elements */
8405 buffer_reset(ds->key);
8406 buffer_reset(ds->value);
8408 static int data_string_insert_dup(data_unset *dst, data_unset *src) {
8409 data_string *ds_dst = (data_string *)dst;
8410 data_string *ds_src = (data_string *)src;
8413 if (ds_dst->value->used) {
8414 buffer_append_string(ds_dst->value, ", ");
8415 buffer_append_string_buffer(ds_dst->value, ds_src->value);
8417 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8427 static int data_response_insert_dup(data_unset *dst, data_unset *src) {
8428 data_string *ds_dst = (data_string *)dst;
8429 data_string *ds_src = (data_string *)src;
8432 if (ds_dst->value->used) {
8433 buffer_append_string(ds_dst->value, "\r\n");
8434 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
8437 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8449 data_string *data_string_init(void) {
8453 ds = calloc(1, sizeof(*ds));
8457 ds->key = buffer_init();
8458 ds->value = buffer_init();
8461 ds->copy = data_string_copy;
8462 ds->free = data_string_free;
8463 ds->reset = data_string_reset;
8464 ds->insert_dup = data_string_insert_dup;
8465 ds->print = data_string_print;
8466 ds->type = TYPE_STRING;
8472 data_string *data_response_init(void) {
8476 ds = data_string_init();
8477 ds->insert_dup = data_response_insert_dup;
8482 --- ../lighttpd-1.4.11/src/etag.c 2005-08-11 01:26:40.000000000 +0300
8483 +++ lighttpd-1.4.12/src/etag.c 2006-07-18 13:03:40.000000000 +0300
8487 int etag_is_equal(buffer *etag, const char *matches) {
8488 - if (0 == strcmp(etag->ptr, matches)) return 1;
8489 + if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
8494 buffer_append_off_t(etag, st->st_size);
8495 buffer_append_string_len(etag, CONST_STR_LEN("-"));
8496 buffer_append_long(etag, st->st_mtime);
8502 int etag_mutate(buffer *mut, buffer *etag) {
8506 for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
8510 buffer_copy_string_len(mut, CONST_STR_LEN("\""));
8511 buffer_append_long(mut, h);
8512 buffer_append_string_len(mut, CONST_STR_LEN("\""));
8517 --- ../lighttpd-1.4.11/src/etag.h 2005-08-11 01:26:40.000000000 +0300
8518 +++ lighttpd-1.4.12/src/etag.h 2006-07-16 00:26:03.000000000 +0300
8521 #include <sys/types.h>
8522 #include <sys/stat.h>
8523 -#include <unistd.h>
8527 int etag_is_equal(buffer *etag, const char *matches);
8528 int etag_create(buffer *etag, struct stat *st);
8529 int etag_mutate(buffer *mut, buffer *etag);
8534 --- ../lighttpd-1.4.11/src/fastcgi.h 2005-08-11 01:26:40.000000000 +0300
8535 +++ lighttpd-1.4.12/src/fastcgi.h 2006-07-16 00:26:03.000000000 +0300
8541 * Defines for the FastCGI protocol.
8546 - unsigned char type;
8547 + unsigned char type;
8548 unsigned char reserved[7];
8549 } FCGI_UnknownTypeBody;
8551 --- ../lighttpd-1.4.11/src/fdevent.c 2005-11-15 10:51:05.000000000 +0200
8552 +++ lighttpd-1.4.12/src/fdevent.c 2006-07-18 13:03:40.000000000 +0300
8555 #include "settings.h"
8557 -#include <unistd.h>
8561 @@ -11,60 +10,116 @@
8563 #include "fdevent.h"
8567 +#include "sys-socket.h"
8569 +fdevent_revent *fdevent_revent_init(void) {
8570 + STRUCT_INIT(fdevent_revent, revent);
8575 +void fdevent_revent_free(fdevent_revent *revent) {
8576 + if (!revent) return;
8581 +fdevent_revents *fdevent_revents_init(void) {
8582 + STRUCT_INIT(fdevent_revents, revents);
8587 +void fdevent_revents_reset(fdevent_revents *revents) {
8588 + if (!revents) return;
8590 + revents->used = 0;
8593 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
8594 + fdevent_revent *revent;
8596 + if (revents->used == revents->size) {
8597 + /* resize the events-array */
8598 + revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
8599 + revents->ptr[revents->size++] = fdevent_revent_init();
8602 + revent = revents->ptr[revents->used++];
8604 + revent->revents = events;
8607 +void fdevent_revents_free(fdevent_revents *revents) {
8610 + if (!revents) return;
8612 + if (revents->size) {
8613 + for (i = 0; i < revents->size; i++) {
8614 + fdevent_revent_free(revents->ptr[i]);
8617 + free(revents->ptr);
8622 fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
8626 ev = calloc(1, sizeof(*ev));
8627 ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
8628 ev->maxfds = maxfds;
8632 case FDEVENT_HANDLER_POLL:
8633 if (0 != fdevent_poll_init(ev)) {
8634 - fprintf(stderr, "%s.%d: event-handler poll failed\n",
8635 + fprintf(stderr, "%s.%d: event-handler poll failed\n",
8636 __FILE__, __LINE__);
8642 case FDEVENT_HANDLER_SELECT:
8643 if (0 != fdevent_select_init(ev)) {
8644 - fprintf(stderr, "%s.%d: event-handler select failed\n",
8645 + fprintf(stderr, "%s.%d: event-handler select failed\n",
8646 __FILE__, __LINE__);
8650 case FDEVENT_HANDLER_LINUX_RTSIG:
8651 if (0 != fdevent_linux_rtsig_init(ev)) {
8652 - fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8653 + fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8654 __FILE__, __LINE__);
8658 case FDEVENT_HANDLER_LINUX_SYSEPOLL:
8659 if (0 != fdevent_linux_sysepoll_init(ev)) {
8660 - fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8661 + fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8662 __FILE__, __LINE__);
8666 case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
8667 if (0 != fdevent_solaris_devpoll_init(ev)) {
8668 - fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8669 + fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8670 __FILE__, __LINE__);
8674 case FDEVENT_HANDLER_FREEBSD_KQUEUE:
8675 if (0 != fdevent_freebsd_kqueue_init(ev)) {
8676 - fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8677 + fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8678 __FILE__, __LINE__);
8683 - fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8684 + fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8685 __FILE__, __LINE__);
8688 @@ -75,28 +130,29 @@
8689 void fdevent_free(fdevents *ev) {
8694 if (ev->free) ev->free(ev);
8697 for (i = 0; i < ev->maxfds; i++) {
8698 if (ev->fdarray[i]) free(ev->fdarray[i]);
8706 int fdevent_reset(fdevents *ev) {
8707 if (ev->reset) return ev->reset(ev);
8713 fdnode *fdnode_init() {
8717 fdn = calloc(1, sizeof(*fdn));
8723 @@ -104,48 +160,40 @@
8727 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
8728 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
8732 fdn = fdnode_init();
8733 fdn->handler = handler;
8735 + fdn->fd = sock->fd;
8738 - ev->fdarray[fd] = fdn;
8740 + ev->fdarray[sock->fd] = fdn;
8745 -int fdevent_unregister(fdevents *ev, int fd) {
8746 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
8749 - fdn = ev->fdarray[fd];
8751 + fdn = ev->fdarray[sock->fd];
8755 - ev->fdarray[fd] = NULL;
8758 + ev->fdarray[sock->fd] = NULL;
8763 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
8764 - int fde = fde_ndx ? *fde_ndx : -1;
8766 - if (ev->event_del) fde = ev->event_del(ev, fde, fd);
8768 - if (fde_ndx) *fde_ndx = fde;
8770 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
8771 + if (ev->event_del) ev->event_del(ev, sock);
8776 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
8777 - int fde = fde_ndx ? *fde_ndx : -1;
8779 - if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
8781 - if (fde_ndx) *fde_ndx = fde;
8783 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
8784 + if (ev->event_add) ev->event_add(ev, sock, events);
8789 @@ -154,49 +202,41 @@
8790 return ev->poll(ev, timeout_ms);
8793 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
8794 - if (ev->event_get_revent == NULL) SEGFAULT();
8796 - return ev->event_get_revent(ev, ndx);
8798 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
8801 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
8802 - if (ev->event_get_fd == NULL) SEGFAULT();
8804 - return ev->event_get_fd(ev, ndx);
8806 + if (ev->get_revents == NULL) SEGFAULT();
8808 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
8809 - if (ev->fdarray[fd] == NULL) SEGFAULT();
8810 - if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8812 - return ev->fdarray[fd]->handler;
8814 + fdevent_revents_reset(revents);
8816 -void * fdevent_get_context(fdevents *ev, int fd) {
8817 - if (ev->fdarray[fd] == NULL) SEGFAULT();
8818 - if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8820 - return ev->fdarray[fd]->ctx;
8821 + ev->get_revents(ev, event_count, revents);
8823 + /* patch the event handlers */
8824 + for (i = 0; i < event_count; i++) {
8825 + fdevent_revent *r = revents->ptr[i];
8827 + r->handler = ev->fdarray[r->fd]->handler;
8828 + r->context = ev->fdarray[r->fd]->ctx;
8834 -int fdevent_fcntl_set(fdevents *ev, int fd) {
8835 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
8840 /* close fd on exec (cgi) */
8841 - fcntl(fd, F_SETFD, FD_CLOEXEC);
8842 + fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
8844 - if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
8846 - return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
8847 + if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
8849 + return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
8850 +#elif defined _WIN32
8851 + return ioctlsocket(sock->fd, FIONBIO, &i);
8858 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
8859 - if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
8864 --- ../lighttpd-1.4.11/src/fdevent.h 2005-09-27 11:26:33.000000000 +0300
8865 +++ lighttpd-1.4.12/src/fdevent.h 2006-07-18 13:03:40.000000000 +0300
8867 #include "settings.h"
8870 +#include "iosocket.h"
8871 +#include "array-static.h"
8873 /* select event-system */
8875 #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
8877 # include <sys/epoll.h>
8880 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8881 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8882 * under /usr/include/sys/ */
8883 #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
8889 # include <sys/poll.h>
8891 # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
8893 # include <signal.h>
8898 +# define HAVE_SELECT
8900 #if defined HAVE_SELECT
8903 # include <winsock2.h>
8907 #define FDEVENT_HUP BV(4)
8908 #define FDEVENT_NVAL BV(5)
8910 -typedef enum { FD_EVENT_TYPE_UNSET = -1,
8911 - FD_EVENT_TYPE_CONNECTION,
8912 - FD_EVENT_TYPE_FCGI_CONNECTION,
8913 - FD_EVENT_TYPE_DIRWATCH,
8914 - FD_EVENT_TYPE_CGI_CONNECTION
8915 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
8916 + FD_EVENT_TYPE_CONNECTION,
8917 + FD_EVENT_TYPE_FCGI_CONNECTION,
8918 + FD_EVENT_TYPE_DIRWATCH,
8919 + FD_EVENT_TYPE_CGI_CONNECTION
8922 -typedef enum { FDEVENT_HANDLER_UNSET,
8923 +typedef enum { FDEVENT_HANDLER_UNSET,
8924 FDEVENT_HANDLER_SELECT,
8925 FDEVENT_HANDLER_POLL,
8926 FDEVENT_HANDLER_LINUX_RTSIG,
8930 * a mapping from fd to connection structure
8935 int fd; /**< the fd */
8936 @@ -96,43 +101,51 @@
8940 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
8954 + fdevent_handler handler;
8958 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
8961 * array of unused fd's
8966 typedef struct _fdnode {
8967 - fdevent_handler handler;
8971 + fdevent_handler handler; /* who handles the events for this fd */
8972 + void *ctx; /* opaque pointer which is passed as 3rd parameter to the handler */
8975 struct _fdnode *prev, *next;
8987 * fd-event handler for select(), poll() and rt-signals on Linux 2.4
8991 typedef struct fdevents {
8992 fdevent_handler_t type;
8996 + fdnode **fdarray; /* a list of fdnodes */
9000 #ifdef USE_LINUX_SIGIO
9003 @@ -146,21 +159,21 @@
9006 struct pollfd *pollfds;
9017 fd_set select_write;
9018 fd_set select_error;
9021 fd_set select_set_read;
9022 fd_set select_set_write;
9023 fd_set select_set_error;
9028 #ifdef USE_SOLARIS_DEVPOLL
9029 @@ -177,16 +190,13 @@
9031 int (*reset)(struct fdevents *ev);
9032 void (*free)(struct fdevents *ev);
9034 - int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9035 - int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9036 - int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9037 - int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9039 - int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9042 + int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9043 + int (*event_del)(struct fdevents *ev, iosocket *sock);
9044 + int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9046 int (*poll)(struct fdevents *ev, int timeout_ms);
9049 int (*fcntl_set)(struct fdevents *ev, int fd);
9052 @@ -194,22 +204,44 @@
9053 int fdevent_reset(fdevents *ev);
9054 void fdevent_free(fdevents *ev);
9056 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9057 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9058 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9059 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9060 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9061 -void * fdevent_get_context(fdevents *ev, int fd);
9063 + * call the plugin for the number of available events
9065 +int fdevent_poll(fdevents *ev, int timeout_ms);
9067 + * get all available events
9069 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9071 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9073 + * add or remove a fd to the handled-pool
9075 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9076 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9078 -int fdevent_poll(fdevents *ev, int timeout_ms);
9080 + * add a event to a registered fd
9082 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9083 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9086 + * set non-blocking
9088 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9090 +fdevent_revents *fdevent_revents_init(void);
9091 +void fdevent_revents_reset(fdevent_revents *revents);
9092 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9093 +void fdevent_revents_free(fdevent_revents *revents);
9095 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9096 -int fdevent_unregister(fdevents *ev, int fd);
9097 +fdevent_revent *fdevent_revent_init(void);
9098 +void fdevent_revent_free(fdevent_revent *revent);
9100 -int fdevent_fcntl_set(fdevents *ev, int fd);
9105 int fdevent_select_init(fdevents *ev);
9106 int fdevent_poll_init(fdevents *ev);
9107 int fdevent_linux_rtsig_init(fdevents *ev);
9108 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c 2005-09-01 10:46:24.000000000 +0300
9109 +++ lighttpd-1.4.12/src/fdevent_freebsd_kqueue.c 2006-07-16 00:26:03.000000000 +0300
9111 #include <sys/types.h>
9113 -#include <unistd.h>
9132 ret = kevent(ev->kq_fd,
9141 if (filter == EVFILT_READ) {
9142 bitset_set_bit(ev->kq_bevents, fd);
9145 } else if (e == EVFILT_WRITE) {
9146 events |= FDEVENT_OUT;
9150 e = ev->kq_results[ndx].flags;
9153 @@ -152,10 +151,10 @@
9154 if (-1 == (ev->kq_fd = kqueue())) {
9155 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9156 __FILE__, __LINE__, strerror(errno));
9167 if (-1 == (ev->kq_fd = kqueue())) {
9168 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9169 __FILE__, __LINE__, strerror(errno));
9175 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c 2005-11-21 19:56:11.000000000 +0200
9176 +++ lighttpd-1.4.12/src/fdevent_linux_rtsig.c 2006-07-18 13:03:40.000000000 +0300
9178 #include <sys/types.h>
9180 -#include <unistd.h>
9185 #include "fdevent.h"
9186 #include "settings.h"
9188 +#include "sys-process.h"
9191 #ifdef USE_LINUX_SIGIO
9192 static void fdevent_linux_rtsig_free(fdevents *ev) {
9197 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
9198 - if (fde_ndx < 0) return -1;
9200 - if ((size_t)fde_ndx >= ev->used) {
9201 - fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
9202 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
9203 + if (sock->fde_ndx < 0) return -1;
9205 + if ((size_t)sock->fde_ndx >= ev->used) {
9206 + TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
9210 - if (ev->pollfds[fde_ndx].fd == fd) {
9211 - size_t k = fde_ndx;
9214 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9215 + size_t k = sock->fde_ndx;
9217 ev->pollfds[k].fd = -1;
9219 - bitset_clear_bit(ev->sigbset, fd);
9221 + bitset_clear_bit(ev->sigbset, sock->fd);
9223 if (ev->unused.size == 0) {
9224 ev->unused.size = 16;
9225 ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9227 ev->unused.size += 16;
9228 ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9232 ev->unused.ptr[ev->unused.used++] = k;
9234 - fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
9236 + fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
9242 + sock->fde_ndx = -1;
9248 static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
9252 if (ev->used == 0) return 0;
9253 if (ev->unused.used != 0) return 0;
9256 for (j = ev->used - 1; j + 1 > 0; j--) {
9257 if (ev->pollfds[j].fd == -1) ev->used--;
9267 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9268 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
9270 - if (fde_ndx != -1) {
9271 - if (ev->pollfds[fde_ndx].fd == fd) {
9272 - ev->pollfds[fde_ndx].events = events;
9275 + if (sock->fde_ndx != -1) {
9276 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9277 + ev->pollfds[sock->fde_ndx].events = events;
9279 + return sock->fde_ndx;
9281 - fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9282 + fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9287 if (ev->unused.used > 0) {
9288 int k = ev->unused.ptr[--ev->unused.used];
9290 - ev->pollfds[k].fd = fd;
9292 + ev->pollfds[k].fd = sock->fd;
9293 ev->pollfds[k].events = events;
9295 - bitset_set_bit(ev->sigbset, fd);
9297 + bitset_set_bit(ev->sigbset, sock->fd);
9301 if (ev->size == 0) {
9302 @@ -102,12 +104,12 @@
9304 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9307 - ev->pollfds[ev->used].fd = fd;
9309 + ev->pollfds[ev->used].fd = sock->fd;
9310 ev->pollfds[ev->used].events = events;
9312 - bitset_set_bit(ev->sigbset, fd);
9314 + bitset_set_bit(ev->sigbset, sock->fd);
9319 @@ -115,20 +117,20 @@
9320 static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
9326 fdevent_linux_rtsig_event_compress(ev);
9333 ts.tv_sec = timeout_ms / 1000;
9334 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
9335 r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
9340 if (errno == EAGAIN) return 0;
9343 } else if (r == SIGIO) {
9344 struct sigaction act;
9347 /* re-enable the signal queue */
9348 act.sa_handler = SIG_DFL;
9349 sigaction(ev->signum, &act, NULL);
9353 r = poll(ev->pollfds, ev->used, timeout_ms);
9355 @@ -156,97 +158,67 @@
9359 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
9360 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9361 if (ev->in_sigio == 1) {
9363 - if (ev->siginfo.si_band == POLLERR) {
9364 - fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
9368 - fprintf(stderr, "+\n");
9372 - return ev->siginfo.si_band & 0x3f;
9373 + /* only one event */
9375 + fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
9377 - if (ndx >= ev->used) {
9378 - fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
9382 + for (ndx = 0; ndx < ev->used; ndx++) {
9383 + if (ev->pollfds[ndx].revents) {
9384 + fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9387 - return ev->pollfds[ndx].revents;
9391 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
9392 - if (ev->in_sigio == 1) {
9393 - return ev->siginfo.si_fd;
9395 - return ev->pollfds[ndx].fd;
9400 static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
9401 static pid_t pid = 0;
9404 if (pid == 0) pid = getpid();
9407 if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
9410 if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
9413 return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
9417 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
9418 - if (ev->in_sigio == 1) {
9419 - if (ndx < 0) return 0;
9424 - i = (ndx < 0) ? 0 : ndx + 1;
9425 - for (; i < ev->used; i++) {
9426 - if (ev->pollfds[i].revents) break;
9433 int fdevent_linux_rtsig_init(fdevents *ev) {
9434 ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
9436 ev->x = fdevent_linux_rtsig_##x;
9446 - SET(event_next_fdndx);
9449 - SET(event_get_fd);
9450 - SET(event_get_revent);
9454 ev->signum = SIGRTMIN + 1;
9457 sigemptyset(&(ev->sigset));
9458 sigaddset(&(ev->sigset), ev->signum);
9459 sigaddset(&(ev->sigset), SIGIO);
9460 if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
9461 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9462 __FILE__, __LINE__, strerror(errno));
9471 ev->sigbset = bitset_init(ev->maxfds);
9477 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c 2005-09-30 20:29:27.000000000 +0300
9478 +++ lighttpd-1.4.12/src/fdevent_linux_sysepoll.c 2006-07-18 13:03:40.000000000 +0300
9480 #include <sys/types.h>
9482 -#include <unistd.h>
9487 #include "fdevent.h"
9488 #include "settings.h"
9492 +#include "sys-files.h"
9494 #ifdef USE_LINUX_EPOLL
9495 static void fdevent_linux_sysepoll_free(fdevents *ev) {
9497 free(ev->epoll_events);
9500 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
9501 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
9502 struct epoll_event ep;
9504 - if (fde_ndx < 0) return -1;
9507 + if (sock->fde_ndx < 0) return -1;
9509 memset(&ep, 0, sizeof(ep));
9513 + ep.data.fd = sock->fd;
9516 - if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
9518 + if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
9519 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9531 + sock->fde_ndx = -1;
9536 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9537 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
9538 struct epoll_event ep;
9541 - if (fde_ndx == -1) add = 1;
9545 + if (sock->fde_ndx == -1) add = 1;
9547 memset(&ep, 0, sizeof(ep));
9553 if (events & FDEVENT_IN) ep.events |= EPOLLIN;
9554 if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
9562 ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
9568 - if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
9569 + ep.data.fd = sock->fd;
9571 + if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
9572 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9583 + sock->fde_ndx = sock->fd;
9588 static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
9589 return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
9592 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
9593 - int events = 0, e;
9595 - e = ev->epoll_events[ndx].events;
9596 - if (e & EPOLLIN) events |= FDEVENT_IN;
9597 - if (e & EPOLLOUT) events |= FDEVENT_OUT;
9598 - if (e & EPOLLERR) events |= FDEVENT_ERR;
9599 - if (e & EPOLLHUP) events |= FDEVENT_HUP;
9600 - if (e & EPOLLPRI) events |= FDEVENT_PRI;
9605 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
9607 - fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
9610 - return ev->epoll_events[ndx].data.fd;
9613 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
9617 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9620 + for (ndx = 0; ndx < event_count; ndx++) {
9621 + int events = 0, e;
9623 + e = ev->epoll_events[ndx].events;
9624 + if (e & EPOLLIN) events |= FDEVENT_IN;
9625 + if (e & EPOLLOUT) events |= FDEVENT_OUT;
9626 + if (e & EPOLLERR) events |= FDEVENT_ERR;
9627 + if (e & EPOLLHUP) events |= FDEVENT_HUP;
9628 + if (e & EPOLLPRI) events |= FDEVENT_PRI;
9630 - i = (ndx < 0) ? 0 : ndx + 1;
9633 + fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
9639 int fdevent_linux_sysepoll_init(fdevents *ev) {
9640 ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
9642 ev->x = fdevent_linux_sysepoll_##x;
9652 - SET(event_next_fdndx);
9653 - SET(event_get_fd);
9654 - SET(event_get_revent);
9659 if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
9660 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9661 __FILE__, __LINE__, strerror(errno));
9664 fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
9665 __FILE__, __LINE__);
9671 --- ../lighttpd-1.4.11/src/fdevent_poll.c 2005-11-18 13:59:16.000000000 +0200
9672 +++ lighttpd-1.4.12/src/fdevent_poll.c 2006-07-18 13:03:40.000000000 +0300
9674 #include <sys/types.h>
9676 -#include <unistd.h>
9681 #include "fdevent.h"
9682 #include "settings.h"
9687 static void fdevent_poll_free(fdevents *ev) {
9689 if (ev->unused.ptr) free(ev->unused.ptr);
9692 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
9693 - if (fde_ndx < 0) return -1;
9695 - if ((size_t)fde_ndx >= ev->used) {
9696 - fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
9697 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
9698 + if (sock->fde_ndx < 0) return -1;
9700 + if ((size_t)sock->fde_ndx >= ev->used) {
9701 + fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
9705 - if (ev->pollfds[fde_ndx].fd == fd) {
9706 - size_t k = fde_ndx;
9709 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9710 + size_t k = sock->fde_ndx;
9712 ev->pollfds[k].fd = -1;
9713 /* ev->pollfds[k].events = 0; */
9714 /* ev->pollfds[k].revents = 0; */
9717 if (ev->unused.size == 0) {
9718 ev->unused.size = 16;
9719 ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9721 ev->unused.size += 16;
9722 ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9726 ev->unused.ptr[ev->unused.used++] = k;
9733 + sock->fde_ndx = -1;
9739 static int fdevent_poll_event_compress(fdevents *ev) {
9743 if (ev->used == 0) return 0;
9744 if (ev->unused.used != 0) return 0;
9747 for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
9754 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9757 - if (fde_ndx != -1) {
9758 - if (ev->pollfds[fde_ndx].fd == fd) {
9759 - ev->pollfds[fde_ndx].events = events;
9762 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
9763 + if (sock->fde_ndx != -1) {
9764 + /* this fd was already added, just change the requested events */
9766 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9767 + ev->pollfds[sock->fde_ndx].events = events;
9769 + return sock->fde_ndx;
9771 - fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9772 + fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9777 if (ev->unused.used > 0) {
9778 int k = ev->unused.ptr[--ev->unused.used];
9780 - ev->pollfds[k].fd = fd;
9782 + ev->pollfds[k].fd = sock->fd;
9783 ev->pollfds[k].events = events;
9787 + sock->fde_ndx = k;
9790 if (ev->size == 0) {
9794 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9797 - ev->pollfds[ev->used].fd = fd;
9799 + ev->pollfds[ev->used].fd = sock->fd;
9800 ev->pollfds[ev->used].events = events;
9802 - return ev->used++;
9804 + sock->fde_ndx = ev->used++;
9809 static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
9810 @@ -105,71 +109,38 @@
9811 return poll(ev->pollfds, ev->used, timeout_ms);
9814 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
9816 - if (ndx >= ev->used) {
9817 - fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
9824 - if (ev->pollfds[ndx].revents & POLLNVAL) {
9825 - /* should never happen */
9828 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9832 - poll_r = ev->pollfds[ndx].revents;
9833 + for (ndx = 0; ndx < ev->used; ndx++) {
9834 + if (ev->pollfds[ndx].revents) {
9835 + if (ev->pollfds[ndx].revents & POLLNVAL) {
9836 + /* should never happen */
9840 - /* map POLL* to FDEVEN_* */
9842 - if (poll_r & POLLIN) r |= FDEVENT_IN;
9843 - if (poll_r & POLLOUT) r |= FDEVENT_OUT;
9844 - if (poll_r & POLLERR) r |= FDEVENT_ERR;
9845 - if (poll_r & POLLHUP) r |= FDEVENT_HUP;
9846 - if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
9847 - if (poll_r & POLLPRI) r |= FDEVENT_PRI;
9849 - return ev->pollfds[ndx].revents;
9852 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
9853 - return ev->pollfds[ndx].fd;
9856 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
9859 - i = (ndx < 0) ? 0 : ndx + 1;
9860 - for (; i < ev->used; i++) {
9861 - if (ev->pollfds[i].revents) break;
9862 + fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9871 int fdevent_poll_init(fdevents *ev) {
9872 ev->type = FDEVENT_HANDLER_POLL;
9874 ev->x = fdevent_poll_##x;
9884 - SET(event_next_fdndx);
9885 - SET(event_get_fd);
9886 - SET(event_get_revent);
9898 int fdevent_poll_init(fdevents *ev) {
9899 --- ../lighttpd-1.4.11/src/fdevent_select.c 2005-08-31 11:12:46.000000000 +0300
9900 +++ lighttpd-1.4.12/src/fdevent_select.c 2006-07-18 13:03:40.000000000 +0300
9902 -#include <sys/time.h>
9903 #include <sys/types.h>
9905 -#include <unistd.h>
9914 #include "fdevent.h"
9915 #include "settings.h"
9918 +#include "sys-socket.h"
9922 static int fdevent_select_reset(fdevents *ev) {
9923 @@ -24,101 +25,98 @@
9927 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
9928 - if (fde_ndx < 0) return -1;
9929 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
9930 + if (sock->fde_ndx < 0) return -1;
9932 - FD_CLR(fd, &(ev->select_set_read));
9933 - FD_CLR(fd, &(ev->select_set_write));
9934 - FD_CLR(fd, &(ev->select_set_error));
9935 + FD_CLR(sock->fd, &(ev->select_set_read));
9936 + FD_CLR(sock->fd, &(ev->select_set_write));
9937 + FD_CLR(sock->fd, &(ev->select_set_error));
9941 + /* mark the fdevent as deleted */
9942 + sock->fde_ndx = -1;
9944 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9949 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
9950 /* we should be protected by max-fds, but you never know */
9951 - assert(fd < FD_SETSIZE);
9953 + assert(sock->fd < FD_SETSIZE);
9956 if (events & FDEVENT_IN) {
9957 - FD_SET(fd, &(ev->select_set_read));
9958 - FD_CLR(fd, &(ev->select_set_write));
9959 + FD_SET(sock->fd, &(ev->select_set_read));
9960 + FD_CLR(sock->fd, &(ev->select_set_write));
9962 if (events & FDEVENT_OUT) {
9963 - FD_CLR(fd, &(ev->select_set_read));
9964 - FD_SET(fd, &(ev->select_set_write));
9965 + FD_CLR(sock->fd, &(ev->select_set_read));
9966 + FD_SET(sock->fd, &(ev->select_set_write));
9968 - FD_SET(fd, &(ev->select_set_error));
9970 - if (fd > ev->select_max_fd) ev->select_max_fd = fd;
9973 + FD_SET(sock->fd, &(ev->select_set_error));
9975 + /* we need this for the poll */
9976 + if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
9978 + /* mark fd as added */
9979 + sock->fde_ndx = sock->fd;
9984 static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
9988 tv.tv_sec = timeout_ms / 1000;
9989 tv.tv_usec = (timeout_ms % 1000) * 1000;
9992 ev->select_read = ev->select_set_read;
9993 ev->select_write = ev->select_set_write;
9994 ev->select_error = ev->select_set_error;
9997 return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
10000 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
10003 - if (FD_ISSET(ndx, &(ev->select_read))) {
10004 - revents |= FDEVENT_IN;
10006 + * scan the fdset for events
10008 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
10012 + for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
10015 + if (FD_ISSET(ndx, &(ev->select_read))) {
10016 + events |= FDEVENT_IN;
10018 + if (FD_ISSET(ndx, &(ev->select_write))) {
10019 + events |= FDEVENT_OUT;
10021 + if (FD_ISSET(ndx, &(ev->select_error))) {
10022 + events |= FDEVENT_ERR;
10026 + fdevent_revents_add(revents, ndx, events);
10029 - if (FD_ISSET(ndx, &(ev->select_write))) {
10030 - revents |= FDEVENT_OUT;
10032 - if (FD_ISSET(ndx, &(ev->select_error))) {
10033 - revents |= FDEVENT_ERR;
10039 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
10045 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
10048 - i = (ndx < 0) ? 0 : ndx + 1;
10050 - for (; i < ev->select_max_fd + 1; i++) {
10051 - if (FD_ISSET(i, &(ev->select_read))) break;
10052 - if (FD_ISSET(i, &(ev->select_write))) break;
10053 - if (FD_ISSET(i, &(ev->select_error))) break;
10060 int fdevent_select_init(fdevents *ev) {
10061 ev->type = FDEVENT_HANDLER_SELECT;
10063 ev->x = fdevent_select_##x;
10073 - SET(event_next_fdndx);
10074 - SET(event_get_fd);
10075 - SET(event_get_revent);
10078 + SET(get_revents);
10083 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c 2005-09-01 10:45:26.000000000 +0300
10084 +++ lighttpd-1.4.12/src/fdevent_solaris_devpoll.c 2006-07-16 00:26:03.000000000 +0300
10086 #include <sys/types.h>
10088 -#include <unistd.h>
10089 #include <stdlib.h>
10091 #include <string.h>
10092 @@ -23,55 +22,55 @@
10094 static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10098 if (fde_ndx < 0) return -1;
10102 pfd.events = POLLREMOVE;
10106 if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10107 - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10108 - __FILE__, __LINE__,
10109 + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10110 + __FILE__, __LINE__,
10111 fd, strerror(errno));
10121 static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10126 if (fde_ndx == -1) add = 1;
10130 pfd.events = events;
10134 if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10135 - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10136 - __FILE__, __LINE__,
10137 + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10138 + __FILE__, __LINE__,
10139 fd, strerror(errno));
10149 static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
10150 struct dvpoll dopoll;
10154 dopoll.dp_timeout = timeout_ms;
10155 dopoll.dp_nfds = ev->maxfds;
10156 dopoll.dp_fds = ev->devpollfds;
10159 ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
10165 @@ -85,11 +84,11 @@
10167 static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
10173 i = (last_ndx < 0) ? 0 : last_ndx + 1;
10179 @@ -117,20 +116,20 @@
10180 ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
10182 ev->x = fdevent_solaris_devpoll_##x;
10194 SET(event_next_fdndx);
10196 SET(event_get_revent);
10199 ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
10202 if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
10203 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10204 __FILE__, __LINE__, strerror(errno));
10205 @@ -152,7 +151,7 @@
10207 fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10208 __FILE__, __LINE__);
10214 --- ../lighttpd-1.4.11/src/http-header-glue.c 2006-02-08 15:31:36.000000000 +0200
10215 +++ lighttpd-1.4.12/src/http-header-glue.c 2006-07-18 13:03:40.000000000 +0300
10216 @@ -45,20 +45,20 @@
10217 # ifdef HAVE_STRUCT_SOCKADDR_STORAGE
10218 static size_t get_sa_len(const struct sockaddr *addr) {
10219 switch (addr->sa_family) {
10224 return (sizeof (struct sockaddr_in));
10230 return (sizeof (struct sockaddr_in6));
10235 return (sizeof (struct sockaddr));
10240 # define SA_LEN(addr) (get_sa_len(addr))
10243 int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10249 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
10250 @@ -82,32 +82,32 @@
10252 buffer_copy_string_len(ds->key, key, keylen);
10253 buffer_copy_string_len(ds->value, value, vallen);
10256 array_insert_unique(con->response.headers, (data_unset *)ds);
10262 int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10268 /* if there already is a key by this name overwrite the value */
10269 if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
10270 buffer_copy_string(ds->value, value);
10277 return response_header_insert(srv, con, key, keylen, value, vallen);
10280 int http_response_redirect_to_directory(server *srv, connection *con) {
10287 if (con->conf.is_ssl) {
10288 buffer_copy_string(o, "https://");
10290 @@ -123,36 +123,36 @@
10292 sock_addr our_addr;
10293 socklen_t our_addr_len;
10296 our_addr_len = sizeof(our_addr);
10298 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
10300 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
10301 con->http_status = 500;
10304 log_error_write(srv, __FILE__, __LINE__, "ss",
10305 "can't get sockname", strerror(errno));
10315 /* Lookup name: secondly try to get hostname for bind address */
10316 switch(our_addr.plain.sa_family) {
10319 - if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10320 - SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10321 + if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10322 + SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10323 hbuf, sizeof(hbuf), NULL, 0, 0)) {
10326 char dst[INET6_ADDRSTRLEN];
10329 log_error_write(srv, __FILE__, __LINE__,
10330 "SSSS", "NOTICE: getnameinfo failed: ",
10331 strerror(errno), ", using ip-address instead");
10333 - buffer_append_string(o,
10334 - inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10336 + buffer_append_string(o,
10337 + inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10338 dst, sizeof(dst)));
10340 buffer_append_string(o, hbuf);
10341 @@ -164,7 +164,7 @@
10342 log_error_write(srv, __FILE__, __LINE__,
10343 "SdSS", "NOTICE: gethostbyaddr failed: ",
10344 h_errno, ", using ip-address instead");
10347 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
10349 buffer_append_string(o, he->h_name);
10350 @@ -173,12 +173,12 @@
10352 log_error_write(srv, __FILE__, __LINE__,
10353 "S", "ERROR: unsupported address-type");
10360 - if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10362 + if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10363 (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
10364 buffer_append_string(o, ":");
10365 buffer_append_long(o, srv->srvconf.port);
10366 @@ -190,41 +190,41 @@
10367 buffer_append_string(o, "?");
10368 buffer_append_string_buffer(o, con->uri.query);
10372 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
10375 con->http_status = 301;
10376 con->file_finished = 1;
10385 buffer * strftime_cache_get(server *srv, time_t last_mod) {
10390 for (i = 0; i < FILE_CACHE_MAX; i++) {
10391 /* found cache-entry */
10392 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
10395 /* found empty slot */
10396 if (srv->mtime_cache[i].mtime == 0) break;
10400 if (i == FILE_CACHE_MAX) {
10405 srv->mtime_cache[i].mtime = last_mod;
10406 buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
10407 tm = gmtime(&(srv->mtime_cache[i].mtime));
10408 - srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10409 + srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10410 srv->mtime_cache[i].str->size - 1,
10411 "%a, %d %b %Y %H:%M:%S GMT", tm);
10412 srv->mtime_cache[i].str->used++;
10415 return srv->mtime_cache[i].str;
10418 @@ -239,56 +239,60 @@
10419 * request. That is, if no entity tags match, then the server MUST NOT
10420 * return a 304 (Not Modified) response.
10424 /* last-modified handling */
10425 if (con->request.http_if_none_match) {
10426 if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
10427 - if (con->request.http_method == HTTP_METHOD_GET ||
10428 + if (con->request.http_method == HTTP_METHOD_GET ||
10429 con->request.http_method == HTTP_METHOD_HEAD) {
10432 /* check if etag + last-modified */
10433 if (con->request.http_if_modified_since) {
10438 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10439 used_len = strlen(con->request.http_if_modified_since);
10441 used_len = semicolon - con->request.http_if_modified_since;
10445 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10446 con->http_status = 304;
10447 return HANDLER_FINISHED;
10449 +#ifdef HAVE_STRPTIME
10450 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10451 + time_t t_header, t_file;
10454 - /* convert to timestamp */
10455 - if (used_len < sizeof(buf)) {
10456 - time_t t_header, t_file;
10459 - strncpy(buf, con->request.http_if_modified_since, used_len);
10460 - buf[used_len] = '\0';
10462 - strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10463 - t_header = mktime(&tm);
10465 - strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10466 - t_file = mktime(&tm);
10468 - if (t_file > t_header) {
10469 - con->http_status = 304;
10470 - return HANDLER_FINISHED;
10473 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
10474 - "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10475 + /* check if we can safely copy the string */
10476 + if (used_len >= sizeof(buf)) {
10477 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
10478 + "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10479 con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
10482 con->http_status = 412;
10483 return HANDLER_FINISHED;
10487 + strncpy(buf, con->request.http_if_modified_since, used_len);
10488 + buf[used_len] = '\0';
10490 + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10491 + t_header = mktime(&tm);
10493 + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10494 + t_file = mktime(&tm);
10496 + if (t_file > t_header) return HANDLER_GO_ON;
10498 + con->http_status = 304;
10499 + return HANDLER_FINISHED;
10501 + return HANDLER_GO_ON;
10505 con->http_status = 304;
10506 @@ -302,16 +306,41 @@
10507 } else if (con->request.http_if_modified_since) {
10512 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10513 used_len = strlen(con->request.http_if_modified_since);
10515 used_len = semicolon - con->request.http_if_modified_since;
10519 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10520 con->http_status = 304;
10521 return HANDLER_FINISHED;
10523 +#ifdef HAVE_STRPTIME
10524 + char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10525 + time_t t_header, t_file;
10528 + /* convert to timestamp */
10529 + if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
10531 + strncpy(buf, con->request.http_if_modified_since, used_len);
10532 + buf[used_len] = '\0';
10534 + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10535 + t_header = mktime(&tm);
10537 + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10538 + t_file = mktime(&tm);
10540 + if (t_file > t_header) return HANDLER_GO_ON;
10542 + con->http_status = 304;
10543 + return HANDLER_FINISHED;
10545 + return HANDLER_GO_ON;
10550 --- ../lighttpd-1.4.11/src/http_auth.c 2006-02-01 13:02:52.000000000 +0200
10551 +++ lighttpd-1.4.12/src/http_auth.c 2006-07-18 13:03:40.000000000 +0300
10553 #include <string.h>
10556 -#include <unistd.h>
10559 #include "server.h"
10560 @@ -31,23 +30,14 @@
10561 #include "http_auth_digest.h"
10562 #include "stream.h"
10564 +#include "sys-strings.h"
10567 # include <openssl/md5.h>
10574 -#include <security/pam_appl.h>
10575 -#include <security/pam_misc.h>
10577 -static struct pam_conv conv = {
10583 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
10585 static const char base64_pad = '=';
10586 @@ -75,25 +65,25 @@
10587 unsigned char *result;
10592 size_t in_len = strlen(in);
10595 buffer_prepare_copy(out, in_len);
10598 result = (unsigned char *)out->ptr;
10602 /* run through the whole string, converting as we go */
10603 for (i = 0; i < in_len; i++) {
10607 if (ch == '\0') break;
10610 if (ch == base64_pad) break;
10613 ch = base64_reverse_table[ch];
10614 if (ch < 0) continue;
10619 result[j] = ch << 2;
10620 @@ -125,168 +115,168 @@
10632 static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
10636 if (!username->used|| !realm->used) return -1;
10639 if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10644 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
10647 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
10648 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
10658 while (f_line - f.start != f.size) {
10659 char *f_user, *f_pwd, *e, *f_realm;
10660 size_t u_len, pwd_len, r_len;
10670 - * user:realm:md5(user:realm:password)
10672 + * user:realm:md5(user:realm:password)
10676 if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10677 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10678 - "parsed error in", p->conf.auth_htdigest_userfile,
10679 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10680 + "parsed error in", p->conf.auth_htdigest_userfile,
10681 "expected 'username:realm:hashed password'");
10691 if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
10692 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10693 - "parsed error in", p->conf.auth_plain_userfile,
10694 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10695 + "parsed error in", p->conf.auth_plain_userfile,
10696 "expected 'username:realm:hashed password'");
10706 /* get pointers to the fields */
10707 - u_len = f_realm - f_user;
10708 + u_len = f_realm - f_user;
10710 r_len = f_pwd - f_realm;
10714 if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10715 pwd_len = e - f_pwd;
10717 pwd_len = f.size - (f_pwd - f.start);
10721 if (username->used - 1 == u_len &&
10722 (realm->used - 1 == r_len) &&
10723 (0 == strncmp(username->ptr, f_user, u_len)) &&
10724 (0 == strncmp(realm->ptr, f_realm, r_len))) {
10728 buffer_copy_string_len(password, f_pwd, pwd_len);
10745 } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
10746 p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
10752 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
10755 if (buffer_is_empty(auth_fn)) return -1;
10758 if (0 != stream_open(&f, auth_fn)) {
10759 - log_error_write(srv, __FILE__, __LINE__, "sbss",
10760 + log_error_write(srv, __FILE__, __LINE__, "sbss",
10761 "opening plain-userfile", auth_fn, "failed:", strerror(errno));
10771 while (f_line - f.start != f.size) {
10772 char *f_user, *f_pwd, *e;
10773 size_t u_len, pwd_len;
10784 * user:crypted passwd
10788 if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10789 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10790 - "parsed error in", auth_fn,
10791 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10792 + "parsed error in", auth_fn,
10793 "expected 'username:hashed password'");
10803 /* get pointers to the fields */
10804 - u_len = f_pwd - f_user;
10805 + u_len = f_pwd - f_user;
10809 if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10810 pwd_len = e - f_pwd;
10812 pwd_len = f.size - (f_pwd - f.start);
10816 if (username->used - 1 == u_len &&
10817 (0 == strncmp(username->ptr, f_user, u_len))) {
10821 buffer_copy_string_len(password, f_pwd, pwd_len);
10838 } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
10848 @@ -296,7 +286,7 @@
10850 data_string *require;
10857 @@ -304,12 +294,12 @@
10858 /* search auth-directives for path */
10859 for (i = 0; i < p->conf.auth_require->used; i++) {
10860 if (p->conf.auth_require->data[i]->key->used == 0) continue;
10863 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
10869 if (i == p->conf.auth_require->used) {
10872 @@ -317,72 +307,72 @@
10873 req = ((data_array *)(p->conf.auth_require->data[i]))->value;
10875 require = (data_string *)array_get_element(req, "require");
10878 /* if we get here, the user we got a authed user */
10879 - if (0 == strcmp(require->value->ptr, "valid-user")) {
10880 + if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
10885 /* user=name1|group=name3|host=name4 */
10888 /* seperate the string by | */
10890 log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
10895 username_len = username ? strlen(username) : 0;
10898 r = rules = require->value->ptr;
10903 const char *k, *v, *e;
10904 int k_len, v_len, r_len;
10907 e = strchr(r, '|');
10913 r_len = strlen(rules) - (r - rules);
10917 /* from r to r + r_len is a rule */
10920 if (0 == strncmp(r, "valid-user", r_len)) {
10921 - log_error_write(srv, __FILE__, __LINE__, "sb",
10922 + log_error_write(srv, __FILE__, __LINE__, "sb",
10923 "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
10929 /* search for = in the rules */
10930 if (NULL == (eq = strchr(r, '='))) {
10931 - log_error_write(srv, __FILE__, __LINE__, "sb",
10932 - "parsing the 'require' section in 'auth.require' failed: a = is missing",
10933 + log_error_write(srv, __FILE__, __LINE__, "sb",
10934 + "parsing the 'require' section in 'auth.require' failed: a = is missing",
10940 /* = out of range */
10941 if (eq > r + r_len) {
10942 - log_error_write(srv, __FILE__, __LINE__, "sb",
10943 + log_error_write(srv, __FILE__, __LINE__, "sb",
10944 "parsing the 'require' section in 'auth.require' failed: = out of range",
10952 /* the part before the = is user|group|host */
10958 v_len = r_len - k_len - 1;
10962 if (0 == strncmp(k, "user", k_len)) {
10965 username_len == v_len &&
10966 0 == strncmp(username, v, v_len)) {
10968 @@ -404,19 +394,19 @@
10969 log_error_write(srv, __FILE__, __LINE__, "s", "unknown key");
10979 log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
10990 * @param password password-string from the auth-backend
10991 * @param pw password-string from the client
10993 @@ -426,16 +416,16 @@
10996 if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
11001 - * user:realm:md5(user:realm:password)
11003 + * user:realm:md5(user:realm:password)
11013 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
11014 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
11015 @@ -443,24 +433,24 @@
11016 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
11017 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
11018 MD5_Final(HA1, &Md5Ctx);
11023 - if (0 == strcmp(password->ptr, a1)) {
11025 + if (buffer_is_equal_string(password, a1, strlen(a1))) {
11028 - } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11030 + } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11034 size_t salt_len = 0;
11040 * user:crypted password
11046 * CRYPT_STD_DES 2-character (Default)
11047 * CRYPT_EXT_DES 9-character
11048 @@ -478,7 +468,7 @@
11050 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
11051 char *dollar = NULL;
11054 if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
11055 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11057 @@ -495,48 +485,21 @@
11058 strncpy(salt, password->ptr, salt_len);
11060 salt[salt_len] = '\0';
11063 crypted = crypt(pw, salt);
11065 - if (0 == strcmp(password->ptr, crypted)) {
11066 + if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
11069 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11073 - } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11074 - if (0 == strcmp(password->ptr, pw)) {
11077 - } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) {
11079 - pam_handle_t *pamh=NULL;
11082 - retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
11084 - if (retval == PAM_SUCCESS)
11085 - retval = pam_authenticate(pamh, 0); /* is user really user? */
11087 - if (retval == PAM_SUCCESS)
11088 - retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
11090 - /* This is where we have been authorized or not. */
11092 - if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
11094 - log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
11097 - if (retval == PAM_SUCCESS) {
11098 - log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
11101 + } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11102 + if (buffer_is_equal_string(password, pw, strlen(pw))) {
11105 - log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
11108 - } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11109 + } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11112 LDAPMessage *lm, *first;
11113 @@ -544,45 +507,45 @@
11115 char *attrs[] = { LDAP_NO_ATTRS, NULL };
11119 /* for now we stay synchronous */
11124 * 1. connect anonymously (done in plugin init)
11125 * 2. get DN for uid = username
11126 * 3. auth against ldap server
11127 * 4. (optional) check a field
11137 * we have to protect us againt username which modifies out filter in
11142 for (i = 0; i < username->used - 1; i++) {
11143 char c = username->ptr[i];
11149 - log_error_write(srv, __FILE__, __LINE__, "sbd",
11151 + log_error_write(srv, __FILE__, __LINE__, "sbd",
11152 "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
11165 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
11166 buffer_append_string_buffer(p->ldap_filter, username);
11167 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
11173 if (p->conf.ldap == NULL ||
11174 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))) {
11175 @@ -590,71 +553,71 @@
11177 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))) {
11179 - log_error_write(srv, __FILE__, __LINE__, "sssb",
11180 + log_error_write(srv, __FILE__, __LINE__, "sssb",
11181 "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
11189 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
11190 log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11200 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
11201 log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11217 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
11218 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
11223 ret = LDAP_VERSION3;
11224 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
11225 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11228 ldap_unbind_s(ldap);
11235 if (p->conf.auth_ldap_starttls == 1) {
11236 if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL, NULL))) {
11237 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
11240 ldap_unbind_s(ldap);
11249 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
11250 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11253 ldap_unbind_s(ldap);
11261 ldap_unbind_s(ldap);
11264 /* everything worked, good, access granted */
11270 @@ -664,65 +627,65 @@
11271 int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11272 buffer *username, *password;
11276 data_string *realm;
11279 realm = (data_string *)array_get_element(req, "realm");
11282 username = buffer_init();
11283 password = buffer_init();
11286 base64_decode(username, realm_str);
11289 /* r2 == user:password */
11290 if (NULL == (pw = strchr(username->ptr, ':'))) {
11291 buffer_free(username);
11294 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
11304 username->used = pw - username->ptr;
11307 /* copy password to r1 */
11308 if (http_auth_get_password(srv, p, username, realm->value, password)) {
11309 buffer_free(username);
11310 buffer_free(password);
11313 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
11320 /* password doesn't match */
11321 if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
11322 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
11325 buffer_free(username);
11326 buffer_free(password);
11333 /* value is our allow-rules */
11334 if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
11335 buffer_free(username);
11336 buffer_free(password);
11339 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
11346 /* remember the username */
11347 buffer_copy_string_buffer(p->auth_user, username);
11350 buffer_free(username);
11351 buffer_free(password);
11357 @@ -735,7 +698,7 @@
11358 int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11366 @@ -745,18 +708,18 @@
11373 const char *m = NULL;
11375 buffer *password, *b, *username_buf, *realm_buf;
11386 /* init pointers */
11388 @@ -771,11 +734,11 @@
11391 { S("response=") },
11399 dkv[0].ptr = &username;
11400 dkv[1].ptr = &realm;
11401 dkv[2].ptr = &nonce;
11402 @@ -786,24 +749,24 @@
11404 dkv[8].ptr = &respons;
11411 for (i = 0; dkv[i].key; i++) {
11412 *(dkv[i].ptr) = NULL;
11418 if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
11419 p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
11420 - log_error_write(srv, __FILE__, __LINE__, "s",
11421 + log_error_write(srv, __FILE__, __LINE__, "s",
11422 "digest: unsupported backend (only htdigest or plain)");
11429 b = buffer_init_string(realm_str);
11432 /* parse credentials from client */
11433 for (c = b->ptr; *c; c++) {
11434 /* skip whitespaces */
11435 @@ -812,18 +775,18 @@
11437 for (i = 0; dkv[i].key; i++) {
11438 if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
11439 - if ((c[dkv[i].key_len] == '"') &&
11440 + if ((c[dkv[i].key_len] == '"') &&
11441 (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
11442 /* value with "..." */
11443 *(dkv[i].ptr) = c + dkv[i].key_len + 1;
11448 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
11449 /* value without "...", terminated by ',' */
11450 *(dkv[i].ptr) = c + dkv[i].key_len;
11456 /* value without "...", terminated by EOL */
11457 @@ -833,7 +796,7 @@
11463 if (p->conf.auth_debug > 1) {
11464 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
11465 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
11466 @@ -845,22 +808,22 @@
11467 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
11468 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
11472 /* check if everything is transmitted */
11478 (qop && (!nc || !cnonce)) ||
11480 /* missing field */
11482 - log_error_write(srv, __FILE__, __LINE__, "s",
11484 + log_error_write(srv, __FILE__, __LINE__, "s",
11485 "digest: missing field");
11489 - m = get_http_method_name(con->request.http_method);
11490 + m = get_http_method_name(con->request.http_method);
11492 /* password-string == HA1 */
11493 password = buffer_init();
11494 @@ -873,10 +836,10 @@
11495 buffer_free(realm_buf);
11500 buffer_free(username_buf);
11501 buffer_free(realm_buf);
11504 if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11505 /* generate password from plain-text */
11507 @@ -890,16 +853,16 @@
11509 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
11510 for (i = 0; i < HASHLEN; i++) {
11511 - HA1[i] = hex2int(password->ptr[i*2]) << 4;
11512 - HA1[i] |= hex2int(password->ptr[i*2+1]);
11513 + HA1[i] = hex2int(password->ptr[i*2]) << 4;
11514 + HA1[i] |= hex2int(password->ptr[i*2+1]);
11517 /* we already check that above */
11522 buffer_free(password);
11526 strcasecmp(algorithm, "md5-sess") == 0) {
11528 @@ -910,9 +873,9 @@
11529 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
11530 MD5_Final(HA1, &Md5Ctx);
11537 /* calculate H(A2) */
11539 MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
11540 @@ -924,7 +887,7 @@
11542 MD5_Final(HA2, &Md5Ctx);
11543 CvtHex(HA2, HA2Hex);
11546 /* calculate response */
11548 MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
11549 @@ -942,39 +905,39 @@
11550 MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
11551 MD5_Final(RespHash, &Md5Ctx);
11552 CvtHex(RespHash, a2);
11555 if (0 != strcmp(a2, respons)) {
11556 /* digest not ok */
11559 if (p->conf.auth_debug) {
11560 - log_error_write(srv, __FILE__, __LINE__, "sss",
11561 + log_error_write(srv, __FILE__, __LINE__, "sss",
11562 "digest: digest mismatch", a2, respons);
11565 - log_error_write(srv, __FILE__, __LINE__, "sss",
11567 + log_error_write(srv, __FILE__, __LINE__, "sss",
11568 "digest: auth failed for", username, "wrong password");
11576 /* value is our allow-rules */
11577 if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
11580 - log_error_write(srv, __FILE__, __LINE__, "s",
11582 + log_error_write(srv, __FILE__, __LINE__, "s",
11583 "digest: rules did match");
11590 /* remember the username */
11591 buffer_copy_string(p->auth_user, username);
11597 if (p->conf.auth_debug) {
11598 - log_error_write(srv, __FILE__, __LINE__, "s",
11599 + log_error_write(srv, __FILE__, __LINE__, "s",
11600 "digest: auth ok");
11603 @@ -985,23 +948,23 @@
11611 /* generate shared-secret */
11613 MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
11614 MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
11617 /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
11618 ltostr(hh, srv->cur_ts);
11619 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11620 ltostr(hh, rand());
11621 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11624 MD5_Final(h, &Md5Ctx);
11632 --- ../lighttpd-1.4.11/src/http_auth.h 2005-08-14 17:12:31.000000000 +0300
11633 +++ lighttpd-1.4.12/src/http_auth.h 2006-07-16 00:26:04.000000000 +0300
11638 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN,
11639 - AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD,
11640 - AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
11642 + AUTH_BACKEND_UNSET,
11643 + AUTH_BACKEND_PLAIN,
11644 + AUTH_BACKEND_LDAP,
11645 + AUTH_BACKEND_HTPASSWD,
11646 + AUTH_BACKEND_HTDIGEST
11651 array *auth_require;
11654 buffer *auth_plain_groupfile;
11655 buffer *auth_plain_userfile;
11658 buffer *auth_htdigest_userfile;
11659 buffer *auth_htpasswd_userfile;
11662 buffer *auth_backend_conf;
11665 buffer *auth_ldap_hostname;
11666 buffer *auth_ldap_basedn;
11667 buffer *auth_ldap_binddn;
11668 @@ -32,15 +36,15 @@
11669 buffer *auth_ldap_filter;
11670 buffer *auth_ldap_cafile;
11671 unsigned short auth_ldap_starttls;
11674 unsigned short auth_debug;
11678 auth_backend_t auth_backend;
11685 buffer *ldap_filter_pre;
11686 buffer *ldap_filter_post;
11688 @@ -49,15 +53,15 @@
11697 buffer *ldap_filter;
11701 mod_auth_plugin_config **config_storage;
11704 mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
11705 } mod_auth_plugin_data;
11707 --- ../lighttpd-1.4.11/src/http_auth_digest.h 2006-01-05 00:54:01.000000000 +0200
11708 +++ lighttpd-1.4.12/src/http_auth_digest.h 2006-07-16 00:26:04.000000000 +0300
11718 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
11719 +++ lighttpd-1.4.12/src/http_chunk.c 2006-07-16 00:26:04.000000000 +0300
11722 * the HTTP chunk-API
11729 #include <sys/types.h>
11732 #include <stdlib.h>
11734 -#include <unistd.h>
11738 @@ -23,19 +22,19 @@
11739 static int http_chunk_append_len(server *srv, connection *con, size_t len) {
11740 size_t i, olen = len, j;
11744 b = srv->tmp_chunk_len;
11748 buffer_copy_string(b, "0");
11750 for (i = 0; i < 8 && len; i++) {
11755 /* i is the number of hex digits we have */
11756 buffer_prepare_copy(b, i + 1);
11759 for (j = i-1, len = olen; j+1 > 0; j--) {
11760 b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
11762 @@ -43,61 +42,61 @@
11764 b->ptr[b->used++] = '\0';
11768 buffer_append_string(b, "\r\n");
11769 chunkqueue_append_buffer(con->write_queue, b);
11776 int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
11780 if (!con) return -1;
11783 cq = con->write_queue;
11786 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11787 http_chunk_append_len(srv, con, len);
11791 chunkqueue_append_file(cq, fn, offset, len);
11794 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
11795 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11802 int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
11806 if (!con) return -1;
11809 cq = con->write_queue;
11812 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11813 http_chunk_append_len(srv, con, mem->used - 1);
11817 chunkqueue_append_buffer(cq, mem);
11820 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
11821 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11828 int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
11832 if (!con) return -1;
11835 cq = con->write_queue;
11839 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11840 http_chunk_append_len(srv, con, 0);
11841 @@ -107,17 +106,17 @@
11847 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11848 http_chunk_append_len(srv, con, len - 1);
11852 chunkqueue_append_mem(cq, mem, len);
11855 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11856 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11863 @@ -125,9 +124,9 @@
11864 off_t http_chunkqueue_length(server *srv, connection *con) {
11866 log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
11873 return chunkqueue_length(con->write_queue);
11875 --- ../lighttpd-1.4.11/src/http_resp.c 1970-01-01 03:00:00.000000000 +0300
11876 +++ lighttpd-1.4.12/src/http_resp.c 2006-07-18 13:03:40.000000000 +0300
11878 +#include <string.h>
11879 +#include <stdlib.h>
11880 +#include <stdio.h>
11881 +#include <assert.h>
11884 +#include "http_resp.h"
11885 +#include "http_resp_parser.h"
11887 +/* declare prototypes for the parser */
11888 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
11889 +void http_resp_parserFree(void *p, void (*freeProc)(void*));
11890 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
11891 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
11896 + chunk *c; /* current chunk in the chunkqueue */
11897 + size_t offset; /* current offset in current chunk */
11900 + size_t lookup_offset;
11903 + int is_statusline;
11904 +} http_resp_tokenizer_t;
11906 +http_resp *http_response_init(void) {
11907 + http_resp *resp = calloc(1, sizeof(*resp));
11909 + resp->reason = buffer_init();
11910 + resp->headers = array_init();
11915 +void http_response_reset(http_resp *resp) {
11916 + if (!resp) return;
11918 + buffer_reset(resp->reason);
11919 + array_reset(resp->headers);
11923 +void http_response_free(http_resp *resp) {
11924 + if (!resp) return;
11926 + buffer_free(resp->reason);
11927 + array_free(resp->headers);
11932 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11933 + if (t->offset == t->c->mem->used - 1) {
11934 + /* end of chunk, open next chunk */
11936 + if (!t->c->next) return -1;
11938 + t->c = t->c->next;
11942 + *c = t->c->mem->ptr[t->offset++];
11944 + t->lookup_offset = t->offset;
11945 + t->lookup_c = t->c;
11948 + fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
11954 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11955 + if (t->lookup_offset == t->lookup_c->mem->used - 1) {
11956 + /* end of chunk, open next chunk */
11958 + if (!t->lookup_c->next) return -1;
11960 + t->lookup_c = t->lookup_c->next;
11961 + t->lookup_offset = 0;
11964 + *c = t->lookup_c->mem->ptr[t->lookup_offset++];
11966 + fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
11973 +static int http_resp_tokenizer(
11974 + http_resp_tokenizer_t *t,
11981 + /* push the token to the parser */
11983 + while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
11997 + if (0 != http_resp_lookup_next_char(t, &c)) return -1;
12002 + t->c = t->lookup_c;
12003 + t->offset = t->lookup_offset;
12005 + t->is_statusline = 0;
12008 + fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
12015 + t->is_statusline = 0;
12020 + while (c >= 32 && c != 127 && c != 255) {
12021 + if (t->is_statusline) {
12022 + if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
12023 + if (c == 32) break; /* the space is a splitter in the statusline */
12026 + if (c == ':') break; /* the : is the splitter between key and value */
12029 + if (0 != http_resp_lookup_next_char(t, &c)) return -1;
12032 + if (t->c == t->lookup_c &&
12033 + t->offset == t->lookup_offset + 1) {
12035 + fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
12041 + /* the lookup points to the first invalid char */
12042 + t->lookup_offset--;
12044 + /* no overlapping string */
12045 + if (t->c == t->lookup_c) {
12046 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
12048 + /* first chunk */
12049 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
12051 + /* chunks in the middle */
12052 + for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
12053 + buffer_append_string_buffer(token, t->c->mem);
12054 + t->offset = t->c->mem->used - 1;
12058 + buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
12061 + t->offset = t->lookup_offset;
12076 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
12077 + http_resp_tokenizer_t t;
12078 + void *pParser = NULL;
12079 + int token_id = 0;
12080 + buffer *token = NULL;
12081 + http_resp_ctx_t context;
12082 + parse_status_t ret = PARSE_UNSET;
12083 + int last_token_id = 0;
12087 + t.offset = t.c->offset;
12089 + t.is_statusline = 1;
12092 + context.errmsg = buffer_init();
12093 + context.resp = resp;
12095 + pParser = http_resp_parserAlloc( malloc );
12096 + token = buffer_init();
12098 + http_resp_parserTrace(stderr, "http-response: ");
12101 + while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
12102 + http_resp_parser(pParser, token_id, token, &context);
12104 + token = buffer_init();
12106 + /* CRLF CRLF ... the header end sequence */
12107 + if (last_token_id == TK_CRLF &&
12108 + token_id == TK_CRLF) break;
12110 + last_token_id = token_id;
12113 + /* oops, the parser failed */
12114 + if (context.ok == 0) {
12115 + ret = PARSE_ERROR;
12117 + if (!buffer_is_empty(context.errmsg)) {
12118 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12120 + TRACE("%s", "parsing failed ...");
12124 + http_resp_parser(pParser, 0, token, &context);
12125 + http_resp_parserFree(pParser, free);
12127 + if (context.ok == 0) {
12128 + /* we are missing the some tokens */
12130 + if (!buffer_is_empty(context.errmsg)) {
12131 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12134 + if (ret == PARSE_UNSET) {
12135 + ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
12140 + for (c = cq->first; c != t.c; c = c->next) {
12141 + c->offset = c->mem->used - 1;
12144 + c->offset = t.offset;
12146 + ret = PARSE_SUCCESS;
12149 + buffer_free(token);
12150 + buffer_free(context.errmsg);
12155 --- ../lighttpd-1.4.11/src/http_resp.h 1970-01-01 03:00:00.000000000 +0300
12156 +++ lighttpd-1.4.12/src/http_resp.h 2006-07-16 00:26:04.000000000 +0300
12158 +#ifndef _HTTP_RESP_H_
12159 +#define _HTTP_RESP_H_
12161 +#include "array.h"
12162 +#include "chunk.h"
12172 + int protocol; /* http/1.0, http/1.1 */
12173 + int status; /* e.g. 200 */
12174 + buffer *reason; /* e.g. Ok */
12183 +} http_resp_ctx_t;
12185 +http_resp *http_response_init(void);
12186 +void http_response_free(http_resp *resp);
12187 +void http_response_reset(http_resp *resp);
12189 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
12192 --- ../lighttpd-1.4.11/src/http_resp_parser.c 1970-01-01 03:00:00.000000000 +0300
12193 +++ lighttpd-1.4.12/src/http_resp_parser.c 2006-07-18 13:03:52.000000000 +0300
12195 +/* Driver template for the LEMON parser generator.
12196 +** The author disclaims copyright to this source code.
12198 +/* First off, code is include which follows the "include" declaration
12199 +** in the input file. */
12200 +#include <stdio.h>
12201 +#line 6 "./http_resp_parser.y"
12203 +#include <assert.h>
12204 +#include <string.h>
12205 +#include "http_resp.h"
12206 +#include "keyvalue.h"
12207 +#include "array.h"
12210 +#line 17 "http_resp_parser.c"
12211 +/* Next is all token values, in a form suitable for use by makeheaders.
12212 +** This section will be null unless lemon is run with the -m switch.
12215 +** These constants (all generated automatically by the parser generator)
12216 +** specify the various kinds of tokens (terminals) that the parser
12219 +** Each symbol here is a terminal symbol in the grammar.
12221 +/* Make sure the INTERFACE macro is defined.
12224 +# define INTERFACE 1
12226 +/* The next thing included is series of defines which control
12227 +** various aspects of the generated parser.
12228 +** YYCODETYPE is the data type used for storing terminal
12229 +** and nonterminal numbers. "unsigned char" is
12230 +** used if there are fewer than 250 terminals
12231 +** and nonterminals. "int" is used otherwise.
12232 +** YYNOCODE is a number of type YYCODETYPE which corresponds
12233 +** to no legal terminal or nonterminal number. This
12234 +** number is used to fill in empty slots of the hash
12236 +** YYFALLBACK If defined, this indicates that one or more tokens
12237 +** have fall-back values which should be used if the
12238 +** original value of the token will not parse.
12239 +** YYACTIONTYPE is the data type used for storing terminal
12240 +** and nonterminal numbers. "unsigned char" is
12241 +** used if there are fewer than 250 rules and
12242 +** states combined. "int" is used otherwise.
12243 +** http_resp_parserTOKENTYPE is the data type used for minor tokens given
12244 +** directly to the parser from the tokenizer.
12245 +** YYMINORTYPE is the data type used for all minor tokens.
12246 +** This is typically a union of many types, one of
12247 +** which is http_resp_parserTOKENTYPE. The entry in the union
12248 +** for base tokens is called "yy0".
12249 +** YYSTACKDEPTH is the maximum depth of the parser's stack.
12250 +** http_resp_parserARG_SDECL A static variable declaration for the %extra_argument
12251 +** http_resp_parserARG_PDECL A parameter declaration for the %extra_argument
12252 +** http_resp_parserARG_STORE Code to store %extra_argument into yypParser
12253 +** http_resp_parserARG_FETCH Code to extract %extra_argument from yypParser
12254 +** YYNSTATE the combined number of states.
12255 +** YYNRULE the number of rules in the grammar
12256 +** YYERRORSYMBOL is the code number of the error symbol. If not
12257 +** defined, then do no error processing.
12260 +#define YYCODETYPE unsigned char
12261 +#define YYNOCODE 12
12262 +#define YYACTIONTYPE unsigned char
12263 +#define http_resp_parserTOKENTYPE buffer *
12265 + http_resp_parserTOKENTYPE yy0;
12267 + data_string * yy9;
12272 +#define YYSTACKDEPTH 100
12273 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
12274 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
12275 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
12276 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
12277 +#define YYNSTATE 19
12279 +#define YYERRORSYMBOL 4
12280 +#define YYERRSYMDT yy23
12281 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
12282 +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
12283 +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
12285 +/* Next are that tables used to determine what action to take based on the
12286 +** current state and lookahead token. These tables are used to implement
12287 +** functions that take a state number and lookahead value and return an
12288 +** action integer.
12290 +** Suppose the action integer is N. Then the action is determined as
12293 +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
12294 +** token onto the stack and goto state N.
12296 +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
12298 +** N == YYNSTATE+YYNRULE A syntax error has occurred.
12300 +** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
12302 +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
12303 +** slots in the yy_action[] table.
12305 +** The action table is constructed as a single large table named yy_action[].
12306 +** Given state S and lookahead X, the action is computed as
12308 +** yy_action[ yy_shift_ofst[S] + X ]
12310 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
12311 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
12312 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
12313 +** and that yy_default[S] should be used instead.
12315 +** The formula above is for computing the action when the lookahead is
12316 +** a terminal symbol. If the lookahead is a non-terminal (as occurs after
12317 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
12318 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
12319 +** YY_SHIFT_USE_DFLT.
12321 +** The following are the tables generated in this section:
12323 +** yy_action[] A single table containing all actions.
12324 +** yy_lookahead[] A table containing the lookahead for each entry in
12325 +** yy_action. Used to detect hash collisions.
12326 +** yy_shift_ofst[] For each state, the offset into yy_action for
12327 +** shifting terminals.
12328 +** yy_reduce_ofst[] For each state, the offset into yy_action for
12329 +** shifting non-terminals after a reduce.
12330 +** yy_default[] Default action for each state.
12332 +static YYACTIONTYPE yy_action[] = {
12333 + /* 0 */ 8, 29, 18, 1, 14, 2, 4, 11, 15, 12,
12334 + /* 10 */ 14, 13, 4, 21, 5, 19, 3, 5, 6, 7,
12335 + /* 20 */ 9, 17, 16, 4, 20, 22, 22, 10,
12337 +static YYCODETYPE yy_lookahead[] = {
12338 + /* 0 */ 5, 6, 2, 8, 9, 1, 2, 1, 2, 8,
12339 + /* 10 */ 9, 1, 2, 2, 3, 0, 9, 3, 2, 1,
12340 + /* 20 */ 7, 2, 2, 2, 0, 2, 11, 10,
12342 +#define YY_SHIFT_USE_DFLT (-1)
12343 +static signed char yy_shift_ofst[] = {
12344 + /* 0 */ 0, 4, 15, -1, 14, 16, 18, -1, 19, 20,
12345 + /* 10 */ 6, 21, 10, 24, -1, -1, -1, 23, 11,
12347 +#define YY_REDUCE_USE_DFLT (-6)
12348 +static signed char yy_reduce_ofst[] = {
12349 + /* 0 */ -5, 7, -6, -6, -6, -6, -6, -6, 13, 17,
12350 + /* 10 */ -6, 1, 7, -6, -6, -6, -6, -6, -6,
12352 +static YYACTIONTYPE yy_default[] = {
12353 + /* 0 */ 28, 28, 28, 25, 28, 28, 28, 27, 28, 28,
12354 + /* 10 */ 28, 28, 28, 28, 26, 24, 23, 28, 28,
12356 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
12358 +/* The next table maps tokens into fallback tokens. If a construct
12359 +** like the following:
12361 +** %fallback ID X Y Z.
12363 +** appears in the grammer, then ID becomes a fallback token for X, Y,
12364 +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
12365 +** but it does not parse, the type of the token is changed to ID and
12366 +** the parse is retried before an error is thrown.
12369 +static const YYCODETYPE yyFallback[] = {
12371 +#endif /* YYFALLBACK */
12373 +/* The following structure represents a single element of the
12374 +** parser's stack. Information stored includes:
12376 +** + The state number for the parser at this level of the stack.
12378 +** + The value of the token stored at this level of the stack.
12379 +** (In other words, the "major" token.)
12381 +** + The semantic value stored at this level of the stack. This is
12382 +** the information used by the action routines in the grammar.
12383 +** It is sometimes called the "minor" token.
12385 +struct yyStackEntry {
12386 + int stateno; /* The state-number */
12387 + int major; /* The major token value. This is the code
12388 + ** number for the token at this stack level */
12389 + YYMINORTYPE minor; /* The user-supplied minor token value. This
12390 + ** is the value of the token */
12392 +typedef struct yyStackEntry yyStackEntry;
12394 +/* The state of the parser is completely contained in an instance of
12395 +** the following structure */
12397 + int yyidx; /* Index of top element in stack */
12398 + int yyerrcnt; /* Shifts left before out of the error */
12399 + http_resp_parserARG_SDECL /* A place to hold %extra_argument */
12400 + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
12402 +typedef struct yyParser yyParser;
12405 +#include <stdio.h>
12406 +static FILE *yyTraceFILE = 0;
12407 +static char *yyTracePrompt = 0;
12408 +#endif /* NDEBUG */
12412 +** Turn parser tracing on by giving a stream to which to write the trace
12413 +** and a prompt to preface each trace message. Tracing is turned off
12414 +** by making either argument NULL
12418 +** <li> A FILE* to which trace output should be written.
12419 +** If NULL, then tracing is turned off.
12420 +** <li> A prefix string written at the beginning of every
12421 +** line of trace output. If NULL, then tracing is
12428 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
12429 + yyTraceFILE = TraceFILE;
12430 + yyTracePrompt = zTracePrompt;
12431 + if( yyTraceFILE==0 ) yyTracePrompt = 0;
12432 + else if( yyTracePrompt==0 ) yyTraceFILE = 0;
12434 +#endif /* NDEBUG */
12437 +/* For tracing shifts, the names of all terminals and nonterminals
12438 +** are required. The following table supplies these names */
12439 +static const char *yyTokenName[] = {
12440 + "$", "CRLF", "STRING", "COLON",
12441 + "error", "protocol", "response_hdr", "number",
12442 + "headers", "header", "reason",
12444 +#endif /* NDEBUG */
12447 +/* For tracing reduce actions, the names of all rules are required.
12449 +static const char *yyRuleName[] = {
12450 + /* 0 */ "response_hdr ::= headers CRLF",
12451 + /* 1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
12452 + /* 2 */ "protocol ::= STRING",
12453 + /* 3 */ "number ::= STRING",
12454 + /* 4 */ "reason ::= STRING",
12455 + /* 5 */ "reason ::= reason STRING",
12456 + /* 6 */ "headers ::= headers header",
12457 + /* 7 */ "headers ::= header",
12458 + /* 8 */ "header ::= STRING COLON STRING CRLF",
12460 +#endif /* NDEBUG */
12463 +** This function returns the symbolic name associated with a token
12466 +const char *http_resp_parserTokenName(int tokenType){
12468 + if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
12469 + return yyTokenName[tokenType];
12471 + return "Unknown";
12479 +** This function allocates a new parser.
12480 +** The only argument is a pointer to a function which works like
12484 +** A pointer to the function used to allocate memory.
12487 +** A pointer to a parser. This pointer is used in subsequent calls
12488 +** to http_resp_parser and http_resp_parserFree.
12490 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
12491 + yyParser *pParser;
12492 + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
12494 + pParser->yyidx = -1;
12499 +/* The following function deletes the value associated with a
12500 +** symbol. The symbol can be either a terminal or nonterminal.
12501 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
12504 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
12505 + switch( yymajor ){
12506 + /* Here is inserted the actions which take place when a
12507 + ** terminal or non-terminal is destroyed. This can happen
12508 + ** when the symbol is popped from the stack during a
12509 + ** reduce or during error processing or when a parser is
12510 + ** being destroyed before it is finished parsing.
12512 + ** Note: during a reduce, the only symbols destroyed are those
12513 + ** which appear on the RHS of the rule, but which are not used
12514 + ** inside the C code.
12519 +#line 25 "./http_resp_parser.y"
12520 +{ buffer_free((yypminor->yy0)); }
12521 +#line 327 "http_resp_parser.c"
12524 +#line 24 "./http_resp_parser.y"
12525 +{ buffer_free((yypminor->yy0)); }
12526 +#line 332 "http_resp_parser.c"
12528 + default: break; /* If no destructor action specified: do nothing */
12533 +** Pop the parser's stack once.
12535 +** If there is a destructor routine associated with the token which
12536 +** is popped from the stack, then call it.
12538 +** Return the major token number for the symbol popped.
12540 +static int yy_pop_parser_stack(yyParser *pParser){
12541 + YYCODETYPE yymajor;
12542 + yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
12544 + if( pParser->yyidx<0 ) return 0;
12546 + if( yyTraceFILE && pParser->yyidx>=0 ){
12547 + fprintf(yyTraceFILE,"%sPopping %s\n",
12549 + yyTokenName[yytos->major]);
12552 + yymajor = yytos->major;
12553 + yy_destructor( yymajor, &yytos->minor);
12554 + pParser->yyidx--;
12559 +** Deallocate and destroy a parser. Destructors are all called for
12560 +** all stack elements before shutting the parser down.
12564 +** <li> A pointer to the parser. This should be a pointer
12565 +** obtained from http_resp_parserAlloc.
12566 +** <li> A pointer to a function used to reclaim memory obtained
12570 +void http_resp_parserFree(
12571 + void *p, /* The parser to be deleted */
12572 + void (*freeProc)(void*) /* Function used to reclaim memory */
12574 + yyParser *pParser = (yyParser*)p;
12575 + if( pParser==0 ) return;
12576 + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
12577 + (*freeProc)((void*)pParser);
12581 +** Find the appropriate action for a parser given the terminal
12582 +** look-ahead token iLookAhead.
12584 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12585 +** independent of the look-ahead. If it is, return the action, otherwise
12586 +** return YY_NO_ACTION.
12588 +static int yy_find_shift_action(
12589 + yyParser *pParser, /* The parser */
12590 + int iLookAhead /* The look-ahead token */
12593 + int stateno = pParser->yystack[pParser->yyidx].stateno;
12595 + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
12596 + i = yy_shift_ofst[stateno];
12597 + if( i==YY_SHIFT_USE_DFLT ){
12598 + return yy_default[stateno];
12600 + if( iLookAhead==YYNOCODE ){
12601 + return YY_NO_ACTION;
12604 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12606 + int iFallback; /* Fallback token */
12607 + if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
12608 + && (iFallback = yyFallback[iLookAhead])!=0 ){
12610 + if( yyTraceFILE ){
12611 + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
12612 + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
12615 + return yy_find_shift_action(pParser, iFallback);
12618 + return yy_default[stateno];
12620 + return yy_action[i];
12625 +** Find the appropriate action for a parser given the non-terminal
12626 +** look-ahead token iLookAhead.
12628 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12629 +** independent of the look-ahead. If it is, return the action, otherwise
12630 +** return YY_NO_ACTION.
12632 +static int yy_find_reduce_action(
12633 + yyParser *pParser, /* The parser */
12634 + int iLookAhead /* The look-ahead token */
12637 + int stateno = pParser->yystack[pParser->yyidx].stateno;
12639 + i = yy_reduce_ofst[stateno];
12640 + if( i==YY_REDUCE_USE_DFLT ){
12641 + return yy_default[stateno];
12643 + if( iLookAhead==YYNOCODE ){
12644 + return YY_NO_ACTION;
12647 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12648 + return yy_default[stateno];
12650 + return yy_action[i];
12655 +** Perform a shift action.
12657 +static void yy_shift(
12658 + yyParser *yypParser, /* The parser to be shifted */
12659 + int yyNewState, /* The new state to shift in */
12660 + int yyMajor, /* The major token to shift in */
12661 + YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
12663 + yyStackEntry *yytos;
12664 + yypParser->yyidx++;
12665 + if( yypParser->yyidx>=YYSTACKDEPTH ){
12666 + http_resp_parserARG_FETCH;
12667 + yypParser->yyidx--;
12669 + if( yyTraceFILE ){
12670 + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
12673 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12674 + /* Here code is inserted which will execute if the parser
12675 + ** stack every overflows */
12676 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
12679 + yytos = &yypParser->yystack[yypParser->yyidx];
12680 + yytos->stateno = yyNewState;
12681 + yytos->major = yyMajor;
12682 + yytos->minor = *yypMinor;
12684 + if( yyTraceFILE && yypParser->yyidx>0 ){
12686 + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
12687 + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
12688 + for(i=1; i<=yypParser->yyidx; i++)
12689 + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
12690 + fprintf(yyTraceFILE,"\n");
12695 +/* The following table contains information about every rule that
12696 +** is used during the reduce.
12699 + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
12700 + unsigned char nrhs; /* Number of right-hand side symbols in the rule */
12701 +} yyRuleInfo[] = {
12713 +static void yy_accept(yyParser*); /* Forward Declaration */
12716 +** Perform a reduce action and the shift that must immediately
12717 +** follow the reduce.
12719 +static void yy_reduce(
12720 + yyParser *yypParser, /* The parser */
12721 + int yyruleno /* Number of the rule by which to reduce */
12723 + int yygoto; /* The next state */
12724 + int yyact; /* The next action */
12725 + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
12726 + yyStackEntry *yymsp; /* The top of the parser's stack */
12727 + int yysize; /* Amount to pop the stack */
12728 + http_resp_parserARG_FETCH;
12729 + yymsp = &yypParser->yystack[yypParser->yyidx];
12731 + if( yyTraceFILE && yyruleno>=0
12732 + && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
12733 + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
12734 + yyRuleName[yyruleno]);
12736 +#endif /* NDEBUG */
12738 + switch( yyruleno ){
12739 + /* Beginning here are the reduction cases. A typical example
12742 + ** #line <lineno> <grammarfile>
12743 + ** { ... } // User supplied code
12744 + ** #line <lineno> <thisfile>
12748 +#line 28 "./http_resp_parser.y"
12750 + http_resp *resp = ctx->resp;
12753 + resp->protocol = HTTP_VERSION_UNSET;
12755 + buffer_copy_string(resp->reason, ""); /* no reason */
12756 + array_free(resp->headers);
12757 + resp->headers = yymsp[-1].minor.yy12;
12759 + if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) {
12760 + resp->status = 0;
12763 + resp->status = strtol(ds->value->ptr, &err, 10);
12765 + if (*err != '\0' && *err != ' ') {
12766 + buffer_copy_string(ctx->errmsg, "expected a number: ");
12767 + buffer_append_string_buffer(ctx->errmsg, ds->value);
12768 + buffer_append_string(ctx->errmsg, err);
12774 + yymsp[-1].minor.yy12 = NULL;
12776 +#line 582 "http_resp_parser.c"
12777 + yy_destructor(1,&yymsp[0].minor);
12780 +#line 56 "./http_resp_parser.y"
12782 + http_resp *resp = ctx->resp;
12784 + resp->status = yymsp[-4].minor.yy20;
12785 + resp->protocol = yymsp[-5].minor.yy20;
12786 + buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
12787 + buffer_free(yymsp[-3].minor.yy0);
12789 + array_free(resp->headers);
12791 + resp->headers = yymsp[-1].minor.yy12;
12793 +#line 599 "http_resp_parser.c"
12794 + yy_destructor(1,&yymsp[-2].minor);
12795 + yy_destructor(1,&yymsp[0].minor);
12798 +#line 69 "./http_resp_parser.y"
12800 + if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
12801 + yygotominor.yy20 = HTTP_VERSION_1_0;
12802 + } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
12803 + yygotominor.yy20 = HTTP_VERSION_1_1;
12805 + buffer_copy_string(ctx->errmsg, "unknown protocol: ");
12806 + buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12810 + buffer_free(yymsp[0].minor.yy0);
12812 +#line 618 "http_resp_parser.c"
12815 +#line 83 "./http_resp_parser.y"
12818 + yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
12820 + if (*err != '\0') {
12821 + buffer_copy_string(ctx->errmsg, "expected a number, got: ");
12822 + buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12826 + buffer_free(yymsp[0].minor.yy0);
12828 +#line 634 "http_resp_parser.c"
12831 +#line 96 "./http_resp_parser.y"
12833 + yygotominor.yy0 = yymsp[0].minor.yy0;
12835 +#line 641 "http_resp_parser.c"
12838 +#line 100 "./http_resp_parser.y"
12840 + yygotominor.yy0 = yymsp[-1].minor.yy0;
12842 + buffer_append_string(yygotominor.yy0, " ");
12843 + buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
12845 + buffer_free(yymsp[0].minor.yy0);
12847 +#line 653 "http_resp_parser.c"
12850 +#line 109 "./http_resp_parser.y"
12852 + yygotominor.yy12 = yymsp[-1].minor.yy12;
12854 + array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12856 +#line 662 "http_resp_parser.c"
12859 +#line 115 "./http_resp_parser.y"
12861 + yygotominor.yy12 = array_init();
12863 + array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12865 +#line 671 "http_resp_parser.c"
12868 +#line 120 "./http_resp_parser.y"
12870 + yygotominor.yy9 = data_string_init();
12872 + buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
12873 + buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);
12874 + buffer_free(yymsp[-3].minor.yy0);
12875 + buffer_free(yymsp[-1].minor.yy0);
12877 +#line 683 "http_resp_parser.c"
12878 + yy_destructor(3,&yymsp[-2].minor);
12879 + yy_destructor(1,&yymsp[0].minor);
12882 + yygoto = yyRuleInfo[yyruleno].lhs;
12883 + yysize = yyRuleInfo[yyruleno].nrhs;
12884 + yypParser->yyidx -= yysize;
12885 + yyact = yy_find_reduce_action(yypParser,yygoto);
12886 + if( yyact < YYNSTATE ){
12887 + yy_shift(yypParser,yyact,yygoto,&yygotominor);
12888 + }else if( yyact == YYNSTATE + YYNRULE + 1 ){
12889 + yy_accept(yypParser);
12894 +** The following code executes when the parse fails
12896 +static void yy_parse_failed(
12897 + yyParser *yypParser /* The parser */
12899 + http_resp_parserARG_FETCH;
12901 + if( yyTraceFILE ){
12902 + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
12905 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12906 + /* Here code is inserted which will be executed whenever the
12907 + ** parser fails */
12908 +#line 15 "./http_resp_parser.y"
12912 +#line 718 "http_resp_parser.c"
12913 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12917 +** The following code executes when a syntax error first occurs.
12919 +static void yy_syntax_error(
12920 + yyParser *yypParser, /* The parser */
12921 + int yymajor, /* The major type of the error token */
12922 + YYMINORTYPE yyminor /* The minor type of the error token */
12924 + http_resp_parserARG_FETCH;
12925 +#define TOKEN (yyminor.yy0)
12926 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12930 +** The following is executed when the parser accepts
12932 +static void yy_accept(
12933 + yyParser *yypParser /* The parser */
12935 + http_resp_parserARG_FETCH;
12937 + if( yyTraceFILE ){
12938 + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
12941 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12942 + /* Here code is inserted which will be executed whenever the
12943 + ** parser accepts */
12944 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12947 +/* The main parser program.
12948 +** The first argument is a pointer to a structure obtained from
12949 +** "http_resp_parserAlloc" which describes the current state of the parser.
12950 +** The second argument is the major token number. The third is
12951 +** the minor token. The fourth optional argument is whatever the
12952 +** user wants (and specified in the grammar) and is available for
12953 +** use by the action routines.
12957 +** <li> A pointer to the parser (an opaque structure.)
12958 +** <li> The major token number.
12959 +** <li> The minor token number.
12960 +** <li> An option argument of a grammar-specified type.
12966 +void http_resp_parser(
12967 + void *yyp, /* The parser */
12968 + int yymajor, /* The major token code number */
12969 + http_resp_parserTOKENTYPE yyminor /* The value for the token */
12970 + http_resp_parserARG_PDECL /* Optional %extra_argument parameter */
12972 + YYMINORTYPE yyminorunion;
12973 + int yyact; /* The parser action. */
12974 + int yyendofinput; /* True if we are at the end of input */
12975 + int yyerrorhit = 0; /* True if yymajor has invoked an error */
12976 + yyParser *yypParser; /* The parser */
12978 + /* (re)initialize the parser, if necessary */
12979 + yypParser = (yyParser*)yyp;
12980 + if( yypParser->yyidx<0 ){
12981 + if( yymajor==0 ) return;
12982 + yypParser->yyidx = 0;
12983 + yypParser->yyerrcnt = -1;
12984 + yypParser->yystack[0].stateno = 0;
12985 + yypParser->yystack[0].major = 0;
12987 + yyminorunion.yy0 = yyminor;
12988 + yyendofinput = (yymajor==0);
12989 + http_resp_parserARG_STORE;
12992 + if( yyTraceFILE ){
12993 + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
12998 + yyact = yy_find_shift_action(yypParser,yymajor);
12999 + if( yyact<YYNSTATE ){
13000 + yy_shift(yypParser,yyact,yymajor,&yyminorunion);
13001 + yypParser->yyerrcnt--;
13002 + if( yyendofinput && yypParser->yyidx>=0 ){
13005 + yymajor = YYNOCODE;
13007 + }else if( yyact < YYNSTATE + YYNRULE ){
13008 + yy_reduce(yypParser,yyact-YYNSTATE);
13009 + }else if( yyact == YY_ERROR_ACTION ){
13012 + if( yyTraceFILE ){
13013 + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
13016 +#ifdef YYERRORSYMBOL
13017 + /* A syntax error has occurred.
13018 + ** The response to an error depends upon whether or not the
13019 + ** grammar defines an error token "ERROR".
13021 + ** This is what we do if the grammar does define ERROR:
13023 + ** * Call the %syntax_error function.
13025 + ** * Begin popping the stack until we enter a state where
13026 + ** it is legal to shift the error symbol, then shift
13027 + ** the error symbol.
13029 + ** * Set the error count to three.
13031 + ** * Begin accepting and shifting new tokens. No new error
13032 + ** processing will occur until three tokens have been
13033 + ** shifted successfully.
13036 + if( yypParser->yyerrcnt<0 ){
13037 + yy_syntax_error(yypParser,yymajor,yyminorunion);
13039 + yymx = yypParser->yystack[yypParser->yyidx].major;
13040 + if( yymx==YYERRORSYMBOL || yyerrorhit ){
13042 + if( yyTraceFILE ){
13043 + fprintf(yyTraceFILE,"%sDiscard input token %s\n",
13044 + yyTracePrompt,yyTokenName[yymajor]);
13047 + yy_destructor(yymajor,&yyminorunion);
13048 + yymajor = YYNOCODE;
13051 + yypParser->yyidx >= 0 &&
13052 + yymx != YYERRORSYMBOL &&
13053 + (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
13055 + yy_pop_parser_stack(yypParser);
13057 + if( yypParser->yyidx < 0 || yymajor==0 ){
13058 + yy_destructor(yymajor,&yyminorunion);
13059 + yy_parse_failed(yypParser);
13060 + yymajor = YYNOCODE;
13061 + }else if( yymx!=YYERRORSYMBOL ){
13063 + u2.YYERRSYMDT = 0;
13064 + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
13067 + yypParser->yyerrcnt = 3;
13069 +#else /* YYERRORSYMBOL is not defined */
13070 + /* This is what we do if the grammar does not define ERROR:
13072 + ** * Report an error message, and throw away the input token.
13074 + ** * If the input token is $, then fail the parse.
13076 + ** As before, subsequent error messages are suppressed until
13077 + ** three input tokens have been successfully shifted.
13079 + if( yypParser->yyerrcnt<=0 ){
13080 + yy_syntax_error(yypParser,yymajor,yyminorunion);
13082 + yypParser->yyerrcnt = 3;
13083 + yy_destructor(yymajor,&yyminorunion);
13084 + if( yyendofinput ){
13085 + yy_parse_failed(yypParser);
13087 + yymajor = YYNOCODE;
13090 + yy_accept(yypParser);
13091 + yymajor = YYNOCODE;
13093 + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
13096 --- ../lighttpd-1.4.11/src/http_resp_parser.h 1970-01-01 03:00:00.000000000 +0300
13097 +++ lighttpd-1.4.12/src/http_resp_parser.h 2006-07-18 13:03:52.000000000 +0300
13100 +#define TK_STRING 2
13101 +#define TK_COLON 3
13102 --- ../lighttpd-1.4.11/src/http_resp_parser.y 1970-01-01 03:00:00.000000000 +0300
13103 +++ lighttpd-1.4.12/src/http_resp_parser.y 2006-07-18 13:03:40.000000000 +0300
13106 +%token_type {buffer *}
13107 +%extra_argument {http_resp_ctx_t *ctx}
13108 +%name http_resp_parser
13111 +#include <assert.h>
13112 +#include <string.h>
13113 +#include "http_resp.h"
13114 +#include "keyvalue.h"
13115 +#include "array.h"
13123 +%type protocol { int }
13124 +%type response_hdr { http_resp * }
13125 +%type number { int }
13126 +%type headers { array * }
13127 +%type header { data_string * }
13128 +%destructor reason { buffer_free($$); }
13129 +%token_destructor { buffer_free($$); }
13131 +/* just headers + Status: ... */
13132 +response_hdr ::= headers(HDR) CRLF . {
13133 + http_resp *resp = ctx->resp;
13136 + resp->protocol = HTTP_VERSION_UNSET;
13138 + buffer_copy_string(resp->reason, ""); /* no reason */
13139 + array_free(resp->headers);
13140 + resp->headers = HDR;
13142 + if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) {
13143 + resp->status = 0;
13146 + resp->status = strtol(ds->value->ptr, &err, 10);
13148 + if (*err != '\0' && *err != ' ') {
13149 + buffer_copy_string(ctx->errmsg, "expected a number: ");
13150 + buffer_append_string_buffer(ctx->errmsg, ds->value);
13151 + buffer_append_string(ctx->errmsg, err);
13159 +/* HTTP/1.0 <status> ... */
13160 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
13161 + http_resp *resp = ctx->resp;
13163 + resp->status = C;
13164 + resp->protocol = B;
13165 + buffer_copy_string_buffer(resp->reason, D);
13168 + array_free(resp->headers);
13170 + resp->headers = HDR;
13173 +protocol(A) ::= STRING(B). {
13174 + if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
13175 + A = HTTP_VERSION_1_0;
13176 + } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
13177 + A = HTTP_VERSION_1_1;
13179 + buffer_copy_string(ctx->errmsg, "unknown protocol: ");
13180 + buffer_append_string_buffer(ctx->errmsg, B);
13187 +number(A) ::= STRING(B). {
13189 + A = strtol(B->ptr, &err, 10);
13191 + if (*err != '\0') {
13192 + buffer_copy_string(ctx->errmsg, "expected a number, got: ");
13193 + buffer_append_string_buffer(ctx->errmsg, B);
13200 +reason(A) ::= STRING(B). {
13204 +reason(A) ::= reason(C) STRING(B). {
13207 + buffer_append_string(A, " ");
13208 + buffer_append_string_buffer(A, B);
13213 +headers(HDRS) ::= headers(SRC) header(HDR). {
13216 + array_insert_unique(HDRS, (data_unset *)HDR);
13219 +headers(HDRS) ::= header(HDR). {
13220 + HDRS = array_init();
13222 + array_insert_unique(HDRS, (data_unset *)HDR);
13224 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
13225 + HDR = data_string_init();
13227 + buffer_copy_string_buffer(HDR->key, A);
13228 + buffer_copy_string_buffer(HDR->value, B);
13232 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c 2005-08-11 01:26:38.000000000 +0300
13233 +++ lighttpd-1.4.12/src/inet_ntop_cache.c 2006-07-16 00:26:04.000000000 +0300
13235 #include "sys-socket.h"
13237 const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
13241 for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
13242 if (srv->inet_ntop_cache[i].ts != 0) {
13243 @@ -20,31 +20,31 @@
13244 srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
13245 /* IPv4 found in cache */
13254 if (i == INET_NTOP_CACHE_MAX) {
13255 /* not found in cache */
13259 - inet_ntop(addr->plain.sa_family,
13260 - addr->plain.sa_family == AF_INET6 ?
13261 + inet_ntop(addr->plain.sa_family,
13262 + addr->plain.sa_family == AF_INET6 ?
13263 (const void *) &(addr->ipv6.sin6_addr) :
13264 (const void *) &(addr->ipv4.sin_addr),
13265 srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
13268 srv->inet_ntop_cache[i].ts = srv->cur_ts;
13269 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
13272 if (srv->inet_ntop_cache[i].family == AF_INET) {
13273 srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
13274 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
13275 memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
13280 return srv->inet_ntop_cache[i].b2;
13283 --- ../lighttpd-1.4.11/src/iosocket.c 1970-01-01 03:00:00.000000000 +0300
13284 +++ lighttpd-1.4.12/src/iosocket.c 2006-07-18 13:03:40.000000000 +0300
13286 +#include <stdlib.h>
13288 +#include "iosocket.h"
13289 +#include "sys-socket.h"
13290 +#include "sys-files.h"
13291 +#include "array-static.h"
13293 +iosocket *iosocket_init(void) {
13294 + STRUCT_INIT(iosocket, sock);
13296 + sock->fde_ndx = -1;
13299 + sock->type = IOSOCKET_TYPE_SOCKET;
13304 +void iosocket_free(iosocket *sock) {
13305 + if (!sock) return;
13307 + if (sock->fd != -1) {
13308 + switch (sock->type) {
13309 + case IOSOCKET_TYPE_SOCKET:
13310 + closesocket(sock->fd);
13312 + case IOSOCKET_TYPE_PIPE:
13322 --- ../lighttpd-1.4.11/src/iosocket.h 1970-01-01 03:00:00.000000000 +0300
13323 +++ lighttpd-1.4.12/src/iosocket.h 2006-07-20 01:14:57.000000000 +0300
13325 +#ifndef _IOSOCKET_H_
13326 +#define _IOSOCKET_H_
13329 + * make sure we know about OPENSSL all the time
13331 + * if we don't include config.h here we run into different sizes
13332 + * for the iosocket-struct depending on config.h include before
13333 + * iosocket.h or not
13336 +#ifdef HAVE_CONFIG_H
13337 +# include "config.h"
13340 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
13341 +# define USE_OPENSSL
13342 +# include <openssl/ssl.h>
13346 + IOSOCKET_TYPE_UNSET,
13347 + IOSOCKET_TYPE_SOCKET,
13348 + IOSOCKET_TYPE_PIPE
13352 + * a non-blocking fd
13358 +#ifdef USE_OPENSSL
13362 + iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
13365 +iosocket *iosocket_init(void);
13366 +void iosocket_free(iosocket *sock);
13369 --- ../lighttpd-1.4.11/src/joblist.c 2005-08-11 01:26:41.000000000 +0300
13370 +++ lighttpd-1.4.12/src/joblist.c 2006-07-16 00:26:03.000000000 +0300
13373 int joblist_append(server *srv, connection *con) {
13374 if (con->in_joblist) return 0;
13377 if (srv->joblist->size == 0) {
13378 srv->joblist->size = 16;
13379 srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
13380 @@ -15,15 +15,15 @@
13381 srv->joblist->size += 16;
13382 srv->joblist->ptr = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
13386 srv->joblist->ptr[srv->joblist->used++] = con;
13392 void joblist_free(server *srv, connections *joblist) {
13396 free(joblist->ptr);
13399 @@ -31,14 +31,14 @@
13400 connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
13407 if (fdwaitqueue->used == 0) return NULL;
13410 con = fdwaitqueue->ptr[0];
13413 memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
13420 srv->fdwaitqueue->size += 16;
13421 srv->fdwaitqueue->ptr = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
13425 srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
13431 --- ../lighttpd-1.4.11/src/keyvalue.c 2006-03-02 16:08:06.000000000 +0200
13432 +++ lighttpd-1.4.12/src/keyvalue.c 2006-07-16 00:26:03.000000000 +0300
13434 { 504, "Gateway Timeout" },
13435 { 505, "HTTP Version Not Supported" },
13436 { 507, "Insufficient Storage" }, /* WebDAV */
13438 + { 509, "Bandwidth Limit exceeded" },
13443 @@ -102,12 +103,12 @@
13444 { 501, "501.html" },
13445 { 503, "503.html" },
13446 { 505, "505.html" },
13453 -const char *keyvalue_get_value(keyvalue *kv, int k) {
13454 +const char *keyvalue_get_value(keyvalue *kv, int k) {
13456 for (i = 0; kv[i].value; i++) {
13457 if (kv[i].key == k) return kv[i].value;
13458 @@ -115,7 +116,7 @@
13462 -int keyvalue_get_key(keyvalue *kv, const char *s) {
13463 +int keyvalue_get_key(keyvalue *kv, const char *s) {
13465 for (i = 0; kv[i].value; i++) {
13466 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
13467 @@ -125,9 +126,9 @@
13469 keyvalue_buffer *keyvalue_buffer_init(void) {
13470 keyvalue_buffer *kvb;
13473 kvb = calloc(1, sizeof(*kvb));
13479 @@ -135,49 +136,49 @@
13481 if (kvb->size == 0) {
13485 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13488 for(i = 0; i < kvb->size; i++) {
13489 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13491 } else if (kvb->used == kvb->size) {
13495 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13498 for(i = kvb->used; i < kvb->size; i++) {
13499 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13504 kvb->kv[kvb->used]->key = key;
13505 kvb->kv[kvb->used]->value = strdup(value);
13514 void keyvalue_buffer_free(keyvalue_buffer *kvb) {
13518 for (i = 0; i < kvb->size; i++) {
13519 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13524 if (kvb->kv) free(kvb->kv);
13531 s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
13532 s_keyvalue_buffer *kvb;
13535 kvb = calloc(1, sizeof(*kvb));
13541 @@ -186,50 +187,50 @@
13542 if (kvb->size == 0) {
13547 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13550 for(i = 0; i < kvb->size; i++) {
13551 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13553 } else if (kvb->used == kvb->size) {
13557 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13560 for(i = kvb->used; i < kvb->size; i++) {
13561 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13566 kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
13567 kvb->kv[kvb->used]->value = strdup(value);
13576 void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
13580 for (i = 0; i < kvb->size; i++) {
13581 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13582 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13587 if (kvb->kv) free(kvb->kv);
13594 httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
13595 httpauth_keyvalue_buffer *kvb;
13598 kvb = calloc(1, sizeof(*kvb));
13604 @@ -237,42 +238,42 @@
13606 if (kvb->size == 0) {
13610 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13613 for(i = 0; i < kvb->size; i++) {
13614 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13616 } else if (kvb->used == kvb->size) {
13620 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13623 for(i = kvb->used; i < kvb->size; i++) {
13624 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13629 kvb->kv[kvb->used]->key = strdup(key);
13630 kvb->kv[kvb->used]->realm = strdup(realm);
13631 kvb->kv[kvb->used]->type = type;
13640 void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
13644 for (i = 0; i < kvb->size; i++) {
13645 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13646 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
13651 if (kvb->kv) free(kvb->kv);
13657 @@ -306,9 +307,9 @@
13659 pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
13660 pcre_keyvalue_buffer *kvb;
13663 kvb = calloc(1, sizeof(*kvb));
13669 @@ -319,46 +320,46 @@
13675 if (!key) return -1;
13678 if (kvb->size == 0) {
13683 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13686 for(i = 0; i < kvb->size; i++) {
13687 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13689 } else if (kvb->used == kvb->size) {
13693 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13696 for(i = kvb->used; i < kvb->size; i++) {
13697 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13702 kv = kvb->kv[kvb->used];
13703 if (NULL == (kv->key = pcre_compile(key,
13704 0, &errptr, &erroff, NULL))) {
13707 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
13711 - if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13712 + if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13718 kv->value = buffer_init_string(value);
13727 @@ -380,9 +381,9 @@
13728 if (kv->value) buffer_free(kv->value);
13733 if (kvb->kv) free(kvb->kv);
13739 --- ../lighttpd-1.4.11/src/keyvalue.h 2006-03-02 16:08:06.000000000 +0200
13740 +++ lighttpd-1.4.12/src/keyvalue.h 2006-07-16 00:26:04.000000000 +0300
13746 - HTTP_METHOD_UNSET = -1,
13748 - HTTP_METHOD_POST,
13749 - HTTP_METHOD_HEAD,
13750 - HTTP_METHOD_OPTIONS,
13752 + HTTP_METHOD_UNSET = -1,
13754 + HTTP_METHOD_POST,
13755 + HTTP_METHOD_HEAD,
13756 + HTTP_METHOD_OPTIONS,
13757 HTTP_METHOD_PROPFIND, /* WebDAV */
13758 - HTTP_METHOD_MKCOL,
13760 - HTTP_METHOD_DELETE,
13761 - HTTP_METHOD_COPY,
13762 - HTTP_METHOD_MOVE,
13763 - HTTP_METHOD_PROPPATCH,
13764 + HTTP_METHOD_MKCOL,
13766 + HTTP_METHOD_DELETE,
13767 + HTTP_METHOD_COPY,
13768 + HTTP_METHOD_MOVE,
13769 + HTTP_METHOD_PROPPATCH,
13770 HTTP_METHOD_REPORT, /* DeltaV */
13771 HTTP_METHOD_CHECKOUT,
13772 HTTP_METHOD_CHECKIN,
13773 @@ -39,13 +39,13 @@
13791 pcre_extra *key_extra;
13805 httpauth_type type;
13806 } httpauth_keyvalue;
13807 --- ../lighttpd-1.4.11/src/lemon.c 2005-09-01 00:21:34.000000000 +0300
13808 +++ lighttpd-1.4.12/src/lemon.c 2006-07-16 00:26:03.000000000 +0300
13809 @@ -579,7 +579,7 @@
13812 /* Find a precedence symbol of every rule in the grammar.
13815 ** Those rules which have a precedence symbol coded in the input
13816 ** grammar using the "[symbol]" construct will already have the
13817 ** rp->precsym field filled. Other rules take as their precedence
13818 @@ -869,7 +869,7 @@
13819 cfp->status = INCOMPLETE;
13826 for(i=0; i<lemp->nstate; i++){
13827 @@ -900,7 +900,7 @@
13831 - /* Add all of the reduce actions
13832 + /* Add all of the reduce actions
13833 ** A reduce action is added for each element of the followset of
13834 ** a configuration which has its dot at the extreme right.
13836 @@ -1017,7 +1017,7 @@
13837 apx->type = RD_RESOLVED;
13842 apx->type==SH_RESOLVED ||
13843 apx->type==RD_RESOLVED ||
13844 apx->type==CONFLICT ||
13845 @@ -1350,7 +1350,7 @@
13846 OptInit(argv,options,stderr);
13848 printf("Lemon version 1.0\n");
13852 if( OptNArgs() < 1 ){
13853 fprintf(stderr,"Exactly one filename argument is required.\n");
13854 @@ -2031,7 +2031,7 @@
13858 - rp = (struct rule *)malloc( sizeof(struct rule) +
13859 + rp = (struct rule *)malloc( sizeof(struct rule) +
13860 sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
13862 ErrorMsg(psp->filename,psp->tokenlineno,
13863 @@ -2546,7 +2546,7 @@
13867 -/* Duplicate the input file without comments and without actions
13868 +/* Duplicate the input file without comments and without actions
13871 struct lemon *lemp;
13872 @@ -2822,7 +2822,7 @@
13873 PRIVATE FILE *tplt_open(lemp)
13874 struct lemon *lemp;
13881 @@ -2930,7 +2930,7 @@
13887 ** Generate code which executes when the rule "rp" is reduced. Write
13888 ** the code to "out". Make sure lineno stays up-to-date.
13890 @@ -3384,7 +3384,7 @@
13892 /* Output the yy_shift_ofst[] table */
13893 fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
13894 - fprintf(out, "static %s yy_shift_ofst[] = {\n",
13895 + fprintf(out, "static %s yy_shift_ofst[] = {\n",
13896 minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
13898 for(i=j=0; i<n; i++){
13899 @@ -3405,7 +3405,7 @@
13901 /* Output the yy_reduce_ofst[] table */
13902 fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
13903 - fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13904 + fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13905 minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
13907 for(i=j=0; i<n; i++){
13908 @@ -3480,7 +3480,7 @@
13909 tplt_xfer(lemp->name,in,out,&lineno);
13911 /* Generate code which executes every time a symbol is popped from
13912 - ** the stack while processing errors or while destroying the parser.
13913 + ** the stack while processing errors or while destroying the parser.
13914 ** (In other words, generate the %destructor actions)
13916 if( lemp->tokendest ){
13917 @@ -3522,7 +3522,7 @@
13918 tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
13919 tplt_xfer(lemp->name,in,out,&lineno);
13921 - /* Generate the table of rule information
13922 + /* Generate the table of rule information
13924 ** Note: This code depends on the fact that rules are number
13925 ** sequentually beginning with 0.
13926 @@ -3589,7 +3589,7 @@
13927 for(i=1; i<lemp->nterminal; i++){
13928 fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
13935 @@ -3630,7 +3630,7 @@
13941 /* Do not make a default if the number of rules to default
13942 ** is not at least 2 */
13943 if( nbest<2 ) continue;
13944 @@ -3781,7 +3781,7 @@
13948 - x1a->tbl = (x1node*)malloc(
13949 + x1a->tbl = (x1node*)malloc(
13950 (sizeof(x1node) + sizeof(x1node*))*1024 );
13953 @@ -3943,7 +3943,7 @@
13957 - x2a->tbl = (x2node*)malloc(
13958 + x2a->tbl = (x2node*)malloc(
13959 (sizeof(x2node) + sizeof(x2node*))*128 );
13962 @@ -4149,7 +4149,7 @@
13966 - x3a->tbl = (x3node*)malloc(
13967 + x3a->tbl = (x3node*)malloc(
13968 (sizeof(x3node) + sizeof(x3node*))*128 );
13971 @@ -4295,7 +4295,7 @@
13975 - x4a->tbl = (x4node*)malloc(
13976 + x4a->tbl = (x4node*)malloc(
13977 (sizeof(x4node) + sizeof(x4node*))*64 );
13980 --- ../lighttpd-1.4.11/src/lempar.c 2005-08-11 01:26:40.000000000 +0300
13981 +++ lighttpd-1.4.12/src/lempar.c 2006-07-16 00:26:03.000000000 +0300
13983 /* Next is all token values, in a form suitable for use by makeheaders.
13984 ** This section will be null unless lemon is run with the -m switch.
13988 ** These constants (all generated automatically by the parser generator)
13989 ** specify the various kinds of tokens (terminals) that the parser
13993 ** Each symbol here is a terminal symbol in the grammar.
13996 ** and nonterminals. "int" is used otherwise.
13997 ** YYNOCODE is a number of type YYCODETYPE which corresponds
13998 ** to no legal terminal or nonterminal number. This
13999 -** number is used to fill in empty slots of the hash
14000 +** number is used to fill in empty slots of the hash
14002 ** YYFALLBACK If defined, this indicates that one or more tokens
14003 ** have fall-back values which should be used if the
14005 ** and nonterminal numbers. "unsigned char" is
14006 ** used if there are fewer than 250 rules and
14007 ** states combined. "int" is used otherwise.
14008 -** ParseTOKENTYPE is the data type used for minor tokens given
14009 +** ParseTOKENTYPE is the data type used for minor tokens given
14010 ** directly to the parser from the tokenizer.
14011 ** YYMINORTYPE is the data type used for all minor tokens.
14012 ** This is typically a union of many types, one of
14014 /* Next are that tables used to determine what action to take based on the
14015 ** current state and lookahead token. These tables are used to implement
14016 ** functions that take a state number and lookahead value and return an
14017 -** action integer.
14018 +** action integer.
14020 ** Suppose the action integer is N. Then the action is determined as
14023 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
14024 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
14025 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
14026 -** and that yy_default[S] should be used instead.
14027 +** and that yy_default[S] should be used instead.
14029 ** The formula above is for computing the action when the lookahead is
14030 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
14031 @@ -111,7 +111,7 @@
14033 /* The next table maps tokens into fallback tokens. If a construct
14034 ** like the following:
14037 ** %fallback ID X Y Z.
14039 ** appears in the grammer, then ID becomes a fallback token for X, Y,
14040 @@ -163,10 +163,10 @@
14041 #endif /* NDEBUG */
14046 ** Turn parser tracing on by giving a stream to which to write the trace
14047 ** and a prompt to preface each trace message. Tracing is turned off
14048 -** by making either argument NULL
14049 +** by making either argument NULL
14053 @@ -191,7 +191,7 @@
14055 /* For tracing shifts, the names of all terminals and nonterminals
14056 ** are required. The following table supplies these names */
14057 -static const char *yyTokenName[] = {
14058 +static const char *yyTokenName[] = {
14061 #endif /* NDEBUG */
14062 @@ -220,7 +220,7 @@
14068 ** This function allocates a new parser.
14069 ** The only argument is a pointer to a function which works like
14071 @@ -251,7 +251,7 @@
14072 /* Here is inserted the actions which take place when a
14073 ** terminal or non-terminal is destroyed. This can happen
14074 ** when the symbol is popped from the stack during a
14075 - ** reduce or during error processing or when a parser is
14076 + ** reduce or during error processing or when a parser is
14077 ** being destroyed before it is finished parsing.
14079 ** Note: during a reduce, the only symbols destroyed are those
14080 @@ -289,7 +289,7 @@
14086 ** Deallocate and destroy a parser. Destructors are all called for
14087 ** all stack elements before shutting the parser down.
14089 @@ -325,7 +325,7 @@
14092 int stateno = pParser->yystack[pParser->yyidx].stateno;
14095 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
14096 i = yy_shift_ofst[stateno];
14097 if( i==YY_SHIFT_USE_DFLT ){
14098 @@ -369,7 +369,7 @@
14101 int stateno = pParser->yystack[pParser->yyidx].stateno;
14104 i = yy_reduce_ofst[stateno];
14105 if( i==YY_REDUCE_USE_DFLT ){
14106 return yy_default[stateno];
14107 @@ -455,7 +455,7 @@
14109 yymsp = &yypParser->yystack[yypParser->yyidx];
14111 - if( yyTraceFILE && yyruleno>=0
14112 + if( yyTraceFILE && yyruleno>=0
14113 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
14114 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
14115 yyRuleName[yyruleno]);
14116 @@ -608,7 +608,7 @@
14117 #ifdef YYERRORSYMBOL
14118 /* A syntax error has occurred.
14119 ** The response to an error depends upon whether or not the
14120 - ** grammar defines an error token "ERROR".
14121 + ** grammar defines an error token "ERROR".
14123 ** This is what we do if the grammar does define ERROR:
14125 --- ../lighttpd-1.4.11/src/log.c 2005-11-07 15:01:35.000000000 +0200
14126 +++ lighttpd-1.4.12/src/log.c 2006-07-18 13:03:40.000000000 +0300
14131 -#include <unistd.h>
14132 #include <string.h>
14133 #include <stdlib.h>
14136 #include "config.h"
14140 +#undef HAVE_SYSLOG_H
14143 #ifdef HAVE_SYSLOG_H
14144 #include <syslog.h>
14150 +#include "sys-files.h"
14152 #ifdef HAVE_VALGRIND_VALGRIND_H
14153 #include <valgrind/valgrind.h>
14155 @@ -31,55 +36,114 @@
14156 # define O_LARGEFILE 0
14161 * open the errorlog
14164 * we have 3 possibilities:
14165 * - stderr (default)
14171 * if the open failed, report to the user and die
14176 -int log_error_open(server *srv) {
14180 + unsigned short use_syslog;
14182 + /* the errorlog */
14184 - int close_stderr = 1;
14185 + enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
14188 + time_t cached_ts;
14189 + buffer *cached_ts_str;
14192 +errorlog *myconfig = NULL;
14194 +void log_init(void) {
14198 + err = calloc(1, sizeof(*err));
14201 + err->mode = ERRORLOG_STDERR;
14202 + err->buf = buffer_init();
14203 + err->cached_ts_str = buffer_init();
14208 +void log_free(void) {
14209 + errorlog *err = myconfig;
14211 + if (!err) return;
14213 + TRACE("%s", "server stopped");
14215 + switch(err->mode) {
14216 + case ERRORLOG_FILE:
14219 + case ERRORLOG_SYSLOG:
14220 +#ifdef HAVE_SYSLOG_H
14224 + case ERRORLOG_STDERR:
14228 + buffer_free(err->buf);
14229 + buffer_free(err->cached_ts_str);
14230 + if (err->file) buffer_free(err->file);
14237 +int log_error_open(buffer *file, int use_syslog) {
14239 + int close_stderr = 1;
14241 + errorlog *err = myconfig;
14243 #ifdef HAVE_SYSLOG_H
14244 /* perhaps someone wants to use syslog() */
14245 openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
14247 - srv->errorlog_mode = ERRORLOG_STDERR;
14249 - if (srv->srvconf.errorlog_use_syslog) {
14250 - srv->errorlog_mode = ERRORLOG_SYSLOG;
14251 - } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
14252 - const char *logfile = srv->srvconf.errorlog_file->ptr;
14254 - if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14255 - log_error_write(srv, __FILE__, __LINE__, "SSSS",
14256 - "opening errorlog '", logfile,
14257 + err->mode = ERRORLOG_STDERR;
14259 + if (use_syslog) {
14260 + err->mode = ERRORLOG_SYSLOG;
14261 + } else if (!buffer_is_empty(file)) {
14262 + if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14263 + log_error_write(NULL, __FILE__, __LINE__, "SBSS",
14264 + "opening errorlog '", file,
14265 "' failed: ", strerror(errno));
14271 /* close fd on exec (cgi) */
14272 - fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
14273 + fcntl(err->fd, F_SETFD, FD_CLOEXEC);
14275 - srv->errorlog_mode = ERRORLOG_FILE;
14276 + err->mode = ERRORLOG_FILE;
14279 - log_error_write(srv, __FILE__, __LINE__, "s", "server started");
14282 + TRACE("%s", "server started");
14284 #ifdef HAVE_VALGRIND_VALGRIND_H
14285 /* don't close stderr for debugging purposes if run in valgrind */
14286 if (RUNNING_ON_VALGRIND) close_stderr = 0;
14288 - if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
14290 + if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
14292 /* move stderr to /dev/null */
14293 if (close_stderr &&
14294 -1 != (fd = open("/dev/null", O_WRONLY))) {
14295 @@ -90,167 +154,202 @@
14301 * open the errorlog
14304 * if the open failed, report to the user and die
14305 * if no filename is given, use syslog instead
14310 -int log_error_cycle(server *srv) {
14311 +int log_error_cycle(void) {
14312 /* only cycle if we are not in syslog-mode */
14314 - if (srv->errorlog_mode == ERRORLOG_FILE) {
14315 - const char *logfile = srv->srvconf.errorlog_file->ptr;
14317 + errorlog *err = myconfig;
14319 + if (err->mode == ERRORLOG_FILE) {
14320 + buffer *file = err->file;
14321 /* already check of opening time */
14326 - if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14328 + if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14329 /* write to old log */
14330 - log_error_write(srv, __FILE__, __LINE__, "SSSSS",
14331 - "cycling errorlog '", logfile,
14332 + log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
14333 + "cycling errorlog '", file,
14334 "' failed: ", strerror(errno),
14335 ", falling back to syslog()");
14337 - close(srv->errorlog_fd);
14338 - srv->errorlog_fd = -1;
14339 -#ifdef HAVE_SYSLOG_H
14340 - srv->errorlog_mode = ERRORLOG_SYSLOG;
14344 +#ifdef HAVE_SYSLOG_H
14345 + err->mode = ERRORLOG_SYSLOG;
14348 /* ok, new log is open, close the old one */
14349 - close(srv->errorlog_fd);
14350 - srv->errorlog_fd = new_fd;
14352 + err->fd = new_fd;
14356 - log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
14361 -int log_error_close(server *srv) {
14362 - log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
14364 - switch(srv->errorlog_mode) {
14365 - case ERRORLOG_FILE:
14366 - close(srv->errorlog_fd);
14368 - case ERRORLOG_SYSLOG:
14369 -#ifdef HAVE_SYSLOG_H
14373 - case ERRORLOG_STDERR:
14377 + TRACE("%s", "logfiles cycled");
14382 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14383 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14386 - switch(srv->errorlog_mode) {
14389 + errorlog *err = myconfig;
14391 + switch(err->mode) {
14392 case ERRORLOG_FILE:
14393 case ERRORLOG_STDERR:
14394 /* cache the generated timestamp */
14395 - if (srv->cur_ts != srv->last_generated_debug_ts) {
14396 - buffer_prepare_copy(srv->ts_debug_str, 255);
14397 - strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
14398 - srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
14400 - srv->last_generated_debug_ts = srv->cur_ts;
14403 + if (t != err->cached_ts) {
14404 + buffer_prepare_copy(err->cached_ts_str, 255);
14405 + strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
14406 + err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
14407 + err->cached_ts = t;
14410 - buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
14411 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
14412 + buffer_copy_string_buffer(err->buf, err->cached_ts_str);
14413 + BUFFER_APPEND_STRING_CONST(err->buf, ": (");
14415 case ERRORLOG_SYSLOG:
14416 /* syslog is generating its own timestamps */
14417 - BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
14418 + BUFFER_COPY_STRING_CONST(err->buf, "(");
14422 - buffer_append_string(srv->errorlog_buf, filename);
14423 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
14424 - buffer_append_long(srv->errorlog_buf, line);
14425 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
14429 + buffer_append_string(err->buf, filename);
14430 + BUFFER_APPEND_STRING_CONST(err->buf, ".");
14431 + buffer_append_long(err->buf, line);
14432 + BUFFER_APPEND_STRING_CONST(err->buf, ") ");
14434 for(va_start(ap, fmt); *fmt; fmt++) {
14442 case 's': /* string */
14443 s = va_arg(ap, char *);
14444 - buffer_append_string(srv->errorlog_buf, s);
14445 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14446 + buffer_append_string(err->buf, s);
14447 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14449 case 'b': /* buffer */
14450 b = va_arg(ap, buffer *);
14451 - buffer_append_string_buffer(srv->errorlog_buf, b);
14452 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14453 + buffer_append_string_buffer(err->buf, b);
14454 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14456 case 'd': /* int */
14457 d = va_arg(ap, int);
14458 - buffer_append_long(srv->errorlog_buf, d);
14459 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14460 + buffer_append_long(err->buf, d);
14461 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14463 case 'o': /* off_t */
14464 o = va_arg(ap, off_t);
14465 - buffer_append_off_t(srv->errorlog_buf, o);
14466 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14467 + buffer_append_off_t(err->buf, o);
14468 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14470 case 'x': /* int (hex) */
14471 d = va_arg(ap, int);
14472 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
14473 - buffer_append_long_hex(srv->errorlog_buf, d);
14474 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14475 + BUFFER_APPEND_STRING_CONST(err->buf, "0x");
14476 + buffer_append_long_hex(err->buf, d);
14477 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14479 case 'S': /* string */
14480 s = va_arg(ap, char *);
14481 - buffer_append_string(srv->errorlog_buf, s);
14482 + buffer_append_string(err->buf, s);
14484 case 'B': /* buffer */
14485 b = va_arg(ap, buffer *);
14486 - buffer_append_string_buffer(srv->errorlog_buf, b);
14487 + buffer_append_string_buffer(err->buf, b);
14489 case 'D': /* int */
14490 d = va_arg(ap, int);
14491 - buffer_append_long(srv->errorlog_buf, d);
14492 + buffer_append_long(err->buf, d);
14501 - buffer_append_string_len(srv->errorlog_buf, fmt, 1);
14502 + buffer_append_string_len(err->buf, fmt, 1);
14508 - switch(srv->errorlog_mode) {
14510 + switch(err->mode) {
14511 case ERRORLOG_FILE:
14512 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14513 - write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14514 + BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14515 + write(err->fd, err->buf->ptr, err->buf->used - 1);
14517 case ERRORLOG_STDERR:
14518 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14519 - write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14520 + BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14521 + write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
14523 +#ifdef HAVE_SYSLOG_H
14524 + case ERRORLOG_SYSLOG:
14525 + syslog(LOG_ERR, "%s", err->buf->ptr);
14533 +static int log_trace_write(const char *fmt, va_list ap) {
14536 + errorlog *err = myconfig;
14538 + b = buffer_init();
14539 + buffer_prepare_copy(b, 1024);
14540 + l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
14542 + b->used = (l > b->size - 1) ? b->size : l + 1;
14546 + switch(err->mode) {
14547 + case ERRORLOG_FILE:
14548 + buffer_append_string(b, "\r\n");
14549 + write(err->fd, b->ptr, b->used - 1);
14551 + case ERRORLOG_STDERR:
14552 + buffer_append_string(b, "\r\n");
14553 + write(STDERR_FILENO, b->ptr, b->used - 1);
14555 +#ifdef HAVE_SYSLOG_H
14556 case ERRORLOG_SYSLOG:
14557 - syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
14558 + syslog(LOG_ERR, "%s", b->ptr);
14568 +int log_trace(const char *fmt, ...) {
14571 + va_start(ap, fmt);
14573 + log_trace_write(fmt, ap);
14581 --- ../lighttpd-1.4.11/src/log.h 2005-08-11 01:26:36.000000000 +0300
14582 +++ lighttpd-1.4.12/src/log.h 2006-07-18 13:03:40.000000000 +0300
14587 -#include "server.h"
14588 +#include "buffer.h"
14590 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
14591 +void log_init(void);
14592 +void log_free(void);
14594 -int log_error_open(server *srv);
14595 -int log_error_close(server *srv);
14596 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
14597 -int log_error_cycle(server *srv);
14599 +int log_error_open(buffer *file, int use_syslog);
14600 +int log_error_close();
14601 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
14602 +int log_error_cycle();
14604 +#define ERROR(fmt, ...) \
14605 + log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14607 +#define TRACE(fmt, ...) \
14608 + log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14610 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
14611 +int log_trace(const char *fmt, ...);
14613 --- ../lighttpd-1.4.11/src/md5.h 2005-11-17 16:20:40.000000000 +0200
14614 +++ lighttpd-1.4.12/src/md5.h 2006-07-16 00:26:04.000000000 +0300
14616 # include <inttypes.h>
14620 +#define UINT4 unsigned __int32
14621 +#define UINT2 unsigned __int16
14622 +#define POINTER unsigned char *
14624 #define UINT4 uint32_t
14625 #define UINT2 uint16_t
14626 #define POINTER unsigned char *
14631 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
14632 +++ lighttpd-1.4.12/src/mod_access.c 2006-07-16 00:26:04.000000000 +0300
14633 @@ -8,126 +8,125 @@
14635 #include "plugin.h"
14637 +#include "sys-strings.h"
14640 array *access_deny;
14647 plugin_config **config_storage;
14649 - plugin_config conf;
14651 + plugin_config conf;
14654 INIT_FUNC(mod_access_init) {
14658 p = calloc(1, sizeof(*p));
14664 FREE_FUNC(mod_access_free) {
14665 plugin_data *p = p_d;
14670 if (!p) return HANDLER_GO_ON;
14673 if (p->config_storage) {
14675 for (i = 0; i < srv->config_context->used; i++) {
14676 plugin_config *s = p->config_storage[i];
14679 array_free(s->access_deny);
14684 free(p->config_storage);
14691 return HANDLER_GO_ON;
14694 SETDEFAULTS_FUNC(mod_access_set_defaults) {
14695 plugin_data *p = p_d;
14698 - config_values_t cv[] = {
14700 + config_values_t cv[] = {
14701 { "url.access-deny", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
14702 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
14706 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
14709 for (i = 0; i < srv->config_context->used; i++) {
14713 s = calloc(1, sizeof(plugin_config));
14714 s->access_deny = array_init();
14717 cv[0].destination = s->access_deny;
14720 p->config_storage[i] = s;
14723 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
14724 return HANDLER_ERROR;
14729 return HANDLER_GO_ON;
14732 -#define PATCH(x) \
14733 - p->conf.x = s->x;
14734 static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
14736 plugin_config *s = p->config_storage[0];
14738 - PATCH(access_deny);
14740 + PATCH_OPTION(access_deny);
14742 /* skip the first, the global context */
14743 for (i = 1; i < srv->config_context->used; i++) {
14744 data_config *dc = (data_config *)srv->config_context->data[i];
14745 s = p->config_storage[i];
14748 /* condition didn't match */
14749 if (!config_check_cond(srv, con, dc)) continue;
14753 for (j = 0; j < dc->value->used; j++) {
14754 data_unset *du = dc->value->data[j];
14757 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
14758 - PATCH(access_deny);
14759 + PATCH_OPTION(access_deny);
14769 URIHANDLER_FUNC(mod_access_uri_handler) {
14770 plugin_data *p = p_d;
14775 if (con->uri.path->used == 0) return HANDLER_GO_ON;
14778 mod_access_patch_connection(srv, con, p);
14781 s_len = con->uri.path->used - 1;
14784 for (k = 0; k < p->conf.access_deny->used; k++) {
14785 data_string *ds = (data_string *)p->conf.access_deny->data[k];
14786 int ct_len = ds->value->used - 1;
14789 if (ct_len > s_len) continue;
14792 if (ds->value->used == 0) continue;
14794 /* if we have a case-insensitive FS we have to lower-case the URI here too */
14795 @@ -135,18 +134,18 @@
14796 if (con->conf.force_lowercase_filenames) {
14797 if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14798 con->http_status = 403;
14801 return HANDLER_FINISHED;
14804 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14805 con->http_status = 403;
14808 return HANDLER_FINISHED;
14815 return HANDLER_GO_ON;
14817 @@ -155,13 +154,13 @@
14818 int mod_access_plugin_init(plugin *p) {
14819 p->version = LIGHTTPD_VERSION_ID;
14820 p->name = buffer_init_string("access");
14823 p->init = mod_access_init;
14824 p->set_defaults = mod_access_set_defaults;
14825 p->handle_uri_clean = mod_access_uri_handler;
14826 p->cleanup = mod_access_free;
14834 --- ../lighttpd-1.4.11/src/mod_accesslog.c 2006-01-31 14:01:43.000000000 +0200
14835 +++ lighttpd-1.4.12/src/mod_accesslog.c 2006-07-16 00:26:04.000000000 +0300
14838 #include <stdlib.h>
14839 #include <string.h>
14840 -#include <fcntl.h>
14841 -#include <unistd.h>
14842 +#include <fcntl.h> /* only the defines on windows */
14847 #include "inet_ntop_cache.h"
14849 #include "sys-socket.h"
14850 +#include "sys-files.h"
14852 #ifdef HAVE_SYSLOG_H
14853 # include <syslog.h>
14861 FORMAT_UNSUPPORTED,
14865 FORMAT_BYTES_OUT_NO_HEADER,
14869 FORMAT_REMOTE_ADDR,
14872 @@ -59,20 +59,20 @@
14873 FORMAT_CONNECTION_STATUS,
14878 FORMAT_RESPONSE_HEADER
14887 * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
14892 -const format_mapping fmap[] =
14894 +const format_mapping fmap[] =
14896 { '%', FORMAT_PERCENT },
14897 { 'h', FORMAT_REMOTE_HOST },
14898 { 'l', FORMAT_REMOTE_IDENT },
14900 { 's', FORMAT_STATUS },
14901 { 'b', FORMAT_BYTES_OUT_NO_HEADER },
14902 { 'i', FORMAT_HEADER },
14905 { 'a', FORMAT_REMOTE_ADDR },
14906 { 'A', FORMAT_LOCAL_ADDR },
14907 { 'B', FORMAT_BYTES_OUT_NO_HEADER },
14908 @@ -103,23 +103,23 @@
14909 { 'X', FORMAT_CONNECTION_STATUS },
14910 { 'I', FORMAT_BYTES_IN },
14911 { 'O', FORMAT_BYTES_OUT },
14914 { 'o', FORMAT_RESPONSE_HEADER },
14917 { '\0', FORMAT_UNSET }
14922 enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
14930 format_field **ptr;
14936 @@ -128,39 +128,39 @@
14937 buffer *access_logfile;
14939 unsigned short use_syslog;
14945 time_t last_generated_accesslog_ts;
14946 time_t *last_generated_accesslog_ts_ptr;
14951 buffer *access_logbuffer;
14952 buffer *ts_accesslog_str;
14955 format_fields *parsed_format;
14962 plugin_config **config_storage;
14963 - plugin_config conf;
14964 + plugin_config conf;
14967 INIT_FUNC(mod_accesslog_init) {
14971 p = calloc(1, sizeof(*p));
14977 int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
14978 size_t i, j, k = 0, start = 0;
14981 for (i = 0; i < format->used - 1; i++) {
14984 switch(format->ptr[i]) {
14987 @@ -173,19 +173,19 @@
14988 fields->size += 16;
14989 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14993 fields->ptr[fields->used] = malloc(sizeof(format_fields));
14994 fields->ptr[fields->used]->type = FIELD_STRING;
14995 fields->ptr[fields->used]->string = buffer_init();
14998 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
15007 /* we need a new field */
15010 if (fields->size == 0) {
15013 @@ -194,43 +194,43 @@
15014 fields->size += 16;
15015 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15019 /* search for the terminating command */
15020 switch (format->ptr[i+1]) {
15026 for (j = 0; fmap[j].key != '\0'; j++) {
15027 if (fmap[j].key != format->ptr[i+2]) continue;
15033 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15034 fields->ptr[fields->used]->type = FIELD_FORMAT;
15035 fields->ptr[fields->used]->field = fmap[j].type;
15036 fields->ptr[fields->used]->string = NULL;
15046 if (fmap[j].key == '\0') {
15047 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15057 /* go forward to } */
15060 for (k = i+2; k < format->used - 1; k++) {
15061 if (format->ptr[k] == '}') break;
15065 if (k == format->used - 1) {
15066 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15068 @@ -239,62 +239,62 @@
15069 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15074 for (j = 0; fmap[j].key != '\0'; j++) {
15075 if (fmap[j].key != format->ptr[k+1]) continue;
15081 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15082 fields->ptr[fields->used]->type = FIELD_FORMAT;
15083 fields->ptr[fields->used]->field = fmap[j].type;
15084 fields->ptr[fields->used]->string = buffer_init();
15087 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
15097 if (fmap[j].key == '\0') {
15098 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15108 for (j = 0; fmap[j].key != '\0'; j++) {
15109 if (fmap[j].key != format->ptr[i+1]) continue;
15115 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15116 fields->ptr[fields->used]->type = FIELD_FORMAT;
15117 fields->ptr[fields->used]->field = fmap[j].type;
15118 fields->ptr[fields->used]->string = NULL;
15128 if (fmap[j].key == '\0') {
15129 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15147 /* copy the string */
15148 if (fields->size == 0) {
15149 @@ -305,32 +305,32 @@
15150 fields->size += 16;
15151 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15155 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15156 fields->ptr[fields->used]->type = FIELD_STRING;
15157 fields->ptr[fields->used]->string = buffer_init();
15160 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
15170 FREE_FUNC(mod_accesslog_free) {
15171 plugin_data *p = p_d;
15175 if (!p) return HANDLER_GO_ON;
15178 if (p->config_storage) {
15181 for (i = 0; i < srv->config_context->used; i++) {
15182 plugin_config *s = p->config_storage[i];
15187 if (s->access_logbuffer->used) {
15188 if (s->use_syslog) {
15189 # ifdef HAVE_SYSLOG_H
15190 @@ -342,14 +342,14 @@
15191 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15196 if (s->log_access_fd != -1) close(s->log_access_fd);
15199 buffer_free(s->ts_accesslog_str);
15200 buffer_free(s->access_logbuffer);
15201 buffer_free(s->format);
15202 buffer_free(s->access_logfile);
15205 if (s->parsed_format) {
15207 for (j = 0; j < s->parsed_format->used; j++) {
15208 @@ -359,36 +359,36 @@
15209 free(s->parsed_format->ptr);
15210 free(s->parsed_format);
15218 free(p->config_storage);
15225 return HANDLER_GO_ON;
15228 SETDEFAULTS_FUNC(log_access_open) {
15229 plugin_data *p = p_d;
15232 - config_values_t cv[] = {
15234 + config_values_t cv[] = {
15235 { "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15236 { "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
15237 { "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15238 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15242 if (!p) return HANDLER_ERROR;
15245 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15248 for (i = 0; i < srv->config_context->used; i++) {
15252 s = calloc(1, sizeof(plugin_config));
15253 s->access_logfile = buffer_init();
15254 s->format = buffer_init();
15255 @@ -397,44 +397,44 @@
15256 s->log_access_fd = -1;
15257 s->last_generated_accesslog_ts = 0;
15258 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
15263 cv[0].destination = s->access_logfile;
15264 cv[1].destination = &(s->use_syslog);
15265 cv[2].destination = s->format;
15268 p->config_storage[i] = s;
15271 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15272 return HANDLER_ERROR;
15276 if (i == 0 && buffer_is_empty(s->format)) {
15277 /* set a default logfile string */
15280 buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
15287 if (s->format->used) {
15288 s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
15291 if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
15293 - log_error_write(srv, __FILE__, __LINE__, "sb",
15294 + log_error_write(srv, __FILE__, __LINE__, "sb",
15295 "parsing accesslog-definition failed:", s->format);
15297 return HANDLER_ERROR;
15302 for (j = 0; j < s->parsed_format->used; j++) {
15303 switch (s->parsed_format->ptr[j]->type) {
15305 - log_error_write(srv, __FILE__, __LINE__, "ssds",
15306 + log_error_write(srv, __FILE__, __LINE__, "ssds",
15307 "config:", "format", s->parsed_format->ptr[j]->field,
15308 - s->parsed_format->ptr[j]->string ?
15309 + s->parsed_format->ptr[j]->string ?
15310 s->parsed_format->ptr[j]->string->ptr : "" );
15313 @@ -446,52 +446,52 @@
15319 if (s->use_syslog) {
15320 /* ignore the next checks */
15325 if (buffer_is_empty(s->access_logfile)) continue;
15328 if (s->access_logfile->ptr[0] == '|') {
15330 /* create write pipe and spawn process */
15337 if (pipe(to_log_fds)) {
15338 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
15339 return HANDLER_ERROR;
15344 switch (pid = fork()) {
15350 close(STDIN_FILENO);
15351 dup2(to_log_fds[0], STDIN_FILENO);
15352 close(to_log_fds[0]);
15354 close(to_log_fds[1]);
15357 /* we don't need the client socket */
15358 for (i = 3; i < 256; i++) {
15362 - /* exec the log-process (skip the | )
15365 + /* exec the log-process (skip the | )
15370 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
15372 - log_error_write(srv, __FILE__, __LINE__, "sss",
15373 - "spawning log-process failed: ", strerror(errno),
15374 + log_error_write(srv, __FILE__, __LINE__, "sss",
15375 + "spawning log-process failed: ", strerror(errno),
15376 s->access_logfile->ptr + 1);
15382 @@ -500,27 +500,28 @@
15385 close(to_log_fds[0]);
15388 s->log_access_fd = to_log_fds[1];
15396 - } else if (-1 == (s->log_access_fd =
15397 + } else if (-1 == (s->log_access_fd =
15398 open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15400 - log_error_write(srv, __FILE__, __LINE__, "ssb",
15401 - "opening access-log failed:",
15403 + log_error_write(srv, __FILE__, __LINE__, "ssb",
15404 + "opening access-log failed:",
15405 strerror(errno), s->access_logfile);
15408 return HANDLER_ERROR;
15411 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
15417 return HANDLER_GO_ON;
15420 @@ -529,7 +530,7 @@
15423 if (!p->config_storage) return HANDLER_GO_ON;
15426 for (i = 0; i < srv->config_context->used; i++) {
15427 plugin_config *s = p->config_storage[i];
15429 @@ -544,90 +545,87 @@
15430 } else if (s->log_access_fd != -1) {
15431 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15435 buffer_reset(s->access_logbuffer);
15439 if (s->use_syslog == 0 &&
15440 !buffer_is_empty(s->access_logfile) &&
15441 s->access_logfile->ptr[0] != '|') {
15444 close(s->log_access_fd);
15446 - if (-1 == (s->log_access_fd =
15448 + if (-1 == (s->log_access_fd =
15449 open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15452 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
15455 return HANDLER_ERROR;
15461 return HANDLER_GO_ON;
15464 -#define PATCH(x) \
15465 - p->conf.x = s->x;
15466 static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
15468 plugin_config *s = p->config_storage[0];
15470 - PATCH(access_logfile);
15472 - PATCH(log_access_fd);
15473 - PATCH(last_generated_accesslog_ts_ptr);
15474 - PATCH(access_logbuffer);
15475 - PATCH(ts_accesslog_str);
15476 - PATCH(parsed_format);
15477 - PATCH(use_syslog);
15480 + PATCH_OPTION(access_logfile);
15481 + PATCH_OPTION(format);
15482 + PATCH_OPTION(log_access_fd);
15483 + PATCH_OPTION(last_generated_accesslog_ts_ptr);
15484 + PATCH_OPTION(access_logbuffer);
15485 + PATCH_OPTION(ts_accesslog_str);
15486 + PATCH_OPTION(parsed_format);
15487 + PATCH_OPTION(use_syslog);
15489 /* skip the first, the global context */
15490 for (i = 1; i < srv->config_context->used; i++) {
15491 data_config *dc = (data_config *)srv->config_context->data[i];
15492 s = p->config_storage[i];
15495 /* condition didn't match */
15496 if (!config_check_cond(srv, con, dc)) continue;
15500 for (j = 0; j < dc->value->used; j++) {
15501 data_unset *du = dc->value->data[j];
15504 if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
15505 - PATCH(access_logfile);
15506 - PATCH(log_access_fd);
15507 - PATCH(last_generated_accesslog_ts_ptr);
15508 - PATCH(access_logbuffer);
15509 - PATCH(ts_accesslog_str);
15510 + PATCH_OPTION(access_logfile);
15511 + PATCH_OPTION(log_access_fd);
15512 + PATCH_OPTION(last_generated_accesslog_ts_ptr);
15513 + PATCH_OPTION(access_logbuffer);
15514 + PATCH_OPTION(ts_accesslog_str);
15515 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
15517 - PATCH(parsed_format);
15518 + PATCH_OPTION(format);
15519 + PATCH_OPTION(parsed_format);
15520 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
15521 - PATCH(use_syslog);
15522 + PATCH_OPTION(use_syslog);
15532 REQUESTDONE_FUNC(log_access_write) {
15533 plugin_data *p = p_d;
15542 mod_accesslog_patch_connection(srv, con, p);
15545 b = p->conf.access_logbuffer;
15546 if (b->used == 0) {
15547 buffer_copy_string(b, "");
15551 for (j = 0; j < p->conf.parsed_format->used; j++) {
15552 switch(p->conf.parsed_format->ptr[j]->type) {
15554 @@ -636,14 +634,14 @@
15556 switch(p->conf.parsed_format->ptr[j]->field) {
15557 case FORMAT_TIMESTAMP:
15560 /* cache the generated timestamp */
15561 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
15563 #if defined(HAVE_STRUCT_TM_GMTOFF)
15564 long scd, hrs, min;
15568 buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
15569 #if defined(HAVE_STRUCT_TM_GMTOFF)
15570 # ifdef HAVE_LOCALTIME_R
15571 @@ -653,17 +651,17 @@
15572 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)));
15574 p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15577 buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
15580 scd = abs(tm.tm_gmtoff);
15582 min = (scd % 3600) / 60;
15586 if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15587 buffer_append_long(p->conf.ts_accesslog_str, hrs);
15590 if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15591 buffer_append_long(p->conf.ts_accesslog_str, min);
15592 BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
15593 @@ -676,20 +674,20 @@
15595 p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15599 *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
15604 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
15608 case FORMAT_REMOTE_HOST:
15611 /* handle inet_ntop cache */
15614 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
15618 case FORMAT_REMOTE_IDENT:
15620 @@ -710,10 +708,10 @@
15621 case FORMAT_STATUS:
15622 buffer_append_long(b, con->http_status);
15626 case FORMAT_BYTES_OUT_NO_HEADER:
15627 if (con->bytes_written > 0) {
15628 - buffer_append_off_t(b,
15629 + buffer_append_off_t(b,
15630 con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
15632 BUFFER_APPEND_STRING_CONST(b, "-");
15633 @@ -772,7 +770,7 @@
15636 case FORMAT_REQUEST_PROTOCOL:
15637 - buffer_append_string(b,
15638 + buffer_append_string(b,
15639 con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
15641 case FORMAT_REQUEST_METHOD:
15642 @@ -801,7 +799,7 @@
15643 { 'D', FORMAT_TIME_USED_MS },
15644 { 'e', FORMAT_ENV },
15651 @@ -809,7 +807,7 @@
15657 BUFFER_APPEND_STRING_CONST(b, "\n");
15659 if (p->conf.use_syslog || /* syslog doesn't cache */
15660 @@ -828,7 +826,7 @@
15666 return HANDLER_GO_ON;
15669 @@ -836,15 +834,15 @@
15670 int mod_accesslog_plugin_init(plugin *p) {
15671 p->version = LIGHTTPD_VERSION_ID;
15672 p->name = buffer_init_string("accesslog");
15675 p->init = mod_accesslog_init;
15676 p->set_defaults= log_access_open;
15677 p->cleanup = mod_accesslog_free;
15680 p->handle_request_done = log_access_write;
15681 p->handle_sighup = log_access_cycle;
15689 --- ../lighttpd-1.4.11/src/mod_alias.c 2006-03-01 23:18:51.000000000 +0200
15690 +++ lighttpd-1.4.12/src/mod_alias.c 2006-07-16 00:26:03.000000000 +0300
15692 #include "buffer.h"
15694 #include "plugin.h"
15695 +#include "sys-strings.h"
15697 /* plugin config for all request/connections */
15699 @@ -16,44 +17,44 @@
15705 plugin_config **config_storage;
15707 - plugin_config conf;
15709 + plugin_config conf;
15712 /* init the plugin data */
15713 INIT_FUNC(mod_alias_init) {
15717 p = calloc(1, sizeof(*p));
15727 /* detroy the plugin data */
15728 FREE_FUNC(mod_alias_free) {
15729 plugin_data *p = p_d;
15732 if (!p) return HANDLER_GO_ON;
15735 if (p->config_storage) {
15739 for (i = 0; i < srv->config_context->used; i++) {
15740 plugin_config *s = p->config_storage[i];
15743 array_free(s->alias);
15748 free(p->config_storage);
15755 return HANDLER_GO_ON;
15758 @@ -62,25 +63,25 @@
15759 SETDEFAULTS_FUNC(mod_alias_set_defaults) {
15760 plugin_data *p = p_d;
15763 - config_values_t cv[] = {
15765 + config_values_t cv[] = {
15766 { "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
15767 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15771 if (!p) return HANDLER_ERROR;
15774 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15777 for (i = 0; i < srv->config_context->used; i++) {
15781 s = calloc(1, sizeof(plugin_config));
15782 - s->alias = array_init();
15783 + s->alias = array_init();
15784 cv[0].destination = s->alias;
15787 p->config_storage[i] = s;
15790 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15791 return HANDLER_ERROR;
15793 @@ -110,76 +111,73 @@
15799 return HANDLER_GO_ON;
15802 -#define PATCH(x) \
15803 - p->conf.x = s->x;
15804 static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
15806 plugin_config *s = p->config_storage[0];
15811 + PATCH_OPTION(alias);
15813 /* skip the first, the global context */
15814 for (i = 1; i < srv->config_context->used; i++) {
15815 data_config *dc = (data_config *)srv->config_context->data[i];
15816 s = p->config_storage[i];
15819 /* condition didn't match */
15820 if (!config_check_cond(srv, con, dc)) continue;
15824 for (j = 0; j < dc->value->used; j++) {
15825 data_unset *du = dc->value->data[j];
15828 if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
15830 + PATCH_OPTION(alias);
15840 PHYSICALPATH_FUNC(mod_alias_physical_handler) {
15841 plugin_data *p = p_d;
15842 int uri_len, basedir_len;
15847 if (con->physical.path->used == 0) return HANDLER_GO_ON;
15850 mod_alias_patch_connection(srv, con, p);
15853 /* not to include the tailing slash */
15854 basedir_len = (con->physical.basedir->used - 1) - 1;
15855 uri_len = con->physical.path->used - 1 - basedir_len;
15856 uri_ptr = con->physical.path->ptr + basedir_len;
15859 for (k = 0; k < p->conf.alias->used; k++) {
15860 data_string *ds = (data_string *)p->conf.alias->data[k];
15861 int alias_len = ds->key->used - 1;
15864 if (alias_len > uri_len) continue;
15865 if (ds->key->used == 0) continue;
15868 if (0 == (con->conf.force_lowercase_filenames ?
15869 strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
15870 strncmp(uri_ptr, ds->key->ptr, alias_len))) {
15874 buffer_copy_string_buffer(con->physical.basedir, ds->value);
15875 buffer_copy_string_buffer(srv->tmp_buf, ds->value);
15876 buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
15877 buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
15880 return HANDLER_GO_ON;
15886 return HANDLER_GO_ON;
15888 @@ -189,13 +187,13 @@
15889 int mod_alias_plugin_init(plugin *p) {
15890 p->version = LIGHTTPD_VERSION_ID;
15891 p->name = buffer_init_string("alias");
15894 p->init = mod_alias_init;
15895 p->handle_physical= mod_alias_physical_handler;
15896 p->set_defaults = mod_alias_set_defaults;
15897 p->cleanup = mod_alias_free;
15905 --- ../lighttpd-1.4.11/src/mod_auth.c 2006-02-15 20:01:31.000000000 +0200
15906 +++ lighttpd-1.4.12/src/mod_auth.c 2006-07-18 13:03:40.000000000 +0300
15907 @@ -5,168 +5,167 @@
15908 #include <string.h>
15911 -#include <unistd.h>
15913 #include "plugin.h"
15914 #include "http_auth.h"
15916 #include "response.h"
15918 +#include "sys-strings.h"
15919 +#include "sys-files.h"
15921 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
15925 * the basic and digest auth framework
15928 * - config handling
15929 * - protocol handling
15932 - * http_auth_digest.c
15936 + * http_auth_digest.c
15941 INIT_FUNC(mod_auth_init) {
15942 mod_auth_plugin_data *p;
15945 p = calloc(1, sizeof(*p));
15948 p->tmp_buf = buffer_init();
15951 p->auth_user = buffer_init();
15953 p->ldap_filter = buffer_init();
15960 FREE_FUNC(mod_auth_free) {
15961 mod_auth_plugin_data *p = p_d;
15966 if (!p) return HANDLER_GO_ON;
15969 buffer_free(p->tmp_buf);
15970 buffer_free(p->auth_user);
15972 buffer_free(p->ldap_filter);
15976 if (p->config_storage) {
15978 for (i = 0; i < srv->config_context->used; i++) {
15979 mod_auth_plugin_config *s = p->config_storage[i];
15985 array_free(s->auth_require);
15986 buffer_free(s->auth_plain_groupfile);
15987 buffer_free(s->auth_plain_userfile);
15988 buffer_free(s->auth_htdigest_userfile);
15989 buffer_free(s->auth_htpasswd_userfile);
15990 buffer_free(s->auth_backend_conf);
15993 buffer_free(s->auth_ldap_hostname);
15994 buffer_free(s->auth_ldap_basedn);
15995 buffer_free(s->auth_ldap_binddn);
15996 buffer_free(s->auth_ldap_bindpw);
15997 buffer_free(s->auth_ldap_filter);
15998 buffer_free(s->auth_ldap_cafile);
16002 buffer_free(s->ldap_filter_pre);
16003 buffer_free(s->ldap_filter_post);
16006 if (s->ldap) ldap_unbind_s(s->ldap);
16012 free(p->config_storage);
16019 return HANDLER_GO_ON;
16022 -#define PATCH(x) \
16023 - p->conf.x = s->x;
16024 static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
16026 mod_auth_plugin_config *s = p->config_storage[0];
16028 - PATCH(auth_backend);
16029 - PATCH(auth_plain_groupfile);
16030 - PATCH(auth_plain_userfile);
16031 - PATCH(auth_htdigest_userfile);
16032 - PATCH(auth_htpasswd_userfile);
16033 - PATCH(auth_require);
16034 - PATCH(auth_debug);
16035 - PATCH(auth_ldap_hostname);
16036 - PATCH(auth_ldap_basedn);
16037 - PATCH(auth_ldap_binddn);
16038 - PATCH(auth_ldap_bindpw);
16039 - PATCH(auth_ldap_filter);
16040 - PATCH(auth_ldap_cafile);
16041 - PATCH(auth_ldap_starttls);
16042 + PATCH_OPTION(auth_backend);
16043 + PATCH_OPTION(auth_plain_groupfile);
16044 + PATCH_OPTION(auth_plain_userfile);
16045 + PATCH_OPTION(auth_htdigest_userfile);
16046 + PATCH_OPTION(auth_htpasswd_userfile);
16047 + PATCH_OPTION(auth_require);
16048 + PATCH_OPTION(auth_debug);
16049 + PATCH_OPTION(auth_ldap_hostname);
16050 + PATCH_OPTION(auth_ldap_basedn);
16051 + PATCH_OPTION(auth_ldap_binddn);
16052 + PATCH_OPTION(auth_ldap_bindpw);
16053 + PATCH_OPTION(auth_ldap_filter);
16054 + PATCH_OPTION(auth_ldap_cafile);
16055 + PATCH_OPTION(auth_ldap_starttls);
16058 - PATCH(ldap_filter_pre);
16059 - PATCH(ldap_filter_post);
16060 + PATCH_OPTION(ldap);
16061 + PATCH_OPTION(ldap_filter_pre);
16062 + PATCH_OPTION(ldap_filter_post);
16066 /* skip the first, the global context */
16067 for (i = 1; i < srv->config_context->used; i++) {
16068 data_config *dc = (data_config *)srv->config_context->data[i];
16069 s = p->config_storage[i];
16072 /* condition didn't match */
16073 if (!config_check_cond(srv, con, dc)) continue;
16077 for (j = 0; j < dc->value->used; j++) {
16078 data_unset *du = dc->value->data[j];
16081 if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
16082 - PATCH(auth_backend);
16083 + PATCH_OPTION(auth_backend);
16084 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
16085 - PATCH(auth_plain_groupfile);
16086 + PATCH_OPTION(auth_plain_groupfile);
16087 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
16088 - PATCH(auth_plain_userfile);
16089 + PATCH_OPTION(auth_plain_userfile);
16090 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
16091 - PATCH(auth_htdigest_userfile);
16092 + PATCH_OPTION(auth_htdigest_userfile);
16093 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
16094 - PATCH(auth_htpasswd_userfile);
16095 + PATCH_OPTION(auth_htpasswd_userfile);
16096 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
16097 - PATCH(auth_require);
16098 + PATCH_OPTION(auth_require);
16099 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
16100 - PATCH(auth_debug);
16101 + PATCH_OPTION(auth_debug);
16102 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
16103 - PATCH(auth_ldap_hostname);
16104 + PATCH_OPTION(auth_ldap_hostname);
16107 - PATCH(ldap_filter_pre);
16108 - PATCH(ldap_filter_post);
16109 + PATCH_OPTION(ldap);
16110 + PATCH_OPTION(ldap_filter_pre);
16111 + PATCH_OPTION(ldap_filter_post);
16113 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
16114 - PATCH(auth_ldap_basedn);
16115 + PATCH_OPTION(auth_ldap_basedn);
16116 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
16117 - PATCH(auth_ldap_filter);
16118 + PATCH_OPTION(auth_ldap_filter);
16119 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
16120 - PATCH(auth_ldap_cafile);
16121 + PATCH_OPTION(auth_ldap_cafile);
16122 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
16123 - PATCH(auth_ldap_starttls);
16124 + PATCH_OPTION(auth_ldap_starttls);
16134 static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
16136 @@ -175,22 +174,22 @@
16138 mod_auth_plugin_data *p = p_d;
16142 /* select the right config */
16143 mod_auth_patch_connection(srv, con, p);
16146 if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
16156 /* do we have to ask for auth ? */
16160 auth_satisfied = 0;
16163 /* search auth-directives for path */
16164 for (k = 0; k < p->conf.auth_require->used; k++) {
16165 buffer *req = p->conf.auth_require->data[k]->key;
16166 @@ -212,76 +211,76 @@
16172 /* nothing to do for us */
16173 if (auth_required == 0) return HANDLER_GO_ON;
16176 req = ((data_array *)(p->conf.auth_require->data[k]))->value;
16179 /* try to get Authorization-header */
16182 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
16183 http_authorization = ds->value->ptr;
16187 if (ds && ds->value && ds->value->used) {
16189 data_string *method;
16192 method = (data_string *)array_get_element(req, "method");
16195 /* parse auth-header */
16196 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
16197 int auth_type_len = auth_realm - http_authorization;
16200 if ((auth_type_len == 5) &&
16201 (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
16203 - if (0 == strcmp(method->value->ptr, "basic")) {
16205 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16206 auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
16208 } else if ((auth_type_len == 6) &&
16209 (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
16210 - if (0 == strcmp(method->value->ptr, "digest")) {
16211 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16212 if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
16213 con->http_status = 400;
16216 /* a field was missing */
16219 return HANDLER_FINISHED;
16223 - log_error_write(srv, __FILE__, __LINE__, "ss",
16224 + log_error_write(srv, __FILE__, __LINE__, "ss",
16225 "unknown authentification type:",
16226 http_authorization);
16232 if (!auth_satisfied) {
16233 data_string *method, *realm;
16234 method = (data_string *)array_get_element(req, "method");
16235 realm = (data_string *)array_get_element(req, "realm");
16238 con->http_status = 401;
16240 - if (0 == strcmp(method->value->ptr, "basic")) {
16242 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16243 buffer_copy_string(p->tmp_buf, "Basic realm=\"");
16244 buffer_append_string_buffer(p->tmp_buf, realm->value);
16245 buffer_append_string(p->tmp_buf, "\"");
16248 response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16249 - } else if (0 == strcmp(method->value->ptr, "digest")) {
16250 + } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16252 http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
16255 buffer_copy_string(p->tmp_buf, "Digest realm=\"");
16256 buffer_append_string_buffer(p->tmp_buf, realm->value);
16257 buffer_append_string(p->tmp_buf, "\", nonce=\"");
16258 buffer_append_string(p->tmp_buf, hh);
16259 buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
16262 response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16265 @@ -289,18 +288,18 @@
16266 return HANDLER_FINISHED;
16268 /* the REMOTE_USER header */
16271 buffer_copy_string_buffer(con->authed_user, p->auth_user);
16275 return HANDLER_GO_ON;
16278 SETDEFAULTS_FUNC(mod_auth_set_defaults) {
16279 mod_auth_plugin_data *p = p_d;
16282 - config_values_t cv[] = {
16284 + config_values_t cv[] = {
16285 { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16286 { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16287 { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16288 @@ -317,7 +316,7 @@
16289 { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
16290 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
16294 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16296 for (i = 0; i < srv->config_context->used; i++) {
16297 @@ -325,14 +324,14 @@
16303 s = calloc(1, sizeof(mod_auth_plugin_config));
16304 s->auth_plain_groupfile = buffer_init();
16305 s->auth_plain_userfile = buffer_init();
16306 s->auth_htdigest_userfile = buffer_init();
16307 s->auth_htpasswd_userfile = buffer_init();
16308 s->auth_backend_conf = buffer_init();
16311 s->auth_ldap_hostname = buffer_init();
16312 s->auth_ldap_basedn = buffer_init();
16313 s->auth_ldap_binddn = buffer_init();
16314 @@ -341,15 +340,15 @@
16315 s->auth_ldap_cafile = buffer_init();
16316 s->auth_ldap_starttls = 0;
16320 s->auth_require = array_init();
16324 s->ldap_filter_pre = buffer_init();
16325 s->ldap_filter_post = buffer_init();
16330 cv[0].destination = s->auth_backend_conf;
16331 cv[1].destination = s->auth_plain_groupfile;
16332 cv[2].destination = s->auth_plain_userfile;
16333 @@ -364,146 +363,148 @@
16334 cv[11].destination = s->auth_htdigest_userfile;
16335 cv[12].destination = s->auth_htpasswd_userfile;
16336 cv[13].destination = &(s->auth_debug);
16339 p->config_storage[i] = s;
16340 ca = ((data_config *)srv->config_context->data[i])->value;
16343 if (0 != config_insert_values_global(srv, ca, cv)) {
16344 return HANDLER_ERROR;
16347 - if (s->auth_backend_conf->used) {
16348 - if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
16350 + if (!buffer_is_empty(s->auth_backend_conf)) {
16351 + if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
16352 s->auth_backend = AUTH_BACKEND_HTPASSWD;
16353 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
16354 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
16355 s->auth_backend = AUTH_BACKEND_HTDIGEST;
16356 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
16357 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
16358 s->auth_backend = AUTH_BACKEND_PLAIN;
16359 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
16360 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
16361 s->auth_backend = AUTH_BACKEND_LDAP;
16363 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
16366 return HANDLER_ERROR;
16370 /* no auth.require for this section */
16371 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
16374 if (da->type != TYPE_ARRAY) continue;
16377 for (n = 0; n < da->value->used; n++) {
16379 data_array *da_file = (data_array *)da->value->data[n];
16380 - const char *method, *realm, *require;
16382 + buffer *method, *realm, *require;
16384 if (da->value->data[n]->type != TYPE_ARRAY) {
16385 - log_error_write(srv, __FILE__, __LINE__, "ss",
16386 - "auth.require should contain an array as in:",
16387 + log_error_write(srv, __FILE__, __LINE__, "ss",
16388 + "auth.require should contain an array as in:",
16389 "auth.require = ( \"...\" => ( ..., ...) )");
16391 return HANDLER_ERROR;
16395 method = realm = require = NULL;
16398 for (m = 0; m < da_file->value->used; m++) {
16399 - if (da_file->value->data[m]->type == TYPE_STRING) {
16400 - if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
16401 - method = ((data_string *)(da_file->value->data[m]))->value->ptr;
16402 - } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
16403 - realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
16404 - } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
16405 - require = ((data_string *)(da_file->value->data[m]))->value->ptr;
16407 - log_error_write(srv, __FILE__, __LINE__, "ssbs",
16408 - "the field is unknown in:",
16409 + data_string *ds_auth_req = (data_string *)da_file->value->data[m];
16411 + if (ds_auth_req->type != TYPE_STRING) {
16412 + log_error_write(srv, __FILE__, __LINE__, "ssbs",
16413 + "a string was expected for:",
16414 + "auth.require = ( \"...\" => ( ..., -> \"",
16415 + ds_auth_req->key,
16416 + "\" <- => \"...\" ) )");
16418 + return HANDLER_ERROR;
16421 + if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
16422 + method = ds_auth_req->value;
16423 + } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
16424 + realm = ds_auth_req->value;
16425 + } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
16426 + require = ds_auth_req->value;
16428 + log_error_write(srv, __FILE__, __LINE__, "ssbs",
16429 + "the field is unknown in:",
16430 "auth.require = ( \"...\" => ( ..., -> \"",
16431 da_file->value->data[m]->key,
16432 "\" <- => \"...\" ) )");
16434 - return HANDLER_ERROR;
16437 - log_error_write(srv, __FILE__, __LINE__, "ssbs",
16438 - "a string was expected for:",
16439 - "auth.require = ( \"...\" => ( ..., -> \"",
16440 - da_file->value->data[m]->key,
16441 - "\" <- => \"...\" ) )");
16443 return HANDLER_ERROR;
16449 if (method == NULL) {
16450 - log_error_write(srv, __FILE__, __LINE__, "ss",
16451 - "the require field is missing in:",
16452 + log_error_write(srv, __FILE__, __LINE__, "ss",
16453 + "the require field is missing in:",
16454 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
16455 return HANDLER_ERROR;
16457 - if (0 != strcmp(method, "basic") &&
16458 - 0 != strcmp(method, "digest")) {
16459 - log_error_write(srv, __FILE__, __LINE__, "ss",
16460 - "method has to be either \"basic\" or \"digest\" in",
16461 - "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16462 - return HANDLER_ERROR;
16465 + if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
16466 + !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
16467 + log_error_write(srv, __FILE__, __LINE__, "ss",
16468 + "method has to be either \"basic\" or \"digest\" in",
16469 + "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16470 + return HANDLER_ERROR;
16474 if (realm == NULL) {
16475 - log_error_write(srv, __FILE__, __LINE__, "ss",
16476 - "the require field is missing in:",
16477 + log_error_write(srv, __FILE__, __LINE__, "ss",
16478 + "the require field is missing in:",
16479 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
16480 return HANDLER_ERROR;
16484 if (require == NULL) {
16485 - log_error_write(srv, __FILE__, __LINE__, "ss",
16486 - "the require field is missing in:",
16487 + log_error_write(srv, __FILE__, __LINE__, "ss",
16488 + "the require field is missing in:",
16489 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
16490 return HANDLER_ERROR;
16494 if (method && realm && require) {
16499 a = data_array_init();
16500 buffer_copy_string_buffer(a->key, da_file->key);
16503 ds = data_string_init();
16506 buffer_copy_string(ds->key, "method");
16507 - buffer_copy_string(ds->value, method);
16509 + buffer_copy_string_buffer(ds->value, method);
16511 array_insert_unique(a->value, (data_unset *)ds);
16514 ds = data_string_init();
16517 buffer_copy_string(ds->key, "realm");
16518 - buffer_copy_string(ds->value, realm);
16520 + buffer_copy_string_buffer(ds->value, realm);
16522 array_insert_unique(a->value, (data_unset *)ds);
16525 ds = data_string_init();
16528 buffer_copy_string(ds->key, "require");
16529 - buffer_copy_string(ds->value, require);
16531 + buffer_copy_string_buffer(ds->value, require);
16533 array_insert_unique(a->value, (data_unset *)ds);
16536 array_insert_unique(s->auth_require, (data_unset *)a);
16541 switch(s->auth_backend) {
16542 case AUTH_BACKEND_PLAIN:
16543 if (s->auth_plain_userfile->used) {
16546 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
16547 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16548 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16549 "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
16550 "failed:", strerror(errno));
16551 return HANDLER_ERROR;
16552 @@ -516,7 +517,7 @@
16555 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
16556 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16557 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16558 "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
16559 "failed:", strerror(errno));
16560 return HANDLER_ERROR;
16561 @@ -529,7 +530,7 @@
16564 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
16565 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16566 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16567 "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
16568 "failed:", strerror(errno));
16569 return HANDLER_ERROR;
16570 @@ -554,75 +555,75 @@
16571 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
16576 if (s->auth_ldap_basedn->used == 0) {
16577 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
16580 return HANDLER_ERROR;
16585 if (s->auth_ldap_filter->used) {
16592 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
16593 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
16596 return HANDLER_ERROR;
16600 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
16601 buffer_copy_string(s->ldap_filter_post, dollar+1);
16605 if (s->auth_ldap_hostname->used) {
16606 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
16607 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
16610 return HANDLER_ERROR;
16614 ret = LDAP_VERSION3;
16615 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
16616 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16619 return HANDLER_ERROR;
16622 if (s->auth_ldap_starttls) {
16623 - /* if no CA file is given, it is ok, as we will use encryption
16624 + /* if no CA file is given, it is ok, as we will use encryption
16625 * if the server requires a CAfile it will tell us */
16626 if (!buffer_is_empty(s->auth_ldap_cafile)) {
16627 - if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16628 + if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16629 s->auth_ldap_cafile->ptr))) {
16630 - log_error_write(srv, __FILE__, __LINE__, "ss",
16631 + log_error_write(srv, __FILE__, __LINE__, "ss",
16632 "Loading CA certificate failed:", ldap_err2string(ret));
16635 return HANDLER_ERROR;
16640 if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL, NULL))) {
16641 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
16644 return HANDLER_ERROR;
16652 if (s->auth_ldap_binddn->used) {
16653 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
16654 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16657 return HANDLER_ERROR;
16660 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
16661 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16664 return HANDLER_ERROR;
16667 @@ -641,8 +642,8 @@
16668 p->set_defaults = mod_auth_set_defaults;
16669 p->handle_uri_clean = mod_auth_uri_handler;
16670 p->cleanup = mod_auth_free;
16678 --- ../lighttpd-1.4.11/src/mod_cgi.c 2006-02-22 15:15:10.000000000 +0200
16679 +++ lighttpd-1.4.12/src/mod_cgi.c 2006-07-18 17:34:32.000000000 +0300
16681 #include <sys/types.h>
16683 -#include <winsock2.h>
16685 -#include <sys/socket.h>
16686 -#include <sys/wait.h>
16687 -#include <sys/mman.h>
16689 -#include <netinet/in.h>
16691 -#include <arpa/inet.h>
16694 -#include <unistd.h>
16696 #include <stdlib.h>
16697 #include <string.h>
16698 -#include <fdevent.h>
16699 #include <signal.h>
16701 #include <assert.h>
16703 #include "connections.h"
16704 #include "joblist.h"
16705 #include "http_chunk.h"
16706 +#include "fdevent.h"
16708 #include "plugin.h"
16709 +#include "http_resp.h"
16711 +#include "sys-files.h"
16712 +#include "sys-mmap.h"
16713 +#include "sys-socket.h"
16714 +#include "sys-strings.h"
16715 +#include "sys-process.h"
16717 #ifdef HAVE_SYS_FILIO_H
16718 # include <sys/filio.h>
16719 @@ -40,11 +35,12 @@
16733 @@ -58,57 +54,68 @@
16736 buffer_pid_t cgi_pid;
16740 - buffer *parse_response;
16745 plugin_config **config_storage;
16747 - plugin_config conf;
16749 + plugin_config conf;
16754 + CGI_STATE_CONNECTING,
16755 + CGI_STATE_READ_RESPONSE_HEADER,
16756 + CGI_STATE_READ_RESPONSE_CONTENT
16762 - int fde_ndx; /* index into the fd-event buffer */
16764 - connection *remote_conn; /* dumb pointer */
16765 - plugin_data *plugin_data; /* dumb pointer */
16767 - buffer *response;
16768 - buffer *response_header;
16771 -static handler_ctx * cgi_handler_ctx_init() {
16772 - handler_ctx *hctx = calloc(1, sizeof(*hctx));
16777 - hctx->response = buffer_init();
16778 - hctx->response_header = buffer_init();
16785 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
16786 - buffer_free(hctx->response);
16787 - buffer_free(hctx->response_header);
16790 + cgi_state_t state;
16792 + connection *remote_con; /* dumb pointer */
16795 +static cgi_session * cgi_session_init() {
16796 + cgi_session *sess = calloc(1, sizeof(*sess));
16799 + sess->sock = iosocket_init();
16800 + sess->wb = chunkqueue_init();
16801 + sess->rb = chunkqueue_init();
16806 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
16807 +static void cgi_session_free(cgi_session *sess) {
16808 + if (!sess) return;
16810 + iosocket_free(sess->sock);
16812 + chunkqueue_free(sess->wb);
16813 + chunkqueue_free(sess->rb);
16818 INIT_FUNC(mod_cgi_init) {
16822 p = calloc(1, sizeof(*p));
16827 p->tmp_buf = buffer_init();
16828 - p->parse_response = buffer_init();
16830 + p->resp = http_response_init();
16835 @@ -116,62 +123,62 @@
16836 FREE_FUNC(mod_cgi_free) {
16837 plugin_data *p = p_d;
16838 buffer_pid_t *r = &(p->cgi_pid);
16844 if (p->config_storage) {
16846 for (i = 0; i < srv->config_context->used; i++) {
16847 plugin_config *s = p->config_storage[i];
16850 array_free(s->cgi);
16855 free(p->config_storage);
16860 if (r->ptr) free(r->ptr);
16863 buffer_free(p->tmp_buf);
16864 - buffer_free(p->parse_response);
16866 + http_response_free(p->resp);
16871 return HANDLER_GO_ON;
16874 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
16875 plugin_data *p = p_d;
16878 - config_values_t cv[] = {
16880 + config_values_t cv[] = {
16881 { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16882 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
16885 if (!p) return HANDLER_ERROR;
16888 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16891 for (i = 0; i < srv->config_context->used; i++) {
16895 s = calloc(1, sizeof(plugin_config));
16899 s->cgi = array_init();
16902 cv[0].destination = s->cgi;
16905 p->config_storage[i] = s;
16908 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
16909 return HANDLER_ERROR;
16914 return HANDLER_GO_ON;
16917 @@ -180,13 +187,13 @@
16920 buffer_pid_t *r = &(p->cgi_pid);
16925 for (i = 0; i < r->used; i++) {
16926 if (r->ptr[i] > m) m = r->ptr[i];
16930 if (r->size == 0) {
16932 r->ptr = malloc(sizeof(*r->ptr) * r->size);
16933 @@ -194,321 +201,179 @@
16935 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
16939 r->ptr[r->used++] = pid;
16945 static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
16947 buffer_pid_t *r = &(p->cgi_pid);
16952 for (i = 0; i < r->used; i++) {
16953 if (r->ptr[i] == pid) break;
16957 if (i != r->used) {
16961 if (i != r->used - 1) {
16962 r->ptr[i] = r->ptr[r->used - 1];
16971 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
16978 - buffer_copy_string_buffer(p->parse_response, in);
16980 - for (s = p->parse_response->ptr;
16981 - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
16982 - s = ns + (eol == EOL_RN ? 2 : 1), line++) {
16983 - const char *key, *value;
16990 - 0 == strncmp(s, "HTTP/1.", 7)) {
16991 - /* non-parsed header ... we parse them anyway */
16993 - if ((s[7] == '1' ||
16997 - /* after the space should be a status code for us */
16999 - status = strtol(s+9, NULL, 10);
17001 - if (con->http_status >= 100 &&
17002 - con->http_status < 1000) {
17003 - /* we expected 3 digits and didn't got them */
17004 - con->parsed_response |= HTTP_STATUS;
17005 - con->http_status = status;
17011 - if (NULL == (value = strchr(s, ':'))) {
17012 - /* we expect: "<key>: <value>\r\n" */
17016 - key_len = value - key;
17020 - while (*value == ' ' || *value == '\t') value++;
17022 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17023 - ds = data_response_init();
17025 - buffer_copy_string_len(ds->key, key, key_len);
17026 - buffer_copy_string(ds->value, value);
17028 - array_insert_unique(con->response.headers, (data_unset *)ds);
17030 - switch(key_len) {
17032 - if (0 == strncasecmp(key, "Date", key_len)) {
17033 - con->parsed_response |= HTTP_DATE;
17037 - if (0 == strncasecmp(key, "Status", key_len)) {
17038 - con->http_status = strtol(value, NULL, 10);
17039 - con->parsed_response |= HTTP_STATUS;
17043 - if (0 == strncasecmp(key, "Location", key_len)) {
17044 - con->parsed_response |= HTTP_LOCATION;
17048 - if (0 == strncasecmp(key, "Connection", key_len)) {
17049 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
17050 - con->parsed_response |= HTTP_CONNECTION;
17054 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
17055 - con->response.content_length = strtol(value, NULL, 10);
17056 - con->parsed_response |= HTTP_CONTENT_LENGTH;
17065 - /* CGI/1.1 rev 03 - 7.2.1.2 */
17066 - if ((con->parsed_response & HTTP_LOCATION) &&
17067 - !(con->parsed_response & HTTP_STATUS)) {
17068 - con->http_status = 302;
17069 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
17070 + cgi_session *sess = con->plugin_ctx[p->id];
17073 + switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
17074 + case NETWORK_STATUS_SUCCESS:
17075 + /* we got content */
17077 + case NETWORK_STATUS_WAIT_FOR_EVENT:
17079 + case NETWORK_STATUS_CONNECTION_CLOSE:
17080 + /* this is a bit too early */
17081 + ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
17085 + ERROR("%s", "oops, read-pipe-read failed and I don't know why");
17092 + /* looks like we got some content
17094 + * split off the header from the incoming stream
17097 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
17098 - plugin_data *p = hctx->plugin_data;
17099 - connection *con = hctx->remote_conn;
17104 - buffer_prepare_copy(hctx->response, 1024);
17105 - if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
17106 - if (errno == EAGAIN || errno == EINTR) {
17107 - /* would block, wait for signal */
17108 - return FDEVENT_HANDLED_NOT_FINISHED;
17111 - log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
17112 - return FDEVENT_HANDLED_ERROR;
17116 - /* read finished */
17118 - con->file_finished = 1;
17120 - /* send final chunk */
17121 - http_chunk_append_mem(srv, con, NULL, 0);
17122 - joblist_append(srv, con);
17124 - return FDEVENT_HANDLED_FINISHED;
17127 - hctx->response->ptr[n] = '\0';
17128 - hctx->response->used = n+1;
17130 - /* split header from body */
17132 - if (con->file_started == 0) {
17134 - int in_header = 0;
17135 - int header_end = 0;
17136 - int cp, eol = EOL_UNSET;
17139 - buffer_append_string_buffer(hctx->response_header, hctx->response);
17141 - /* nph (non-parsed headers) */
17142 - if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
17144 - /* search for the \r\n\r\n or \n\n in the string */
17145 - for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
17146 - if (*c == ':') in_header = 1;
17147 - else if (*c == '\n') {
17148 - if (in_header == 0) {
17149 - /* got a response without a response header */
17156 - if (eol == EOL_UNSET) eol = EOL_N;
17158 - if (*(c+1) == '\n') {
17163 - } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
17164 - if (in_header == 0) {
17165 - /* got a response without a response header */
17172 - if (eol == EOL_UNSET) eol = EOL_RN;
17175 - *(c+2) == '\r' &&
17176 - *(c+3) == '\n') {
17181 - /* skip the \n */
17185 + if (con->file_started == 0) {
17187 + int have_content_length = 0;
17189 + http_response_reset(p->resp);
17191 + /* the response header is not fully received yet,
17193 + * extract the http-response header from the rb-cq
17195 + switch (http_response_parse_cq(sess->rb, p->resp)) {
17196 + case PARSE_ERROR:
17197 + /* parsing failed */
17199 + TRACE("%s", "response parser failed");
17201 + con->http_status = 502; /* Bad Gateway */
17203 + case PARSE_NEED_MORE:
17205 + case PARSE_SUCCESS:
17206 + con->http_status = p->resp->status;
17208 + chunkqueue_remove_finished_chunks(sess->rb);
17210 + /* copy the http-headers */
17211 + for (i = 0; i < p->resp->headers->used; i++) {
17212 + const char *ign[] = { "Status", "Connection", NULL };
17216 + data_string *header = (data_string *)p->resp->headers->data[i];
17218 + /* some headers are ignored by default */
17219 + for (j = 0; ign[j]; j++) {
17220 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
17224 - if (header_end) {
17226 - /* no header, but a body */
17228 - if (con->request.http_version == HTTP_VERSION_1_1) {
17229 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17232 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17233 - joblist_append(srv, con);
17235 - size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
17236 - size_t blen = hctx->response_header->used - hlen - 1;
17238 - /* a small hack: terminate after at the second \r */
17239 - hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
17240 - hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
17242 - /* parse the response header */
17243 - cgi_response_parse(srv, con, p, hctx->response_header, eol);
17245 - /* enable chunked-transfer-encoding */
17246 - if (con->request.http_version == HTTP_VERSION_1_1 &&
17247 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
17248 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17251 - if ((hctx->response->used != hlen) && blen > 0) {
17252 - http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
17253 - joblist_append(srv, con);
17255 + if (ign[j]) continue;
17257 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
17258 + /* CGI/1.1 rev 03 - 7.2.1.2 */
17259 + if (con->http_status == 0) con->http_status = 302;
17260 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
17261 + have_content_length = 1;
17264 - con->file_started = 1;
17265 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17266 + ds = data_response_init();
17268 + buffer_copy_string_buffer(ds->key, header->key);
17269 + buffer_copy_string_buffer(ds->value, header->value);
17271 + array_insert_unique(con->response.headers, (data_unset *)ds);
17274 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
17275 - joblist_append(srv, con);
17277 + con->file_started = 1;
17278 + sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
17280 + if (con->request.http_version == HTTP_VERSION_1_1 &&
17281 + !have_content_length) {
17282 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17289 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
17293 - return FDEVENT_HANDLED_NOT_FINISHED;
17295 + /* FIXME: pass the response-header to the other plugins to
17296 + * setup the filter-queue
17298 + * - use next-queue instead of con->write_queue
17301 + /* copy the content to the next cq */
17302 + for (c = sess->rb->first; c; c = c->next) {
17303 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17305 + c->offset = c->mem->used - 1;
17308 + chunkqueue_remove_finished_chunks(sess->rb);
17309 + joblist_append(srv, con);
17314 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
17315 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
17316 + cgi_session *sess = con->plugin_ctx[p->id];
17322 - if (NULL == hctx) return HANDLER_GO_ON;
17324 - p = hctx->plugin_data;
17325 - con = hctx->remote_conn;
17328 + if (NULL == sess) return HANDLER_GO_ON;
17329 if (con->mode != p->id) return HANDLER_GO_ON;
17335 /* the connection to the browser went away, but we still have a connection
17336 - * to the CGI script
17337 + * to the CGI script
17339 * close cgi-connection
17342 - if (hctx->fd != -1) {
17344 + if (sess->sock->fd != -1) {
17345 /* close connection to the cgi-script */
17346 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
17347 - fdevent_unregister(srv->ev, hctx->fd);
17349 - if (close(hctx->fd)) {
17350 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
17354 - hctx->fde_ndx = -1;
17355 + fdevent_event_del(srv->ev, sess->sock);
17356 + fdevent_unregister(srv->ev, sess->sock);
17364 con->plugin_ctx[p->id] = NULL;
17367 /* is this a good idea ? */
17368 - cgi_handler_ctx_free(hctx);
17370 + cgi_session_free(sess);
17373 /* if waitpid hasn't been called by response.c yet, do it here */
17375 /* check if the CGI-script is already gone */
17377 switch(waitpid(pid, &status, WNOHANG)) {
17379 /* not finished yet */
17380 @@ -519,35 +384,35 @@
17383 if (errno == EINTR) break;
17386 - * errno == ECHILD happens if _subrequest catches the process-status before
17389 + * errno == ECHILD happens if _subrequest catches the process-status before
17390 * we have read the response of the cgi process
17394 * -> WAIT_FOR_EVENT
17396 * -> we get here with waitpid == ECHILD
17400 if (errno == ECHILD) return HANDLER_GO_ON;
17403 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
17404 return HANDLER_ERROR;
17406 /* Send an error if we haven't sent any data yet */
17407 if (0 == con->file_started) {
17408 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17409 - con->http_status = 500;
17410 + if (con->http_status == 0) con->http_status = 500;
17411 con->mode = DIRECT;
17415 if (WIFEXITED(status)) {
17417 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
17422 return HANDLER_GO_ON;
17424 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
17425 @@ -555,122 +420,126 @@
17426 return HANDLER_GO_ON;
17433 kill(pid, SIGTERM);
17436 /* cgi-script is still alive, queue the PID for removal */
17437 cgi_pid_add(srv, p, pid);
17441 return HANDLER_GO_ON;
17444 static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
17445 plugin_data *p = p_d;
17447 - return cgi_connection_close(srv, con->plugin_ctx[p->id]);
17449 + return cgi_connection_close(srv, con, p);
17453 static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
17454 server *srv = (server *)s;
17455 - handler_ctx *hctx = ctx;
17456 - connection *con = hctx->remote_conn;
17458 - joblist_append(srv, con);
17460 - if (hctx->fd == -1) {
17461 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
17463 - return HANDLER_ERROR;
17466 + cgi_session *sess = ctx;
17467 + connection *con = sess->remote_con;
17470 if (revents & FDEVENT_IN) {
17471 - switch (cgi_demux_response(srv, hctx)) {
17472 - case FDEVENT_HANDLED_NOT_FINISHED:
17473 + switch (sess->state) {
17474 + case CGI_STATE_READ_RESPONSE_HEADER:
17475 + /* parse the header and set file-started, the demuxer will care about it */
17476 + joblist_append(srv, con);
17479 - case FDEVENT_HANDLED_FINISHED:
17480 - /* we are done */
17482 + case CGI_STATE_READ_RESPONSE_CONTENT:
17483 + /* just forward the content to the out-going queue */
17485 + chunkqueue_remove_finished_chunks(sess->rb);
17487 + switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
17488 + case NETWORK_STATUS_CONNECTION_CLOSE:
17489 + fdevent_event_del(srv->ev, sess->sock);
17491 + /* the connection is gone
17492 + * make the connect */
17493 + sess->remote_con->file_finished = 1;
17495 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
17496 + fdevent_event_del(srv->ev, sess->sock);
17498 - cgi_connection_close(srv, hctx);
17500 - /* if we get a IN|HUP and have read everything don't exec the close twice */
17501 - return HANDLER_FINISHED;
17502 - case FDEVENT_HANDLED_ERROR:
17503 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17504 - con->http_status = 500;
17505 - con->mode = DIRECT;
17507 - log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
17508 + case NETWORK_STATUS_SUCCESS:
17509 + /* read even more, do we have all the content */
17511 + /* how much do we want to read ? */
17513 + /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
17515 + chunkqueue_remove_finished_chunks(sess->rb);
17517 + /* copy the content to the next cq */
17518 + for (c = sess->rb->first; c; c = c->next) {
17519 + if (c->mem->used == 0) continue;
17521 + http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17523 + c->offset = c->mem->used - 1;
17526 + chunkqueue_remove_finished_chunks(sess->rb);
17528 + if (sess->remote_con->file_finished) {
17529 + /* send final HTTP-Chunk packet */
17530 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17535 + ERROR("%s", "oops, we failed to read");
17539 + joblist_append(srv, sess->remote_con);
17542 + TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
17548 if (revents & FDEVENT_OUT) {
17549 /* nothing to do */
17553 /* perhaps this issue is already handled */
17554 if (revents & FDEVENT_HUP) {
17555 - /* check if we still have a unfinished header package which is a body in reality */
17556 - if (con->file_started == 0 &&
17557 - hctx->response_header->used) {
17558 - con->file_started = 1;
17559 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17560 - joblist_append(srv, con);
17563 - if (con->file_finished == 0) {
17564 - http_chunk_append_mem(srv, con, NULL, 0);
17565 - joblist_append(srv, con);
17568 con->file_finished = 1;
17570 - if (chunkqueue_is_empty(con->write_queue)) {
17571 - /* there is nothing left to write */
17572 - connection_set_state(srv, con, CON_STATE_RESPONSE_END);
17574 - /* used the write-handler to finish the request on demand */
17579 - log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
17582 - /* rtsigs didn't liked the close */
17583 - cgi_connection_close(srv, hctx);
17585 + fdevent_event_del(srv->ev, sess->sock);
17587 + /* someone has to close this socket now :) */
17588 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17589 + joblist_append(srv, sess->remote_con);
17590 } else if (revents & FDEVENT_ERR) {
17591 con->file_finished = 1;
17594 /* kill all connections to the cgi process */
17595 - cgi_connection_close(srv, hctx);
17597 - log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
17599 - return HANDLER_ERROR;
17600 + fdevent_event_del(srv->ev, sess->sock);
17604 return HANDLER_FINISHED;
17608 static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
17612 if (!key || !val) return -1;
17615 dst = malloc(key_len + val_len + 3);
17616 memcpy(dst, key, key_len);
17617 dst[key_len] = '=';
17618 /* add the \0 from the value */
17619 memcpy(dst + key_len + 1, val, val_len + 1);
17622 if (env->size == 0) {
17624 env->ptr = malloc(env->size * sizeof(*env->ptr));
17625 @@ -678,45 +547,45 @@
17627 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
17631 env->ptr[env->used++] = dst;
17637 static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
17642 char b2[INET6_ADDRSTRLEN + 1];
17647 int from_cgi_fds[2];
17655 if (cgi_handler->used > 1) {
17656 /* stat the exec file */
17657 if (-1 == (stat(cgi_handler->ptr, &st))) {
17658 - log_error_write(srv, __FILE__, __LINE__, "sbss",
17659 + log_error_write(srv, __FILE__, __LINE__, "sbss",
17660 "stat for cgi-handler", cgi_handler,
17661 "failed:", strerror(errno));
17667 if (pipe(to_cgi_fds)) {
17668 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17673 if (pipe(from_cgi_fds)) {
17674 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17680 switch (pid = fork()) {
17682 @@ -730,44 +599,40 @@
17685 server_socket *srv_sock = con->srv_socket;
17688 /* move stdout to from_cgi_fd[1] */
17689 close(STDOUT_FILENO);
17690 dup2(from_cgi_fds[1], STDOUT_FILENO);
17691 close(from_cgi_fds[1]);
17693 close(from_cgi_fds[0]);
17696 /* move the stdin to to_cgi_fd[0] */
17697 close(STDIN_FILENO);
17698 dup2(to_cgi_fds[0], STDIN_FILENO);
17699 close(to_cgi_fds[0]);
17701 close(to_cgi_fds[1]);
17704 - * this is not nice, but it works
17706 - * we feed the stderr of the CGI to our errorlog, if possible
17709 + * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
17711 - if (srv->errorlog_mode == ERRORLOG_FILE) {
17712 - close(STDERR_FILENO);
17713 - dup2(srv->errorlog_fd, STDERR_FILENO);
17717 + close(STDERR_FILENO);
17719 /* create environment */
17725 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
17727 if (!buffer_is_empty(con->server_name)) {
17728 cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
17731 - s = inet_ntop(srv_sock->addr.plain.sa_family,
17732 - srv_sock->addr.plain.sa_family == AF_INET6 ?
17733 + s = inet_ntop(srv_sock->addr.plain.sa_family,
17734 + srv_sock->addr.plain.sa_family == AF_INET6 ?
17735 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17736 (const void *) &(srv_sock->addr.ipv4.sin_addr),
17738 @@ -779,10 +644,10 @@
17739 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
17741 s = get_http_version_name(con->request.http_version);
17744 cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
17750 ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
17752 @@ -790,10 +655,10 @@
17755 cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
17759 - s = inet_ntop(srv_sock->addr.plain.sa_family,
17760 - srv_sock->addr.plain.sa_family == AF_INET6 ?
17761 + s = inet_ntop(srv_sock->addr.plain.sa_family,
17762 + srv_sock->addr.plain.sa_family == AF_INET6 ?
17763 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17764 (const void *) &(srv_sock->addr.ipv4.sin_addr),
17766 @@ -811,15 +676,18 @@
17767 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
17768 if (!buffer_is_empty(con->uri.query)) {
17769 cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
17771 + /* set a empty QUERY_STRING */
17772 + cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
17774 if (!buffer_is_empty(con->request.orig_uri)) {
17775 cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
17782 - s = inet_ntop(con->dst_addr.plain.sa_family,
17783 - con->dst_addr.plain.sa_family == AF_INET6 ?
17784 + s = inet_ntop(con->dst_addr.plain.sa_family,
17785 + con->dst_addr.plain.sa_family == AF_INET6 ?
17786 (const void *) &(con->dst_addr.ipv6.sin6_addr) :
17787 (const void *) &(con->dst_addr.ipv4.sin_addr),
17789 @@ -828,7 +696,7 @@
17791 cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
17796 ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
17798 @@ -836,19 +704,19 @@
17801 cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
17804 if (!buffer_is_empty(con->authed_user)) {
17805 cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
17806 CONST_BUF_LEN(con->authed_user));
17810 /* request.content_length < SSIZE_MAX, see request.c */
17811 ltostr(buf, con->request.content_length);
17812 cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
17813 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
17814 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
17815 cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
17819 if (NULL != (s = getenv("LD_PRELOAD"))) {
17820 cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
17821 @@ -863,24 +731,24 @@
17822 cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
17827 for (n = 0; n < con->request.headers->used; n++) {
17831 ds = (data_string *)con->request.headers->data[n];
17834 if (ds->value->used && ds->key->used) {
17838 buffer_reset(p->tmp_buf);
17841 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
17842 buffer_copy_string(p->tmp_buf, "HTTP_");
17843 p->tmp_buf->used--; /* strip \0 after HTTP_ */
17847 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17850 for (j = 0; j < ds->key->used - 1; j++) {
17852 if (light_isalpha(ds->key->ptr[j])) {
17853 @@ -893,46 +761,46 @@
17854 p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
17856 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17859 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17864 for (n = 0; n < con->environment->used; n++) {
17868 ds = (data_string *)con->environment->data[n];
17871 if (ds->value->used && ds->key->used) {
17875 buffer_reset(p->tmp_buf);
17878 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17881 for (j = 0; j < ds->key->used - 1; j++) {
17882 - p->tmp_buf->ptr[p->tmp_buf->used++] =
17883 - isalpha((unsigned char)ds->key->ptr[j]) ?
17884 + p->tmp_buf->ptr[p->tmp_buf->used++] =
17885 + isalpha((unsigned char)ds->key->ptr[j]) ?
17886 toupper((unsigned char)ds->key->ptr[j]) : '_';
17888 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17891 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17896 if (env.size == env.used) {
17898 env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
17902 env.ptr[env.used] = NULL;
17907 args = malloc(sizeof(*args) * argc);
17911 if (cgi_handler->used > 1) {
17912 args[i++] = cgi_handler->ptr;
17914 @@ -942,7 +810,7 @@
17915 /* search for the last / */
17916 if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
17920 /* change to the physical directory */
17921 if (-1 == chdir(con->physical.path->ptr)) {
17922 log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
17923 @@ -952,14 +820,14 @@
17925 /* we don't need the client socket */
17926 for (i = 3; i < 256; i++) {
17927 - if (i != srv->errorlog_fd) close(i);
17933 execve(args[0], args, env.ptr);
17936 log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]);
17942 @@ -969,16 +837,16 @@
17943 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
17946 - handler_ctx *hctx;
17947 + cgi_session *sess;
17950 close(from_cgi_fds[1]);
17951 close(to_cgi_fds[0]);
17954 if (con->request.content_length) {
17955 chunkqueue *cq = con->request_content_queue;
17959 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
17961 /* there is content to send */
17962 @@ -993,16 +861,16 @@
17963 if (-1 == c->file.fd && /* open the file if not already open */
17964 -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
17965 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
17968 close(from_cgi_fds[0]);
17969 close(to_cgi_fds[1]);
17973 c->file.mmap.length = c->file.length;
17976 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
17977 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
17978 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
17979 strerror(errno), c->file.name, c->file.fd);
17981 close(from_cgi_fds[0]);
17982 @@ -1012,7 +880,7 @@
17988 /* chunk_reset() or chunk_free() will cleanup for us */
17991 @@ -1020,7 +888,7 @@
17994 con->http_status = 507;
17999 con->http_status = 403;
18000 @@ -1033,7 +901,7 @@
18003 con->http_status = 507;
18008 con->http_status = 403;
18009 @@ -1056,103 +924,95 @@
18012 close(to_cgi_fds[1]);
18015 /* register PID and wait for them asyncronously */
18017 buffer_reset(con->physical.path);
18019 - hctx = cgi_handler_ctx_init();
18021 - hctx->remote_conn = con;
18022 - hctx->plugin_data = p;
18024 - hctx->fd = from_cgi_fds[0];
18025 - hctx->fde_ndx = -1;
18027 - con->plugin_ctx[p->id] = hctx;
18029 - fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
18030 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
18032 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
18034 + sess = cgi_session_init();
18036 + sess->remote_con = con;
18039 + assert(sess->sock);
18041 + sess->sock->fd = from_cgi_fds[0];
18042 + sess->sock->type = IOSOCKET_TYPE_PIPE;
18044 + if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
18045 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
18047 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18048 - fdevent_unregister(srv->ev, hctx->fd);
18050 - log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
18054 - cgi_handler_ctx_free(hctx);
18056 - con->plugin_ctx[p->id] = NULL;
18059 + cgi_session_free(sess);
18065 + con->plugin_ctx[p->id] = sess;
18067 + fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
18068 + fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
18070 + sess->state = CGI_STATE_READ_RESPONSE_HEADER;
18083 -#define PATCH(x) \
18084 - p->conf.x = s->x;
18085 static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
18087 plugin_config *s = p->config_storage[0];
18092 + PATCH_OPTION(cgi);
18094 /* skip the first, the global context */
18095 for (i = 1; i < srv->config_context->used; i++) {
18096 data_config *dc = (data_config *)srv->config_context->data[i];
18097 s = p->config_storage[i];
18100 /* condition didn't match */
18101 if (!config_check_cond(srv, con, dc)) continue;
18105 for (j = 0; j < dc->value->used; j++) {
18106 data_unset *du = dc->value->data[j];
18109 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
18111 + PATCH_OPTION(cgi);
18121 URIHANDLER_FUNC(cgi_is_handled) {
18123 plugin_data *p = p_d;
18124 buffer *fn = con->physical.path;
18127 if (fn->used == 0) return HANDLER_GO_ON;
18130 mod_cgi_patch_connection(srv, con, p);
18133 s_len = fn->used - 1;
18136 for (k = 0; k < p->conf.cgi->used; k++) {
18137 data_string *ds = (data_string *)p->conf.cgi->data[k];
18138 size_t ct_len = ds->key->used - 1;
18141 if (ds->key->used == 0) continue;
18142 if (s_len < ct_len) continue;
18145 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
18146 if (cgi_create_env(srv, con, p, ds->value)) {
18147 con->http_status = 500;
18150 buffer_reset(con->physical.path);
18151 return HANDLER_FINISHED;
18153 @@ -1160,7 +1020,7 @@
18159 return HANDLER_GO_ON;
18162 @@ -1168,11 +1028,11 @@
18163 plugin_data *p = p_d;
18165 /* the trigger handle only cares about lonely PID which we have to wait for */
18169 for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
18173 switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
18175 /* not finished yet */
18176 @@ -1182,7 +1042,7 @@
18179 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18182 return HANDLER_ERROR;
18185 @@ -1193,96 +1053,105 @@
18187 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18191 cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
18192 - /* del modified the buffer structure
18193 + /* del modified the buffer structure
18194 * and copies the last entry to the current one
18195 * -> recheck the current index
18202 return HANDLER_GO_ON;
18205 SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
18207 plugin_data *p = p_d;
18208 - handler_ctx *hctx = con->plugin_ctx[p->id];
18210 + cgi_session *sess = con->plugin_ctx[p->id];
18212 if (con->mode != p->id) return HANDLER_GO_ON;
18213 - if (NULL == hctx) return HANDLER_GO_ON;
18215 + if (NULL == sess) return HANDLER_GO_ON;
18217 + switch (cgi_demux_response(srv, con, p)) {
18221 + cgi_connection_close(srv, con, p);
18223 + /* if we get a IN|HUP and have read everything don't exec the close twice */
18224 + return HANDLER_FINISHED;
18226 + cgi_connection_close(srv, con, p);
18228 + if (0 == con->http_status) con->http_status = 500;
18229 + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
18230 + con->mode = DIRECT;
18232 + return HANDLER_FINISHED;
18236 - log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
18238 - if (hctx->pid == 0) return HANDLER_FINISHED;
18240 - switch(waitpid(hctx->pid, &status, WNOHANG)) {
18241 + log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", sess, sess->pid);
18243 + if (sess->pid == 0) return HANDLER_FINISHED;
18245 + switch(waitpid(sess->pid, &status, WNOHANG)) {
18247 /* we only have for events here if we don't have the header yet,
18248 * otherwise the event-handler will send us the incoming data */
18249 - if (con->file_started) return HANDLER_FINISHED;
18251 - return HANDLER_WAIT_FOR_EVENT;
18252 + if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18253 + if (con->file_finished) return HANDLER_FINISHED;
18255 + return HANDLER_GO_ON;
18257 if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
18260 if (errno == ECHILD && con->file_started == 0) {
18262 - * second round but still not response
18263 + * second round but still not response
18265 - return HANDLER_WAIT_FOR_EVENT;
18266 + return HANDLER_WAIT_FOR_EVENT;
18270 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18271 con->mode = DIRECT;
18272 con->http_status = 500;
18276 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18277 - fdevent_unregister(srv->ev, hctx->fd);
18279 - if (close(hctx->fd)) {
18280 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18283 - cgi_handler_ctx_free(hctx);
18288 + fdevent_event_del(srv->ev, sess->sock);
18289 + fdevent_unregister(srv->ev, sess->sock);
18291 + cgi_session_free(sess);
18294 con->plugin_ctx[p->id] = NULL;
18297 return HANDLER_FINISHED;
18299 - /* cgi process exited cleanly
18301 - * check if we already got the response
18304 - if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18306 + con->file_finished = 1;
18308 if (WIFEXITED(status)) {
18311 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18314 con->mode = DIRECT;
18315 con->http_status = 500;
18322 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18323 - fdevent_unregister(srv->ev, hctx->fd);
18325 - if (close(hctx->fd)) {
18326 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18329 - cgi_handler_ctx_free(hctx);
18334 + fdevent_event_del(srv->ev, sess->sock);
18335 + fdevent_unregister(srv->ev, sess->sock);
18337 + cgi_session_free(sess);
18340 con->plugin_ctx[p->id] = NULL;
18341 return HANDLER_FINISHED;
18343 @@ -1306,8 +1175,8 @@
18344 p->init = mod_cgi_init;
18345 p->cleanup = mod_cgi_free;
18346 p->set_defaults = mod_fastcgi_set_defaults;
18354 --- ../lighttpd-1.4.11/src/mod_cml.c 2006-01-30 13:51:48.000000000 +0200
18355 +++ lighttpd-1.4.12/src/mod_cml.c 2006-07-16 00:26:03.000000000 +0300
18357 #include <stdlib.h>
18358 #include <string.h>
18360 -#include <unistd.h>
18363 #include "buffer.h"
18364 @@ -20,50 +19,50 @@
18365 /* init the plugin data */
18366 INIT_FUNC(mod_cml_init) {
18370 p = calloc(1, sizeof(*p));
18373 p->basedir = buffer_init();
18374 p->baseurl = buffer_init();
18375 p->trigger_handler = buffer_init();
18381 /* detroy the plugin data */
18382 FREE_FUNC(mod_cml_free) {
18383 plugin_data *p = p_d;
18388 if (!p) return HANDLER_GO_ON;
18391 if (p->config_storage) {
18393 for (i = 0; i < srv->config_context->used; i++) {
18394 plugin_config *s = p->config_storage[i];
18397 buffer_free(s->ext);
18400 buffer_free(s->mc_namespace);
18401 buffer_free(s->power_magnet);
18402 array_free(s->mc_hosts);
18405 #if defined(HAVE_MEMCACHE_H)
18406 if (s->mc) mc_free(s->mc);
18412 free(p->config_storage);
18416 buffer_free(p->trigger_handler);
18417 buffer_free(p->basedir);
18418 buffer_free(p->baseurl);
18424 return HANDLER_GO_ON;
18427 @@ -72,22 +71,22 @@
18428 SETDEFAULTS_FUNC(mod_cml_set_defaults) {
18429 plugin_data *p = p_d;
18432 - config_values_t cv[] = {
18434 + config_values_t cv[] = {
18435 { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
18436 { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
18437 { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
18438 { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
18439 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18443 if (!p) return HANDLER_ERROR;
18446 p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
18449 for (i = 0; i < srv->config_context->used; i++) {
18453 s = malloc(sizeof(plugin_config));
18454 s->ext = buffer_init();
18455 s->mc_hosts = array_init();
18456 @@ -96,87 +95,84 @@
18457 #if defined(HAVE_MEMCACHE_H)
18462 cv[0].destination = s->ext;
18463 cv[1].destination = s->mc_hosts;
18464 cv[2].destination = s->mc_namespace;
18465 cv[3].destination = s->power_magnet;
18468 p->config_storage[i] = s;
18471 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18472 return HANDLER_ERROR;
18476 if (s->mc_hosts->used) {
18477 #if defined(HAVE_MEMCACHE_H)
18482 for (k = 0; k < s->mc_hosts->used; k++) {
18483 data_string *ds = (data_string *)s->mc_hosts->data[k];
18486 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
18487 - log_error_write(srv, __FILE__, __LINE__, "sb",
18488 - "connection to host failed:",
18489 + log_error_write(srv, __FILE__, __LINE__, "sb",
18490 + "connection to host failed:",
18494 return HANDLER_ERROR;
18498 - log_error_write(srv, __FILE__, __LINE__, "s",
18499 + log_error_write(srv, __FILE__, __LINE__, "s",
18500 "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
18501 return HANDLER_ERROR;
18507 return HANDLER_GO_ON;
18510 -#define PATCH(x) \
18511 - p->conf.x = s->x;
18512 static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
18514 plugin_config *s = p->config_storage[0];
18518 + PATCH_OPTION(ext);
18519 #if defined(HAVE_MEMCACHE_H)
18521 + PATCH_OPTION(mc);
18523 - PATCH(mc_namespace);
18524 - PATCH(power_magnet);
18526 + PATCH_OPTION(mc_namespace);
18527 + PATCH_OPTION(power_magnet);
18529 /* skip the first, the global context */
18530 for (i = 1; i < srv->config_context->used; i++) {
18531 data_config *dc = (data_config *)srv->config_context->data[i];
18532 s = p->config_storage[i];
18535 /* condition didn't match */
18536 if (!config_check_cond(srv, con, dc)) continue;
18540 for (j = 0; j < dc->value->used; j++) {
18541 data_unset *du = dc->value->data[j];
18544 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
18546 + PATCH_OPTION(ext);
18547 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
18548 #if defined(HAVE_MEMCACHE_H)
18550 + PATCH_OPTION(mc);
18552 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
18553 - PATCH(mc_namespace);
18554 + PATCH_OPTION(mc_namespace);
18555 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
18556 - PATCH(power_magnet);
18557 + PATCH_OPTION(power_magnet);
18567 int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
18569 @@ -187,57 +183,57 @@
18571 buffer_copy_string_buffer(b, con->uri.path);
18572 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18576 b->used = c - b->ptr + 2;
18582 buffer_copy_string_buffer(b, con->physical.path);
18583 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18587 b->used = c - b->ptr + 2;
18593 /* prepare variables
18595 * - get-param-based
18599 return cache_parse_lua(srv, con, p, cml_file);
18604 URIHANDLER_FUNC(mod_cml_power_magnet) {
18605 plugin_data *p = p_d;
18608 mod_cml_patch_connection(srv, con, p);
18611 buffer_reset(p->basedir);
18612 buffer_reset(p->baseurl);
18613 buffer_reset(p->trigger_handler);
18615 if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
18621 * cml.power-magnet = server.docroot + "/rewrite.cml"
18623 * is called on EACH request, take the original REQUEST_URI and modifies the
18624 - * request header as neccesary.
18625 + * request header as neccesary.
18628 * if file_exists("/maintainance.html") {
18629 * output_include = ( "/maintainance.html" )
18630 - * return CACHE_HIT
18631 + * return CACHE_HIT
18634 * as we only want to rewrite HTML like requests we should cover it in a conditional
18639 switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
18640 @@ -266,20 +262,20 @@
18642 URIHANDLER_FUNC(mod_cml_is_handled) {
18643 plugin_data *p = p_d;
18646 if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
18649 mod_cml_patch_connection(srv, con, p);
18652 buffer_reset(p->basedir);
18653 buffer_reset(p->baseurl);
18654 buffer_reset(p->trigger_handler);
18656 if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
18659 if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
18660 return HANDLER_GO_ON;
18664 switch(cache_call_lua(srv, con, p, con->physical.path)) {
18666 @@ -311,15 +307,15 @@
18667 int mod_cml_plugin_init(plugin *p) {
18668 p->version = LIGHTTPD_VERSION_ID;
18669 p->name = buffer_init_string("cache");
18672 p->init = mod_cml_init;
18673 p->cleanup = mod_cml_free;
18674 p->set_defaults = mod_cml_set_defaults;
18677 p->handle_subrequest_start = mod_cml_is_handled;
18678 p->handle_physical = mod_cml_power_magnet;
18686 --- ../lighttpd-1.4.11/src/mod_cml.h 2006-01-30 13:51:35.000000000 +0200
18687 +++ lighttpd-1.4.12/src/mod_cml.h 2006-07-16 00:26:03.000000000 +0300
18688 @@ -16,10 +16,10 @@
18695 buffer *mc_namespace;
18696 -#if defined(HAVE_MEMCACHE_H)
18697 +#if defined(HAVE_MEMCACHE_H)
18698 struct memcache *mc;
18700 buffer *power_magnet;
18701 @@ -27,15 +27,15 @@
18711 buffer *trigger_handler;
18714 plugin_config **config_storage;
18716 - plugin_config conf;
18718 + plugin_config conf;
18721 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
18722 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c 2005-11-17 16:15:08.000000000 +0200
18723 +++ lighttpd-1.4.12/src/mod_cml_funcs.c 2006-07-16 00:26:04.000000000 +0300
18725 #include <stdlib.h>
18726 #include <string.h>
18728 -#include <unistd.h>
18729 -#include <dirent.h>
18733 #include "buffer.h"
18736 #include "plugin.h"
18737 #include "response.h"
18738 +#include "sys-files.h"
18740 #include "mod_cml.h"
18741 #include "mod_cml_funcs.h"
18751 @@ -42,29 +42,29 @@
18754 int n = lua_gettop(L);
18759 b.size = sizeof(hex);
18763 lua_pushstring(L, "md5: expected one argument");
18768 if (!lua_isstring(L, 1)) {
18769 lua_pushstring(L, "md5: argument has to be a string");
18775 MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
18776 MD5_Final(HA1, &Md5Ctx);
18779 buffer_copy_string_hex(&b, (char *)HA1, 16);
18782 lua_pushstring(L, b.ptr);
18788 @@ -72,37 +72,37 @@
18789 int f_file_mtime(lua_State *L) {
18791 int n = lua_gettop(L);
18795 lua_pushstring(L, "file_mtime: expected one argument");
18800 if (!lua_isstring(L, 1)) {
18801 lua_pushstring(L, "file_mtime: argument has to be a string");
18806 if (-1 == stat(lua_tostring(L, 1), &st)) {
18812 lua_pushnumber(L, st.st_mtime);
18819 int f_dir_files_iter(lua_State *L) {
18824 d = lua_touserdata(L, lua_upvalueindex(1));
18827 if (NULL == (de = readdir(d))) {
18834 lua_pushstring(L, de->d_name);
18835 @@ -113,75 +113,75 @@
18836 int f_dir_files(lua_State *L) {
18838 int n = lua_gettop(L);
18842 lua_pushstring(L, "dir_files: expected one argument");
18847 if (!lua_isstring(L, 1)) {
18848 lua_pushstring(L, "dir_files: argument has to be a string");
18852 - /* check if there is a valid DIR handle on the stack */
18854 + /* check if there is a valid DIR handle on the stack */
18855 if (NULL == (d = opendir(lua_tostring(L, 1)))) {
18861 /* push d into registry */
18862 lua_pushlightuserdata(L, d);
18863 lua_pushcclosure(L, f_dir_files_iter, 1);
18870 int f_file_isreg(lua_State *L) {
18872 int n = lua_gettop(L);
18876 lua_pushstring(L, "file_isreg: expected one argument");
18881 if (!lua_isstring(L, 1)) {
18882 lua_pushstring(L, "file_isreg: argument has to be a string");
18887 if (-1 == stat(lua_tostring(L, 1), &st)) {
18893 lua_pushnumber(L, S_ISREG(st.st_mode));
18899 int f_file_isdir(lua_State *L) {
18901 int n = lua_gettop(L);
18905 lua_pushstring(L, "file_isreg: expected one argument");
18910 if (!lua_isstring(L, 1)) {
18911 lua_pushstring(L, "file_isreg: argument has to be a string");
18916 if (-1 == stat(lua_tostring(L, 1), &st)) {
18922 lua_pushnumber(L, S_ISDIR(st.st_mode));
18928 @@ -192,33 +192,33 @@
18930 int n = lua_gettop(L);
18931 struct memcache *mc;
18934 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18935 lua_pushstring(L, "where is my userdata ?");
18940 mc = lua_touserdata(L, lua_upvalueindex(1));
18944 lua_pushstring(L, "expected one argument");
18949 if (!lua_isstring(L, 1)) {
18950 lua_pushstring(L, "argument has to be a string");
18954 - if (NULL == (r = mc_aget(mc,
18956 + if (NULL == (r = mc_aget(mc,
18957 lua_tostring(L, 1), lua_strlen(L, 1)))) {
18960 lua_pushboolean(L, 0);
18968 lua_pushboolean(L, 1);
18971 @@ -226,74 +226,74 @@
18972 int f_memcache_get_string(lua_State *L) {
18974 int n = lua_gettop(L);
18977 struct memcache *mc;
18980 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18981 lua_pushstring(L, "where is my userdata ?");
18986 mc = lua_touserdata(L, lua_upvalueindex(1));
18992 lua_pushstring(L, "expected one argument");
18997 if (!lua_isstring(L, 1)) {
18998 lua_pushstring(L, "argument has to be a string");
19002 - if (NULL == (r = mc_aget(mc,
19004 + if (NULL == (r = mc_aget(mc,
19005 lua_tostring(L, 1), lua_strlen(L, 1)))) {
19011 lua_pushstring(L, r);
19020 int f_memcache_get_long(lua_State *L) {
19022 int n = lua_gettop(L);
19025 struct memcache *mc;
19028 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
19029 lua_pushstring(L, "where is my userdata ?");
19034 mc = lua_touserdata(L, lua_upvalueindex(1));
19040 lua_pushstring(L, "expected one argument");
19045 if (!lua_isstring(L, 1)) {
19046 lua_pushstring(L, "argument has to be a string");
19050 - if (NULL == (r = mc_aget(mc,
19052 + if (NULL == (r = mc_aget(mc,
19053 lua_tostring(L, 1), lua_strlen(L, 1)))) {
19059 lua_pushnumber(L, strtol(r, NULL, 10));
19068 --- ../lighttpd-1.4.11/src/mod_cml_lua.c 2006-01-30 13:56:40.000000000 +0200
19069 +++ lighttpd-1.4.12/src/mod_cml_lua.c 2006-07-16 00:26:04.000000000 +0300
19082 #include <lualib.h>
19083 +#include <lauxlib.h>
19087 @@ -39,11 +40,11 @@
19089 static const char * load_file(lua_State *L, void *data, size_t *size) {
19096 if (rm->done) return 0;
19099 *size = rm->st.size;
19101 return rm->st.start;
19102 @@ -51,47 +52,47 @@
19104 static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
19108 lua_pushstring(L, varname);
19111 curelem = lua_gettop(L);
19112 lua_gettable(L, LUA_GLOBALSINDEX);
19115 /* it should be a table */
19116 if (!lua_isstring(L, curelem)) {
19117 lua_settop(L, curelem - 1);
19124 buffer_copy_string(b, lua_tostring(L, curelem));
19130 assert(curelem - 1 == lua_gettop(L));
19136 static int lua_to_c_is_table(lua_State *L, const char *varname) {
19140 lua_pushstring(L, varname);
19143 curelem = lua_gettop(L);
19144 lua_gettable(L, LUA_GLOBALSINDEX);
19147 /* it should be a table */
19148 if (!lua_istable(L, curelem)) {
19149 lua_settop(L, curelem - 1);
19156 lua_settop(L, curelem - 1);
19159 assert(curelem - 1 == lua_gettop(L));
19166 lua_pushlstring(L, key, key_len);
19167 lua_pushlstring(L, val, val_len);
19168 lua_settable(L, tbl);
19174 @@ -108,21 +109,21 @@
19177 char *key = NULL, *val = NULL;
19183 /* we need the \0 */
19184 for (i = 0; i < qrystr->used; i++) {
19185 switch(qrystr->ptr[i]) {
19188 val = qrystr->ptr + i + 1;
19191 qrystr->ptr[i] = '\0';
19200 case '\0': /* fin symbol */
19201 @@ -131,19 +132,19 @@
19203 /* terminate the value */
19204 qrystr->ptr[i] = '\0';
19206 - c_to_lua_push(L, tbl,
19208 + c_to_lua_push(L, tbl,
19214 key = qrystr->ptr + i + 1;
19225 @@ -151,21 +152,21 @@
19231 if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
19232 data_string *ds = (data_string *)d;
19233 size_t key = 0, value = 0;
19234 size_t is_key = 1, is_sid = 0;
19239 if (!DATA_IS_STRING(d)) return -1;
19240 if (ds->value->used == 0) return -1;
19243 if (ds->value->ptr[0] == '\0' ||
19244 ds->value->ptr[0] == '=' ||
19245 ds->value->ptr[0] == ';') return -1;
19248 buffer_reset(p->session_id);
19249 for (i = 0; i < ds->value->used; i++) {
19250 switch(ds->value->ptr[i]) {
19251 @@ -176,16 +177,16 @@
19264 buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
19271 @@ -204,48 +205,43 @@
19281 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
19286 buffer *b = buffer_init();
19287 int header_tbl = 0;
19291 stream_open(&rm.st, fn);
19294 /* push the lua file to the interpreter and see what happends */
19298 - luaopen_table(L);
19299 - luaopen_string(L);
19303 + L = luaL_newstate();
19304 + luaL_openlibs(L);
19306 /* register functions */
19307 lua_register(L, "md5", f_crypto_md5);
19308 lua_register(L, "file_mtime", f_file_mtime);
19309 lua_register(L, "file_isreg", f_file_isreg);
19310 lua_register(L, "file_isdir", f_file_isreg);
19311 lua_register(L, "dir_files", f_dir_files);
19314 #ifdef HAVE_MEMCACHE_H
19315 lua_pushliteral(L, "memcache_get_long");
19316 lua_pushlightuserdata(L, p->conf.mc);
19317 lua_pushcclosure(L, f_memcache_get_long, 1);
19318 lua_settable(L, LUA_GLOBALSINDEX);
19321 lua_pushliteral(L, "memcache_get_string");
19322 lua_pushlightuserdata(L, p->conf.mc);
19323 lua_pushcclosure(L, f_memcache_get_string, 1);
19324 lua_settable(L, LUA_GLOBALSINDEX);
19327 lua_pushliteral(L, "memcache_exists");
19328 lua_pushlightuserdata(L, p->conf.mc);
19329 lua_pushcclosure(L, f_memcache_exists, 1);
19330 @@ -255,11 +251,11 @@
19331 lua_pushliteral(L, "request");
19333 lua_settable(L, LUA_GLOBALSINDEX);
19336 lua_pushliteral(L, "request");
19337 header_tbl = lua_gettop(L);
19338 lua_gettable(L, LUA_GLOBALSINDEX);
19341 c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
19342 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
19343 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
19344 @@ -267,84 +263,84 @@
19345 if (!buffer_is_empty(con->request.pathinfo)) {
19346 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
19350 c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
19351 c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
19354 /* register GET parameter */
19355 lua_pushliteral(L, "get");
19357 lua_settable(L, LUA_GLOBALSINDEX);
19360 lua_pushliteral(L, "get");
19361 header_tbl = lua_gettop(L);
19362 lua_gettable(L, LUA_GLOBALSINDEX);
19365 buffer_copy_string_buffer(b, con->uri.query);
19366 cache_export_get_params(L, header_tbl, b);
19369 - /* 2 default constants */
19370 + /* 2 default constants */
19371 lua_pushliteral(L, "CACHE_HIT");
19372 lua_pushboolean(L, 0);
19373 lua_settable(L, LUA_GLOBALSINDEX);
19376 lua_pushliteral(L, "CACHE_MISS");
19377 lua_pushboolean(L, 1);
19378 lua_settable(L, LUA_GLOBALSINDEX);
19381 /* load lua program */
19382 if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
19383 log_error_write(srv, __FILE__, __LINE__, "s",
19384 lua_tostring(L,-1));
19391 /* get return value */
19392 ret = (int)lua_tonumber(L, -1);
19395 - /* fetch the data from lua */
19397 + /* fetch the data from lua */
19398 lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
19401 if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
19402 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
19407 /* up to now it is a cache-hit, check if all files exist */
19414 if (!lua_to_c_is_table(L, "output_include")) {
19415 log_error_write(srv, __FILE__, __LINE__, "s",
19416 "output_include is missing or not a table");
19424 lua_pushstring(L, "output_include");
19427 curelem = lua_gettop(L);
19428 lua_gettable(L, LUA_GLOBALSINDEX);
19430 /* HOW-TO build a etag ?
19431 - * as we don't just have one file we have to take the stat()
19432 + * as we don't just have one file we have to take the stat()
19433 * from all base files, merge them and build the etag from
19437 * The mtime of the content is the mtime of the freshest base file
19443 lua_pushnil(L); /* first key */
19444 while (lua_next(L, curelem) != 0) {
19445 stat_cache_entry *sce = NULL;
19446 /* key' is at index -2 and value' at index -1 */
19449 if (lua_isstring(L, -1)) {
19450 const char *s = lua_tostring(L, -1);
19452 @@ -364,18 +360,18 @@
19453 /* a file is missing, call the handler to generate it */
19454 if (!buffer_is_empty(p->trigger_handler)) {
19455 ret = 1; /* cache-miss */
19458 log_error_write(srv, __FILE__, __LINE__, "s",
19459 "a file is missing, calling handler");
19464 /* handler not set -> 500 */
19468 log_error_write(srv, __FILE__, __LINE__, "s",
19469 "a file missing and no handler set");
19475 @@ -393,12 +389,12 @@
19481 lua_pop(L, 1); /* removes value'; keeps key' for next iteration */
19485 lua_settop(L, curelem - 1);
19490 char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
19491 @@ -410,9 +406,9 @@
19493 /* no Last-Modified specified */
19494 if ((mtime) && (NULL == ds)) {
19497 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
19500 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
19503 @@ -428,9 +424,9 @@
19509 if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
19510 - /* ok, the client already has our content,
19511 + /* ok, the client already has our content,
19512 * no need to send it again */
19514 chunkqueue_reset(con->write_queue);
19515 @@ -440,24 +436,24 @@
19516 chunkqueue_reset(con->write_queue);
19521 if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
19523 buffer_copy_string_buffer(con->uri.path, p->baseurl);
19524 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
19527 buffer_copy_string_buffer(con->physical.path, p->basedir);
19528 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
19531 chunkqueue_reset(con->write_queue);
19539 stream_close(&rm.st);
19543 return ret /* cache-error */;
19546 --- ../lighttpd-1.4.11/src/mod_compress.c 2005-11-18 13:49:14.000000000 +0200
19547 +++ lighttpd-1.4.12/src/mod_compress.c 2006-07-16 00:26:04.000000000 +0300
19549 #include <sys/stat.h>
19552 -#include <unistd.h>
19554 #include <stdlib.h>
19555 #include <string.h>
19557 #include "buffer.h"
19558 #include "response.h"
19559 #include "stat_cache.h"
19560 +#include "http_chunk.h"
19562 #include "plugin.h"
19567 #include "sys-mmap.h"
19568 +#include "sys-files.h"
19570 /* request: accept-encoding */
19571 #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
19572 @@ -55,97 +56,127 @@
19578 plugin_config **config_storage;
19579 - plugin_config conf;
19580 + plugin_config conf;
19583 INIT_FUNC(mod_compress_init) {
19587 p = calloc(1, sizeof(*p));
19590 p->ofn = buffer_init();
19591 p->b = buffer_init();
19597 FREE_FUNC(mod_compress_free) {
19598 plugin_data *p = p_d;
19603 if (!p) return HANDLER_GO_ON;
19606 buffer_free(p->ofn);
19610 if (p->config_storage) {
19612 for (i = 0; i < srv->config_context->used; i++) {
19613 plugin_config *s = p->config_storage[i];
19618 array_free(s->compress);
19619 buffer_free(s->compress_cache_dir);
19624 free(p->config_storage);
19633 return HANDLER_GO_ON;
19636 +void mkdir_recursive(const char *dir) {
19638 + char dir_copy[256];
19639 + char *p = dir_copy;
19641 + if (!dir || !dir[0])
19644 + strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
19646 + while ((p = strchr(p + 1, '/')) != NULL) {
19649 + if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
19655 + mkdir(dir, 0700);
19658 SETDEFAULTS_FUNC(mod_compress_setdefaults) {
19659 plugin_data *p = p_d;
19662 - config_values_t cv[] = {
19664 + config_values_t cv[] = {
19665 { "compress.cache-dir", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19666 { "compress.filetype", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
19667 { "compress.max-filesize", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
19668 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19672 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19675 for (i = 0; i < srv->config_context->used; i++) {
19679 s = calloc(1, sizeof(plugin_config));
19680 s->compress_cache_dir = buffer_init();
19681 s->compress = array_init();
19682 s->compress_max_filesize = 0;
19685 cv[0].destination = s->compress_cache_dir;
19686 cv[1].destination = s->compress;
19687 cv[2].destination = &(s->compress_max_filesize);
19690 p->config_storage[i] = s;
19693 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19694 return HANDLER_ERROR;
19698 if (!buffer_is_empty(s->compress_cache_dir)) {
19700 if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19701 - log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
19703 + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
19704 s->compress_cache_dir, strerror(errno));
19706 - return HANDLER_ERROR;
19707 + mkdir_recursive(s->compress_cache_dir->ptr);
19709 + if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19711 + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
19712 + s->compress_cache_dir, strerror(errno));
19714 + return HANDLER_ERROR;
19721 return HANDLER_GO_ON;
19727 @@ -153,32 +184,32 @@
19740 - if (Z_OK != deflateInit2(&z,
19742 + if (Z_OK != deflateInit2(&z,
19743 Z_DEFAULT_COMPRESSION,
19746 -MAX_WBITS, /* supress zlib-header */
19748 Z_DEFAULT_STRATEGY)) {
19753 z.next_in = (unsigned char *)start;
19754 z.avail_in = st_size;
19760 buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
19763 /* write gzip header */
19766 c = (unsigned char *)p->b->ptr;
19769 @@ -190,24 +221,24 @@
19770 c[7] = (mtime >> 24) & 0xff;
19771 c[8] = 0x00; /* extra flags */
19772 c[9] = 0x03; /* UNIX */
19776 z.next_out = (unsigned char *)p->b->ptr + p->b->used;
19777 z.avail_out = p->b->size - p->b->used - 8;
19781 if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19788 p->b->used += z.total_out;
19791 crc = generate_crc32c(start, st_size);
19794 c = (unsigned char *)p->b->ptr + p->b->used;
19797 c[0] = (crc >> 0) & 0xff;
19798 c[1] = (crc >> 8) & 0xff;
19799 c[2] = (crc >> 16) & 0xff;
19800 @@ -221,51 +252,51 @@
19801 if (Z_OK != deflateEnd(&z)) {
19809 static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19820 - if (Z_OK != deflateInit2(&z,
19822 + if (Z_OK != deflateInit2(&z,
19823 Z_DEFAULT_COMPRESSION,
19826 -MAX_WBITS, /* supress zlib-header */
19828 Z_DEFAULT_STRATEGY)) {
19834 z.avail_in = st_size;
19838 buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
19841 z.next_out = (unsigned char *)p->b->ptr;
19842 z.avail_out = p->b->size;
19846 if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19853 p->b->used += z.total_out;
19856 if (Z_OK != deflateEnd(&z)) {
19864 @@ -274,48 +305,48 @@
19866 static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19877 - if (BZ_OK != BZ2_bzCompressInit(&bz,
19879 + if (BZ_OK != BZ2_bzCompressInit(&bz,
19880 9, /* blocksize = 900k */
19882 0)) { /* workFactor: default */
19887 bz.next_in = (char *)start;
19888 bz.avail_in = st_size;
19889 bz.total_in_lo32 = 0;
19890 bz.total_in_hi32 = 0;
19893 buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
19896 bz.next_out = p->b->ptr;
19897 bz.avail_out = p->b->size;
19898 bz.total_out_lo32 = 0;
19899 bz.total_out_hi32 = 0;
19902 if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
19903 BZ2_bzCompressEnd(&bz);
19908 /* file is too large for now */
19909 if (bz.total_out_hi32) return -1;
19913 p->b->used = bz.total_out_lo32;
19916 if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
19924 @@ -326,47 +357,50 @@
19926 const char *filename = fn->ptr;
19929 + stat_cache_entry *compressed_sce = NULL;
19931 + if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
19934 if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
19936 - /* don't mmap files > 128Mb
19939 + /* don't mmap files > 128Mb
19941 * we could use a sliding window, but currently there is no need for it
19945 if (sce->st.st_size > 128 * 1024 * 1024) return -1;
19948 buffer_reset(p->ofn);
19949 buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
19950 - BUFFER_APPEND_SLASH(p->ofn);
19952 + PATHNAME_APPEND_SLASH(p->ofn);
19954 if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
19955 size_t offset = p->ofn->used - 1;
19956 char *dir, *nextdir;
19959 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
19962 buffer_copy_string_buffer(p->b, p->ofn);
19966 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
19970 if (-1 == mkdir(p->b->ptr, 0700)) {
19971 if (errno != EEXIST) {
19972 log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
19983 buffer_append_string_buffer(p->ofn, con->uri.path);
19988 case HTTP_ACCEPT_ENCODING_GZIP:
19989 buffer_append_string(p->ofn, "-gzip-");
19990 @@ -381,55 +415,64 @@
19991 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
19996 buffer_append_string_buffer(p->ofn, sce->etag);
20000 + if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
20001 + /* file exists */
20003 + http_chunk_append_file(srv, con, p->ofn, 0, compressed_sce->st.st_size);
20004 + con->file_finished = 1;
20009 if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
20010 if (errno == EEXIST) {
20011 /* cache-entry exists */
20013 - log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
20015 - buffer_copy_string_buffer(con->physical.path, p->ofn);
20021 - log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
20024 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20025 + "creating cachefile", p->ofn,
20026 + "failed", strerror(errno));
20031 - log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
20034 if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
20035 - log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20037 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20038 + "opening plain-file", fn,
20039 + "failed", strerror(errno));
20050 if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20051 - log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20053 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20055 + "failed", strerror(errno));
20065 - case HTTP_ACCEPT_ENCODING_GZIP:
20066 + case HTTP_ACCEPT_ENCODING_GZIP:
20067 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20069 - case HTTP_ACCEPT_ENCODING_DEFLATE:
20070 + case HTTP_ACCEPT_ENCODING_DEFLATE:
20071 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20075 - case HTTP_ACCEPT_ENCODING_BZIP2:
20076 + case HTTP_ACCEPT_ENCODING_BZIP2:
20077 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20080 @@ -437,26 +480,27 @@
20086 if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
20087 - munmap(start, sce->st.st_size);
20088 + munmap(start, sce->st.st_size);
20095 if ((size_t)r != p->b->used) {
20101 munmap(start, sce->st.st_size);
20106 if (ret != 0) return -1;
20108 - buffer_copy_string_buffer(con->physical.path, p->ofn);
20111 + http_chunk_append_file(srv, con, p->ofn, 0, r);
20112 + con->file_finished = 1;
20117 @@ -465,43 +509,44 @@
20124 if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
20127 /* don't mmap files > 128M
20130 * we could use a sliding window, but currently there is no need for it
20134 if (sce->st.st_size > 128 * 1024 * 1024) return -1;
20138 if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
20139 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20146 - if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20148 + start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
20152 + if (MAP_FAILED == start) {
20153 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20163 - case HTTP_ACCEPT_ENCODING_GZIP:
20164 + case HTTP_ACCEPT_ENCODING_GZIP:
20165 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20167 - case HTTP_ACCEPT_ENCODING_DEFLATE:
20168 + case HTTP_ACCEPT_ENCODING_DEFLATE:
20169 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20173 - case HTTP_ACCEPT_ENCODING_BZIP2:
20174 + case HTTP_ACCEPT_ENCODING_BZIP2:
20175 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20178 @@ -509,69 +554,64 @@
20184 munmap(start, sce->st.st_size);
20188 if (ret != 0) return -1;
20191 chunkqueue_reset(con->write_queue);
20192 b = chunkqueue_get_append_buffer(con->write_queue);
20193 buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
20196 buffer_reset(con->physical.path);
20199 con->file_finished = 1;
20200 con->file_started = 1;
20207 -#define PATCH(x) \
20208 - p->conf.x = s->x;
20209 static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
20211 plugin_config *s = p->config_storage[0];
20213 - PATCH(compress_cache_dir);
20215 - PATCH(compress_max_filesize);
20217 + PATCH_OPTION(compress_cache_dir);
20218 + PATCH_OPTION(compress);
20219 + PATCH_OPTION(compress_max_filesize);
20221 /* skip the first, the global context */
20222 for (i = 1; i < srv->config_context->used; i++) {
20223 data_config *dc = (data_config *)srv->config_context->data[i];
20224 s = p->config_storage[i];
20227 /* condition didn't match */
20228 if (!config_check_cond(srv, con, dc)) continue;
20232 for (j = 0; j < dc->value->used; j++) {
20233 data_unset *du = dc->value->data[j];
20236 if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
20237 - PATCH(compress_cache_dir);
20238 + PATCH_OPTION(compress_cache_dir);
20239 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
20241 + PATCH_OPTION(compress);
20242 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
20243 - PATCH(compress_max_filesize);
20244 + PATCH_OPTION(compress_max_filesize);
20254 PHYSICALPATH_FUNC(mod_compress_physical) {
20255 plugin_data *p = p_d;
20258 stat_cache_entry *sce = NULL;
20261 /* only GET and POST can get compressed */
20262 - if (con->request.http_method != HTTP_METHOD_GET &&
20263 + if (con->request.http_method != HTTP_METHOD_GET &&
20264 con->request.http_method != HTTP_METHOD_POST) {
20265 return HANDLER_GO_ON;
20267 @@ -579,46 +619,49 @@
20268 if (buffer_is_empty(con->physical.path)) {
20269 return HANDLER_GO_ON;
20273 mod_compress_patch_connection(srv, con, p);
20276 max_fsize = p->conf.compress_max_filesize;
20278 stat_cache_get_entry(srv, con, con->physical.path, &sce);
20280 /* don't compress files that are too large as we need to much time to handle them */
20281 if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
20284 + /* compressing the file might lead to larger files instead */
20285 + if (sce->st.st_size < 128) return HANDLER_GO_ON;
20287 /* check if mimetype is in compress-config */
20288 for (m = 0; m < p->conf.compress->used; m++) {
20289 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
20292 if (!compress_ds) {
20293 log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
20296 return HANDLER_GO_ON;
20300 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
20301 /* mimetype found */
20305 /* the response might change according to Accept-Encoding */
20306 response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
20309 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
20310 int accept_encoding = 0;
20311 char *value = ds->value->ptr;
20312 int srv_encodings = 0;
20313 int matched_encodings = 0;
20316 /* get client side support encodings */
20317 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
20318 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
20319 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
20320 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
20321 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
20324 /* get server side supported ones */
20326 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
20327 @@ -627,18 +670,31 @@
20328 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
20329 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
20333 /* find matching entries */
20334 matched_encodings = accept_encoding & srv_encodings;
20337 if (matched_encodings) {
20338 const char *dflt_gzip = "gzip";
20339 const char *dflt_deflate = "deflate";
20340 const char *dflt_bzip2 = "bzip2";
20343 const char *compression_name = NULL;
20344 int compression_type = 0;
20348 + mtime = strftime_cache_get(srv, sce->st.st_mtime);
20349 + etag_mutate(con->physical.etag, sce->etag);
20351 + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20352 + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20354 + /* perhaps we don't even have to compress the file as the browser still has the
20355 + * current version */
20356 + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20357 + return HANDLER_FINISHED;
20360 /* select best matching encoding */
20361 if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
20362 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
20363 @@ -650,31 +706,21 @@
20364 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
20365 compression_name = dflt_deflate;
20369 - if (p->conf.compress_cache_dir->used) {
20370 - if (0 == deflate_file_to_file(srv, con, p,
20371 - con->physical.path, sce, compression_type)) {
20374 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20376 - mtime = strftime_cache_get(srv, sce->st.st_mtime);
20377 - response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20379 - etag_mutate(con->physical.etag, sce->etag);
20380 - response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20382 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20384 - return HANDLER_GO_ON;
20386 - } else if (0 == deflate_file_to_buffer(srv, con, p,
20387 - con->physical.path, sce, compression_type)) {
20389 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20390 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20393 + /* deflate it to file (cached) or to memory */
20394 + if (0 == deflate_file_to_file(srv, con, p,
20395 + con->physical.path, sce, compression_type) ||
20396 + 0 == deflate_file_to_buffer(srv, con, p,
20397 + con->physical.path, sce, compression_type)) {
20399 + response_header_overwrite(srv, con,
20400 + CONST_STR_LEN("Content-Encoding"),
20401 + compression_name, strlen(compression_name));
20403 + response_header_overwrite(srv, con,
20404 + CONST_STR_LEN("Content-Type"),
20405 + CONST_BUF_LEN(sce->content_type));
20407 return HANDLER_FINISHED;
20410 @@ -682,20 +728,20 @@
20416 return HANDLER_GO_ON;
20419 int mod_compress_plugin_init(plugin *p) {
20420 p->version = LIGHTTPD_VERSION_ID;
20421 p->name = buffer_init_string("compress");
20424 p->init = mod_compress_init;
20425 p->set_defaults = mod_compress_setdefaults;
20426 p->handle_subrequest_start = mod_compress_physical;
20427 p->cleanup = mod_compress_free;
20435 --- ../lighttpd-1.4.11/src/mod_dirlisting.c 2006-01-13 00:00:45.000000000 +0200
20436 +++ lighttpd-1.4.12/src/mod_dirlisting.c 2006-07-16 00:26:04.000000000 +0300
20439 #include <stdlib.h>
20440 #include <string.h>
20441 -#include <dirent.h>
20442 #include <assert.h>
20445 -#include <unistd.h>
20450 #include "response.h"
20451 #include "stat_cache.h"
20452 #include "stream.h"
20455 +#include "sys-strings.h"
20458 * this is a dirlisting for a lighttpd plugin
20459 @@ -27,10 +28,13 @@
20460 #include <sys/syslimits.h>
20463 -#ifdef HAVE_ATTR_ATTRIBUTES_H
20465 #include <attr/attributes.h>
20468 +#include "sys-files.h"
20469 +#include "sys-strings.h"
20471 /* plugin config for all request/connections */
20475 unsigned short hide_readme_file;
20476 unsigned short show_header;
20477 unsigned short hide_header_file;
20480 excludes_buffer *excludes;
20482 buffer *external_css;
20483 @@ -63,13 +67,14 @@
20490 buffer *content_charset;
20494 plugin_config **config_storage;
20496 - plugin_config conf;
20498 + plugin_config conf;
20501 excludes_buffer *excludes_buffer_init(void) {
20502 @@ -146,44 +151,46 @@
20503 /* init the plugin data */
20504 INIT_FUNC(mod_dirlisting_init) {
20508 p = calloc(1, sizeof(*p));
20510 p->tmp_buf = buffer_init();
20511 p->content_charset = buffer_init();
20513 + p->path = buffer_init();
20518 /* detroy the plugin data */
20519 FREE_FUNC(mod_dirlisting_free) {
20520 plugin_data *p = p_d;
20525 if (!p) return HANDLER_GO_ON;
20528 if (p->config_storage) {
20530 for (i = 0; i < srv->config_context->used; i++) {
20531 plugin_config *s = p->config_storage[i];
20537 excludes_buffer_free(s->excludes);
20538 buffer_free(s->external_css);
20539 buffer_free(s->encoding);
20544 free(p->config_storage);
20548 buffer_free(p->tmp_buf);
20549 + buffer_free(p->path);
20550 buffer_free(p->content_charset);
20556 return HANDLER_GO_ON;
20559 @@ -215,10 +222,10 @@
20560 if (0 != excludes_buffer_append(s->excludes,
20561 ((data_string *)(da->value->data[j]))->value)) {
20563 - log_error_write(srv, __FILE__, __LINE__, "sb",
20564 + log_error_write(srv, __FILE__, __LINE__, "sb",
20565 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
20567 - log_error_write(srv, __FILE__, __LINE__, "s",
20568 + log_error_write(srv, __FILE__, __LINE__, "s",
20569 "pcre support is missing, please install libpcre and the headers");
20572 @@ -233,8 +240,8 @@
20573 SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
20574 plugin_data *p = p_d;
20577 - config_values_t cv[] = {
20579 + config_values_t cv[] = {
20580 { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
20581 { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
20582 { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
20583 @@ -245,18 +252,18 @@
20584 { "dir-listing.show-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
20585 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
20586 { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
20589 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
20593 if (!p) return HANDLER_ERROR;
20596 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20599 for (i = 0; i < srv->config_context->used; i++) {
20604 s = calloc(1, sizeof(plugin_config));
20605 s->excludes = excludes_buffer_init();
20606 s->dir_listing = 0;
20607 @@ -267,7 +274,7 @@
20608 s->show_header = 0;
20609 s->hide_header_file = 0;
20610 s->encoding = buffer_init();
20613 cv[0].destination = s->excludes;
20614 cv[1].destination = &(s->dir_listing);
20615 cv[2].destination = &(s->hide_dot_files);
20616 @@ -292,60 +299,57 @@
20617 return HANDLER_GO_ON;
20620 -#define PATCH(x) \
20621 - p->conf.x = s->x;
20622 static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
20624 plugin_config *s = p->config_storage[0];
20626 - PATCH(dir_listing);
20627 - PATCH(external_css);
20628 - PATCH(hide_dot_files);
20630 - PATCH(show_readme);
20631 - PATCH(hide_readme_file);
20632 - PATCH(show_header);
20633 - PATCH(hide_header_file);
20636 + PATCH_OPTION(dir_listing);
20637 + PATCH_OPTION(external_css);
20638 + PATCH_OPTION(hide_dot_files);
20639 + PATCH_OPTION(encoding);
20640 + PATCH_OPTION(show_readme);
20641 + PATCH_OPTION(hide_readme_file);
20642 + PATCH_OPTION(show_header);
20643 + PATCH_OPTION(hide_header_file);
20644 + PATCH_OPTION(excludes);
20646 /* skip the first, the global context */
20647 for (i = 1; i < srv->config_context->used; i++) {
20648 data_config *dc = (data_config *)srv->config_context->data[i];
20649 s = p->config_storage[i];
20652 /* condition didn't match */
20653 if (!config_check_cond(srv, con, dc)) continue;
20657 for (j = 0; j < dc->value->used; j++) {
20658 data_unset *du = dc->value->data[j];
20661 if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
20662 buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
20663 - PATCH(dir_listing);
20664 + PATCH_OPTION(dir_listing);
20665 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
20666 - PATCH(hide_dot_files);
20667 + PATCH_OPTION(hide_dot_files);
20668 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
20669 - PATCH(external_css);
20670 + PATCH_OPTION(external_css);
20671 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
20673 + PATCH_OPTION(encoding);
20674 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
20675 - PATCH(show_readme);
20676 + PATCH_OPTION(show_readme);
20677 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
20678 - PATCH(hide_readme_file);
20679 + PATCH_OPTION(hide_readme_file);
20680 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
20681 - PATCH(show_header);
20682 + PATCH_OPTION(show_header);
20683 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
20684 - PATCH(hide_header_file);
20685 + PATCH_OPTION(hide_header_file);
20686 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
20688 + PATCH_OPTION(excludes);
20700 @@ -432,7 +436,7 @@
20702 static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
20706 BUFFER_APPEND_STRING_CONST(out,
20707 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
20708 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
20709 @@ -492,11 +496,11 @@
20710 if (p->conf.show_header) {
20712 /* if we have a HEADER file, display it in <pre class="header"></pre> */
20715 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20716 - BUFFER_APPEND_SLASH(p->tmp_buf);
20717 + PATHNAME_APPEND_SLASH(p->tmp_buf);
20718 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
20721 if (-1 != stream_open(&s, p->tmp_buf)) {
20722 BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
20723 buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20724 @@ -531,21 +535,21 @@
20726 static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
20730 BUFFER_APPEND_STRING_CONST(out,
20737 if (p->conf.show_readme) {
20739 /* if we have a README file, display it in <pre class="readme"></pre> */
20742 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20743 - BUFFER_APPEND_SLASH(p->tmp_buf);
20744 + PATHNAME_APPEND_SLASH(p->tmp_buf);
20745 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
20748 if (-1 != stream_open(&s, p->tmp_buf)) {
20749 BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
20750 buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20751 @@ -553,7 +557,7 @@
20757 BUFFER_APPEND_STRING_CONST(out,
20758 "<div class=\"foot\">"
20760 @@ -576,7 +580,6 @@
20762 struct dirent *dent;
20764 - char *path, *path_file;
20766 int hide_dotfiles = p->conf.hide_dot_files;
20767 dirls_list_t dirs, files, *list;
20768 @@ -586,6 +589,7 @@
20770 const char *content_type;
20776 @@ -594,10 +598,10 @@
20780 - if (dir->used == 0) return -1;
20782 - i = dir->used - 1;
20783 + /* empty pathname, never ... */
20784 + if (buffer_is_empty(dir)) return -1;
20786 + /* max-length for the opendir */
20787 #ifdef HAVE_PATHCONF
20788 if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
20790 @@ -606,22 +610,24 @@
20791 name_max = 256; /* stupid default */
20794 -#elif defined __WIN32
20795 +#elif defined _WIN32
20796 name_max = FILENAME_MAX;
20798 name_max = NAME_MAX;
20801 - path = malloc(dir->used + name_max);
20803 - strcpy(path, dir->ptr);
20804 - path_file = path + i;
20806 - if (NULL == (dp = opendir(path))) {
20807 - log_error_write(srv, __FILE__, __LINE__, "sbs",
20808 + buffer_copy_string_buffer(p->path, dir);
20809 + PATHNAME_APPEND_SLASH(p->path);
20812 + /* append *.* to the path */
20813 + buffer_append_string(path, "*.*");
20816 + if (NULL == (dp = opendir(p->path->ptr))) {
20817 + log_error_write(srv, __FILE__, __LINE__, "sbs",
20818 "opendir failed:", dir, strerror(errno));
20824 @@ -633,7 +639,7 @@
20826 files.size = DIRLIST_BLOB_SIZE;
20830 while ((dent = readdir(dp)) != NULL) {
20831 unsigned short exclude_match = 0;
20833 @@ -686,15 +692,21 @@
20836 i = strlen(dent->d_name);
20839 /* NOTE: the manual says, d_name is never more than NAME_MAX
20840 * so this should actually not be a buffer-overflow-risk
20842 if (i > (size_t)name_max) continue;
20844 - memcpy(path_file, dent->d_name, i + 1);
20845 - if (stat(path, &st) != 0)
20847 + /* build the dirname */
20848 + buffer_copy_string_buffer(p->path, dir);
20849 + PATHNAME_APPEND_SLASH(p->path);
20850 + buffer_append_string(p->path, dent->d_name);
20852 + if (stat(p->path->ptr, &st) != 0) {
20853 + fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
20858 if (S_ISDIR(st.st_mode))
20859 @@ -740,7 +752,7 @@
20861 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
20865 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
20866 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
20867 BUFFER_APPEND_STRING_CONST(out, "/\">");
20868 @@ -757,18 +769,22 @@
20869 tmp = files.ent[i];
20871 content_type = NULL;
20875 if (con->conf.use_xattr) {
20876 - memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
20877 + /* build the dirname */
20878 + buffer_copy_string_buffer(p->path, dir);
20879 + PATHNAME_APPEND_SLASH(p->path);
20880 + buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
20882 attrlen = sizeof(attrval) - 1;
20883 - if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
20884 + if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
20885 attrval[attrlen] = '\0';
20886 content_type = attrval;
20892 if (content_type == NULL) {
20893 content_type = "application/octet-stream";
20894 for (k = 0; k < con->conf.mimetypes->used; k++) {
20895 @@ -788,7 +804,7 @@
20901 #ifdef HAVE_LOCALTIME_R
20902 localtime_r(&(tmp->mtime), &tm);
20903 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
20904 @@ -814,7 +830,6 @@
20910 http_list_directory_footer(srv, con, p, out);
20912 @@ -837,36 +852,55 @@
20913 URIHANDLER_FUNC(mod_dirlisting_subrequest) {
20914 plugin_data *p = p_d;
20915 stat_cache_entry *sce = NULL;
20919 - if (con->physical.path->used == 0) return HANDLER_GO_ON;
20920 - if (con->uri.path->used == 0) return HANDLER_GO_ON;
20924 + if (con->uri.path->used < 2) return HANDLER_GO_ON;
20925 if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
20927 + if (con->physical.path->used == 0) return HANDLER_GO_ON;
20929 mod_dirlisting_patch_connection(srv, con, p);
20931 if (!p->conf.dir_listing) return HANDLER_GO_ON;
20934 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20935 + /* just a second ago the file was still there */
20936 + return HANDLER_GO_ON;
20939 + if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20941 if (con->conf.log_request_handling) {
20942 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing");
20943 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
20946 - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20947 - fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
20950 + /* perhaps this a cachable request
20951 + * - we use the etag of the directory
20954 + etag_mutate(con->physical.etag, sce->etag);
20955 + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20957 + /* prepare header */
20958 + if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
20959 + mtime = strftime_cache_get(srv, sce->st.st_mtime);
20960 + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20962 + mtime = ds->value;
20965 - if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20968 + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20969 + return HANDLER_FINISHED;
20972 if (http_list_directory(srv, con, p, con->physical.path)) {
20973 /* dirlisting failed */
20974 con->http_status = 403;
20978 buffer_reset(con->physical.path);
20982 return HANDLER_FINISHED;
20984 @@ -876,13 +910,13 @@
20985 int mod_dirlisting_plugin_init(plugin *p) {
20986 p->version = LIGHTTPD_VERSION_ID;
20987 p->name = buffer_init_string("dirlisting");
20990 p->init = mod_dirlisting_init;
20991 p->handle_subrequest_start = mod_dirlisting_subrequest;
20992 p->set_defaults = mod_dirlisting_set_defaults;
20993 p->cleanup = mod_dirlisting_free;
21001 --- ../lighttpd-1.4.11/src/mod_evasive.c 2006-01-04 15:24:51.000000000 +0200
21002 +++ lighttpd-1.4.12/src/mod_evasive.c 2006-07-16 00:26:04.000000000 +0300
21003 @@ -31,100 +31,97 @@
21009 plugin_config **config_storage;
21011 - plugin_config conf;
21013 + plugin_config conf;
21016 INIT_FUNC(mod_evasive_init) {
21020 p = calloc(1, sizeof(*p));
21026 FREE_FUNC(mod_evasive_free) {
21027 plugin_data *p = p_d;
21032 if (!p) return HANDLER_GO_ON;
21035 if (p->config_storage) {
21037 for (i = 0; i < srv->config_context->used; i++) {
21038 plugin_config *s = p->config_storage[i];
21043 free(p->config_storage);
21050 return HANDLER_GO_ON;
21053 SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
21054 plugin_data *p = p_d;
21057 - config_values_t cv[] = {
21059 + config_values_t cv[] = {
21060 { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
21061 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21065 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21068 for (i = 0; i < srv->config_context->used; i++) {
21072 s = calloc(1, sizeof(plugin_config));
21076 cv[0].destination = &(s->max_conns);
21079 p->config_storage[i] = s;
21082 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21083 return HANDLER_ERROR;
21088 return HANDLER_GO_ON;
21091 -#define PATCH(x) \
21092 - p->conf.x = s->x;
21093 static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
21095 plugin_config *s = p->config_storage[0];
21097 - PATCH(max_conns);
21099 + PATCH_OPTION(max_conns);
21101 /* skip the first, the global context */
21102 for (i = 1; i < srv->config_context->used; i++) {
21103 data_config *dc = (data_config *)srv->config_context->data[i];
21104 s = p->config_storage[i];
21107 /* condition didn't match */
21108 if (!config_check_cond(srv, con, dc)) continue;
21112 for (j = 0; j < dc->value->used; j++) {
21113 data_unset *du = dc->value->data[j];
21116 if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
21117 - PATCH(max_conns);
21118 + PATCH_OPTION(max_conns);
21128 URIHANDLER_FUNC(mod_evasive_uri_handler) {
21129 plugin_data *p = p_d;
21130 @@ -132,10 +129,10 @@
21133 if (con->uri.path->used == 0) return HANDLER_GO_ON;
21136 mod_evasive_patch_connection(srv, con, p);
21138 - /* no limit set, nothing to block */
21140 + /* no limit set, nothing to block */
21141 if (p->conf.max_conns == 0) return HANDLER_GO_ON;
21143 for (j = 0; j < srv->conns->used; j++) {
21144 @@ -147,7 +144,7 @@
21145 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
21146 c->state > CON_STATE_REQUEST_END) {
21150 if (conns_by_ip > p->conf.max_conns) {
21151 log_error_write(srv, __FILE__, __LINE__, "ss",
21152 inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
21153 @@ -158,7 +155,7 @@
21159 return HANDLER_GO_ON;
21162 @@ -166,13 +163,13 @@
21163 int mod_evasive_plugin_init(plugin *p) {
21164 p->version = LIGHTTPD_VERSION_ID;
21165 p->name = buffer_init_string("evasive");
21168 p->init = mod_evasive_init;
21169 p->set_defaults = mod_evasive_set_defaults;
21170 p->handle_uri_clean = mod_evasive_uri_handler;
21171 p->cleanup = mod_evasive_free;
21179 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
21180 +++ lighttpd-1.4.12/src/mod_evhost.c 2006-07-16 00:26:03.000000000 +0300
21182 #include "response.h"
21183 #include "stat_cache.h"
21185 +#include "sys-files.h"
21188 /* unparsed pieces */
21189 buffer *path_pieces_raw;
21192 /* pieces for path creation */
21194 buffer **path_pieces;
21195 @@ -21,14 +23,14 @@
21198 plugin_config **config_storage;
21199 - plugin_config conf;
21200 + plugin_config conf;
21203 INIT_FUNC(mod_evhost_init) {
21207 p = calloc(1, sizeof(*p));
21210 p->tmp_buf = buffer_init();
21213 @@ -36,34 +38,34 @@
21215 FREE_FUNC(mod_evhost_free) {
21216 plugin_data *p = p_d;
21221 if (!p) return HANDLER_GO_ON;
21224 if (p->config_storage) {
21226 for (i = 0; i < srv->config_context->used; i++) {
21227 plugin_config *s = p->config_storage[i];
21232 if(s->path_pieces) {
21234 for (j = 0; j < s->len; j++) {
21235 buffer_free(s->path_pieces[j]);
21239 free(s->path_pieces);
21243 buffer_free(s->path_pieces_raw);
21248 free(p->config_storage);
21252 buffer_free(p->tmp_buf);
21255 @@ -73,30 +75,30 @@
21257 static void mod_evhost_parse_pattern(plugin_config *s) {
21258 char *ptr = s->path_pieces_raw->ptr,*pos;
21261 s->path_pieces = NULL;
21264 for(pos=ptr;*ptr;ptr++) {
21266 s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
21267 s->path_pieces[s->len] = buffer_init();
21268 s->path_pieces[s->len+1] = buffer_init();
21271 buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
21275 buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
21284 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
21285 s->path_pieces[s->len] = buffer_init();
21288 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
21294 @@ -104,9 +106,9 @@
21295 SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
21296 plugin_data *p = p_d;
21304 * # define a pattern for the host url finding
21306 @@ -117,39 +119,39 @@
21307 * # %4 => subdomain 2 name
21309 * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
21314 - config_values_t cv[] = {
21316 + config_values_t cv[] = {
21317 { "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
21318 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21322 if (!p) return HANDLER_ERROR;
21325 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21328 for (i = 0; i < srv->config_context->used; i++) {
21332 s = calloc(1, sizeof(plugin_config));
21333 s->path_pieces_raw = buffer_init();
21334 s->path_pieces = NULL;
21338 cv[0].destination = s->path_pieces_raw;
21341 p->config_storage[i] = s;
21344 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21345 return HANDLER_ERROR;
21349 if (s->path_pieces_raw->used != 0) {
21350 mod_evhost_parse_pattern(s);
21355 return HANDLER_GO_ON;
21358 @@ -158,7 +160,7 @@
21359 * - %0 - full hostname (authority w/o port)
21361 * - %2 - domain.tld
21366 static int mod_evhost_parse_host(connection *con,array *host) {
21367 @@ -168,7 +170,7 @@
21373 /* first, find the domain + tld */
21374 for(;ptr > con->uri.authority->ptr;ptr--) {
21376 @@ -179,18 +181,18 @@
21382 ds = data_string_init();
21383 buffer_copy_string(ds->key,"%0");
21386 /* if we stopped at a dot, skip the dot */
21387 if (*ptr == '.') ptr++;
21388 buffer_copy_string_len(ds->value, ptr, colon-ptr);
21391 array_insert_unique(host,(data_unset *)ds);
21394 /* if the : is not the start of the authority, go on parsing the hostname */
21397 if (colon != con->uri.authority->ptr) {
21398 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
21400 @@ -200,59 +202,55 @@
21401 buffer_copy_string(ds->key,"%");
21402 buffer_append_long(ds->key, i++);
21403 buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
21406 array_insert_unique(host,(data_unset *)ds);
21413 /* if the . is not the first charactor of the hostname */
21414 if (colon != ptr) {
21415 ds = data_string_init();
21416 buffer_copy_string(ds->key,"%");
21417 buffer_append_long(ds->key, i++);
21418 buffer_copy_string_len(ds->value,ptr,colon-ptr);
21421 array_insert_unique(host,(data_unset *)ds);
21429 -#define PATCH(x) \
21430 - p->conf.x = s->x;
21431 static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
21433 plugin_config *s = p->config_storage[0];
21435 - PATCH(path_pieces);
21439 + PATCH_OPTION(path_pieces);
21440 + PATCH_OPTION(len);
21442 /* skip the first, the global context */
21443 for (i = 1; i < srv->config_context->used; i++) {
21444 data_config *dc = (data_config *)srv->config_context->data[i];
21445 s = p->config_storage[i];
21448 /* condition didn't match */
21449 if (!config_check_cond(srv, con, dc)) continue;
21453 for (j = 0; j < dc->value->used; j++) {
21454 data_unset *du = dc->value->data[j];
21457 if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
21458 - PATCH(path_pieces);
21460 + PATCH_OPTION(path_pieces);
21461 + PATCH_OPTION(len);
21472 static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
21473 plugin_data *p = p_d;
21474 @@ -261,29 +259,29 @@
21475 register char *ptr;
21477 stat_cache_entry *sce = NULL;
21480 /* not authority set */
21481 if (con->uri.authority->used == 0) return HANDLER_GO_ON;
21484 mod_evhost_patch_connection(srv, con, p);
21487 /* missing even default(global) conf */
21488 if (0 == p->conf.len) {
21489 return HANDLER_GO_ON;
21492 parsed_host = array_init();
21495 mod_evhost_parse_host(con, parsed_host);
21498 /* build document-root */
21499 buffer_reset(p->tmp_buf);
21502 for (i = 0; i < p->conf.len; i++) {
21503 ptr = p->conf.path_pieces[i]->ptr;
21508 if (*(ptr+1) == '%') {
21510 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
21511 @@ -298,11 +296,11 @@
21512 buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
21516 - BUFFER_APPEND_SLASH(p->tmp_buf);
21519 + PATHNAME_APPEND_SLASH(p->tmp_buf);
21521 array_free(parsed_host);
21524 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
21525 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
21527 @@ -310,11 +308,11 @@
21528 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
21534 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
21538 return HANDLER_GO_ON;
21541 @@ -325,9 +323,9 @@
21542 p->set_defaults = mod_evhost_set_defaults;
21543 p->handle_docroot = mod_evhost_uri_handler;
21544 p->cleanup = mod_evhost_free;
21553 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
21554 +++ lighttpd-1.4.12/src/mod_expire.c 2006-07-16 00:26:04.000000000 +0300
21556 #include "stat_cache.h"
21559 - * this is a expire module for a lighttpd
21561 + * this is a expire module for a lighttpd
21563 * set 'Expires:' HTTP Headers on demand
21566 @@ -27,51 +27,51 @@
21572 buffer *expire_tstmp;
21575 plugin_config **config_storage;
21577 - plugin_config conf;
21579 + plugin_config conf;
21582 /* init the plugin data */
21583 INIT_FUNC(mod_expire_init) {
21587 p = calloc(1, sizeof(*p));
21590 p->expire_tstmp = buffer_init();
21593 buffer_prepare_copy(p->expire_tstmp, 255);
21599 /* detroy the plugin data */
21600 FREE_FUNC(mod_expire_free) {
21601 plugin_data *p = p_d;
21606 if (!p) return HANDLER_GO_ON;
21609 buffer_free(p->expire_tstmp);
21612 if (p->config_storage) {
21614 for (i = 0; i < srv->config_context->used; i++) {
21615 plugin_config *s = p->config_storage[i];
21618 array_free(s->expire_url);
21623 free(p->config_storage);
21630 return HANDLER_GO_ON;
21633 @@ -79,25 +79,25 @@
21646 * '(access|modification) [plus] {<num> <type>}*'
21649 * e.g. 'access 1 years'
21653 if (expire->used == 0) {
21654 - log_error_write(srv, __FILE__, __LINE__, "s",
21655 + log_error_write(srv, __FILE__, __LINE__, "s",
21664 if (0 == strncmp(ts, "access ", 7)) {
21667 @@ -110,39 +110,39 @@
21668 "invalid <base>:", ts);
21673 if (0 == strncmp(ts, "plus ", 5)) {
21674 /* skip the optional plus */
21679 /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
21685 if (NULL == (space = strchr(ts, ' '))) {
21686 - log_error_write(srv, __FILE__, __LINE__, "ss",
21687 + log_error_write(srv, __FILE__, __LINE__, "ss",
21688 "missing space after <num>:", ts);
21693 num = strtol(ts, &err, 10);
21695 - log_error_write(srv, __FILE__, __LINE__, "ss",
21696 + log_error_write(srv, __FILE__, __LINE__, "ss",
21697 "missing <type> after <num>:", ts);
21705 if (NULL != (space = strchr(ts, ' '))) {
21715 0 == strncmp(ts, "years", slen)) {
21716 num *= 60 * 60 * 24 * 30 * 12;
21717 } else if (slen == 6 &&
21718 @@ -161,13 +161,13 @@
21719 0 == strncmp(ts, "seconds", slen)) {
21722 - log_error_write(srv, __FILE__, __LINE__, "ss",
21723 + log_error_write(srv, __FILE__, __LINE__, "ss",
21724 "unknown type:", ts);
21734 if (0 == strcmp(ts, "years")) {
21735 @@ -183,19 +183,19 @@
21736 } else if (0 == strcmp(ts, "seconds")) {
21739 - log_error_write(srv, __FILE__, __LINE__, "ss",
21740 + log_error_write(srv, __FILE__, __LINE__, "ss",
21741 "unknown type:", ts);
21754 if (offset != NULL) *offset = retts;
21760 @@ -205,102 +205,99 @@
21761 SETDEFAULTS_FUNC(mod_expire_set_defaults) {
21762 plugin_data *p = p_d;
21765 - config_values_t cv[] = {
21767 + config_values_t cv[] = {
21768 { "expire.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
21769 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21773 if (!p) return HANDLER_ERROR;
21776 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21779 for (i = 0; i < srv->config_context->used; i++) {
21783 s = calloc(1, sizeof(plugin_config));
21784 s->expire_url = array_init();
21787 cv[0].destination = s->expire_url;
21790 p->config_storage[i] = s;
21793 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21794 return HANDLER_ERROR;
21798 for (k = 0; k < s->expire_url->used; k++) {
21799 data_string *ds = (data_string *)s->expire_url->data[k];
21803 if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
21804 - log_error_write(srv, __FILE__, __LINE__, "sb",
21805 + log_error_write(srv, __FILE__, __LINE__, "sb",
21806 "parsing expire.url failed:", ds->value);
21807 return HANDLER_ERROR;
21815 return HANDLER_GO_ON;
21818 -#define PATCH(x) \
21819 - p->conf.x = s->x;
21820 static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
21822 plugin_config *s = p->config_storage[0];
21824 - PATCH(expire_url);
21827 + PATCH_OPTION(expire_url);
21829 /* skip the first, the global context */
21830 for (i = 1; i < srv->config_context->used; i++) {
21831 data_config *dc = (data_config *)srv->config_context->data[i];
21832 s = p->config_storage[i];
21835 /* condition didn't match */
21836 if (!config_check_cond(srv, con, dc)) continue;
21840 for (j = 0; j < dc->value->used; j++) {
21841 data_unset *du = dc->value->data[j];
21844 if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
21845 - PATCH(expire_url);
21846 + PATCH_OPTION(expire_url);
21856 URIHANDLER_FUNC(mod_expire_path_handler) {
21857 plugin_data *p = p_d;
21862 if (con->uri.path->used == 0) return HANDLER_GO_ON;
21865 mod_expire_patch_connection(srv, con, p);
21868 s_len = con->uri.path->used - 1;
21871 for (k = 0; k < p->conf.expire_url->used; k++) {
21872 data_string *ds = (data_string *)p->conf.expire_url->data[k];
21873 int ct_len = ds->key->used - 1;
21876 if (ct_len > s_len) continue;
21877 if (ds->key->used == 0) continue;
21880 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
21884 stat_cache_entry *sce = NULL;
21887 stat_cache_get_entry(srv, con, con->physical.path, &sce);
21890 switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
21893 @@ -308,38 +305,38 @@
21899 t = (ts + sce->st.st_mtime);
21902 /* -1 is handled at parse-time */
21907 - if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21910 + if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21911 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
21912 /* could not set expire header, out of mem */
21915 return HANDLER_GO_ON;
21921 p->expire_tstmp->used = len + 1;
21926 response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
21930 buffer_copy_string(p->expire_tstmp, "max-age=");
21931 buffer_append_long(p->expire_tstmp, ts);
21934 response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
21937 return HANDLER_GO_ON;
21943 return HANDLER_GO_ON;
21945 @@ -349,13 +346,13 @@
21946 int mod_expire_plugin_init(plugin *p) {
21947 p->version = LIGHTTPD_VERSION_ID;
21948 p->name = buffer_init_string("expire");
21951 p->init = mod_expire_init;
21952 p->handle_subrequest_start = mod_expire_path_handler;
21953 p->set_defaults = mod_expire_set_defaults;
21954 p->cleanup = mod_expire_free;
21962 --- ../lighttpd-1.4.11/src/mod_fastcgi.c 2006-03-09 13:18:39.000000000 +0200
21963 +++ lighttpd-1.4.12/src/mod_fastcgi.c 2006-07-19 20:02:55.000000000 +0300
21965 #include <sys/types.h>
21966 -#include <unistd.h>
21969 #include <string.h>
21970 @@ -18,13 +17,14 @@
21971 #include "connections.h"
21972 #include "response.h"
21973 #include "joblist.h"
21974 +#include "status_counter.h"
21976 #include "plugin.h"
21978 #include "inet_ntop_cache.h"
21979 #include "stat_cache.h"
21981 -#include <fastcgi.h>
21982 +#include "fastcgi.h"
21985 #ifdef HAVE_SYS_FILIO_H
21989 #include "sys-socket.h"
21990 +#include "sys-files.h"
21991 +#include "sys-strings.h"
21992 +#include "sys-process.h"
21994 +#include "http_resp.h"
21996 #ifndef UNIX_PATH_MAX
21997 # define UNIX_PATH_MAX 108
21998 @@ -45,14 +49,13 @@
21999 #include <sys/wait.h>
22009 * - add timeout for a connect to a non-fastcgi process
22010 * (use state_timestamp + state)
22015 typedef struct fcgi_proc {
22017 unsigned port; /* config.port + pno */
22019 buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
22022 pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
22025 @@ -70,20 +73,20 @@
22026 time_t last_used; /* see idle_timeout */
22027 size_t requests; /* see max_requests */
22028 struct fcgi_proc *prev, *next; /* see first */
22031 time_t disabled_until; /* this proc is disabled until, use something else until than */
22038 PROC_STATE_UNSET, /* init-phase */
22039 PROC_STATE_RUNNING, /* alive */
22040 - PROC_STATE_OVERLOADED, /* listen-queue is full,
22041 + PROC_STATE_OVERLOADED, /* listen-queue is full,
22042 don't send something to this proc for the next 2 seconds */
22043 PROC_STATE_DIED_WAIT_FOR_PID, /* */
22044 PROC_STATE_DIED, /* marked as dead, should be restarted */
22045 PROC_STATE_KILLED /* was killed as we don't have the load anymore */
22051 @@ -94,20 +97,20 @@
22052 * sorted by lowest load
22054 * whenever a job is done move it up in the list
22055 - * until it is sorted, move it down as soon as the
22056 + * until it is sorted, move it down as soon as the
22059 - fcgi_proc *first;
22060 - fcgi_proc *unused_procs;
22061 + fcgi_proc *first;
22062 + fcgi_proc *unused_procs;
22066 * spawn at least min_procs, at max_procs.
22068 - * as soon as the load of the first entry
22069 + * as soon as the load of the first entry
22070 * is max_load_per_proc we spawn a new one
22071 - * and add it to the first entry and give it
22072 + * and add it to the first entry and give it
22078 unsigned short min_procs;
22079 @@ -119,44 +122,44 @@
22082 * kick the process from the list if it was not
22083 - * used for idle_timeout until min_procs is
22084 + * used for idle_timeout until min_procs is
22085 * reached. this helps to get the processlist
22086 * small again we had a small peak load.
22091 unsigned short idle_timeout;
22095 * time after a disabled remote connection is tried to be re-enabled
22103 unsigned short disable_time;
22106 * same fastcgi processes get a little bit larger
22107 - * than wanted. max_requests_per_proc kills a
22108 + * than wanted. max_requests_per_proc kills a
22109 * process after a number of handled requests.
22112 size_t max_requests_per_proc;
22123 - * if host is one of the local IP adresses the
22124 + * if host is one of the local IP adresses the
22125 * whole connection is local
22127 * if tcp/ip should be used host AND port have
22128 - * to be specified
22132 + * to be specified
22136 unsigned short port;
22139 @@ -169,7 +172,7 @@
22141 buffer *unixsocket;
22143 - /* if socket is local we can start the fastcgi
22144 + /* if socket is local we can start the fastcgi
22147 * bin-path is the path to the binary
22148 @@ -177,19 +180,19 @@
22149 * check min_procs and max_procs for the number
22150 * of process to start-up
22152 - buffer *bin_path;
22154 - /* bin-path is set bin-environment is taken to
22155 + buffer *bin_path;
22157 + /* bin-path is set bin-environment is taken to
22158 * create the environement before starting the
22166 array *bin_env_copy;
22170 - * docroot-translation between URL->phys and the
22171 + * docroot-translation between URL->phys and the
22175 @@ -208,7 +211,7 @@
22176 unsigned short mode;
22179 - * check_local tell you if the phys file is stat()ed
22180 + * check_local tell you if the phys file is stat()ed
22181 * or not. FastCGI doesn't care if the service is
22182 * remote. If the web-server side doesn't contain
22183 * the fastcgi-files we should not stat() for them
22184 @@ -218,11 +221,11 @@
22187 * append PATH_INFO to SCRIPT_FILENAME
22190 * php needs this if cgi.fix_pathinfo is provied
22196 unsigned short break_scriptfilename_for_php;
22199 @@ -231,12 +234,12 @@
22202 unsigned short allow_xsendfile;
22205 ssize_t load; /* replace by host->load */
22207 size_t max_id; /* corresponds most of the time to
22211 only if a process is killed max_id waits for the process itself
22212 to die and decrements its afterwards */
22214 @@ -245,17 +248,17 @@
22217 * one extension can have multiple hosts assigned
22218 - * one host can spawn additional processes on the same
22219 + * one host can spawn additional processes on the same
22220 * socket (if we control it)
22222 * ext -> host -> procs
22225 - * if the fastcgi process is remote that whole goes down
22226 + * if the fastcgi process is remote that whole goes down
22229 * ext -> host -> procs
22233 * in case of PHP and FCGI_CHILDREN we have again a procs
22234 * but we don't control it directly.
22235 @@ -268,7 +271,7 @@
22238 fcgi_extension_host **hosts;
22244 @@ -282,10 +285,10 @@
22251 array *ext_mapping;
22257 @@ -297,7 +300,7 @@
22266 @@ -306,55 +309,54 @@
22269 buffer_uint fcgi_request_id;
22276 - buffer *parse_response;
22283 plugin_config **config_storage;
22286 plugin_config conf; /* this is only used as long as no handler_ctx is setup */
22289 /* connection specific data */
22294 - FCGI_STATE_CONNECT_DELAYED,
22295 - FCGI_STATE_PREPARE_WRITE,
22296 - FCGI_STATE_WRITE,
22299 + FCGI_STATE_CONNECT_DELAYED,
22300 + FCGI_STATE_PREPARE_WRITE,
22301 + FCGI_STATE_WRITE,
22303 } fcgi_connection_state_t;
22307 fcgi_extension_host *host;
22308 fcgi_extension *ext;
22311 fcgi_connection_state_t state;
22312 time_t state_timestamp;
22315 int reconnects; /* number of reconnect attempts */
22317 - chunkqueue *rb; /* read queue */
22319 + chunkqueue *rb; /* the raw fcgi read-queue */
22320 + chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
22321 chunkqueue *wb; /* write queue */
22323 - buffer *response_header;
22327 - int fd; /* fd to the fastcgi process */
22328 - int fde_ndx; /* index into the fd-event buffer */
22334 int send_content_body;
22337 plugin_config conf;
22340 connection *remote_conn; /* dumb pointer */
22341 plugin_data *plugin_data; /* dumb pointer */
22343 @@ -363,49 +365,6 @@
22344 /* ok, we need a prototype */
22345 static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
22347 -data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
22348 - data_integer *di;
22350 - if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
22351 - /* not found, create it */
22353 - if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
22354 - di = data_integer_init();
22356 - buffer_copy_string_len(di->key, s, len);
22359 - array_insert_unique(srv->status, (data_unset *)di);
22364 -/* dummies of the statistic framework functions
22365 - * they will be moved to a statistics.c later */
22366 -int status_counter_inc(server *srv, const char *s, size_t len) {
22367 - data_integer *di = status_counter_get_counter(srv, s, len);
22374 -int status_counter_dec(server *srv, const char *s, size_t len) {
22375 - data_integer *di = status_counter_get_counter(srv, s, len);
22377 - if (di->value > 0) di->value--;
22382 -int status_counter_set(server *srv, const char *s, size_t len, int val) {
22383 - data_integer *di = status_counter_get_counter(srv, s, len);
22390 int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
22391 buffer_copy_string(b, "fastcgi.backend.");
22392 buffer_append_string_buffer(b, host->id);
22393 @@ -421,7 +380,7 @@
22395 fastcgi_status_copy_procname(b, host, proc); \
22396 buffer_append_string(b, x); \
22397 - status_counter_set(srv, CONST_BUF_LEN(b), 0);
22398 + status_counter_set(CONST_BUF_LEN(b), 0);
22400 CLEAN(".disabled");
22402 @@ -429,42 +388,39 @@
22403 CLEAN(".connected");
22410 fastcgi_status_copy_procname(b, host, NULL); \
22411 buffer_append_string(b, x); \
22412 - status_counter_set(srv, CONST_BUF_LEN(b), 0);
22413 + status_counter_set(CONST_BUF_LEN(b), 0);
22423 static handler_ctx * handler_ctx_init() {
22424 handler_ctx * hctx;
22427 hctx = calloc(1, sizeof(*hctx));
22430 - hctx->fde_ndx = -1;
22432 - hctx->response_header = buffer_init();
22435 hctx->request_id = 0;
22436 hctx->state = FCGI_STATE_INIT;
22442 + hctx->sock = iosocket_init();
22444 hctx->reconnects = 0;
22445 hctx->send_content_body = 1;
22447 hctx->rb = chunkqueue_init();
22448 + hctx->http_rb = chunkqueue_init();
22449 hctx->wb = chunkqueue_init();
22455 @@ -473,12 +429,13 @@
22456 hctx->host->load--;
22460 - buffer_free(hctx->response_header);
22462 chunkqueue_free(hctx->rb);
22463 + chunkqueue_free(hctx->http_rb);
22464 chunkqueue_free(hctx->wb);
22466 + iosocket_free(hctx->sock);
22471 @@ -488,21 +445,21 @@
22472 f = calloc(1, sizeof(*f));
22473 f->unixsocket = buffer_init();
22474 f->connection_name = buffer_init();
22484 void fastcgi_process_free(fcgi_proc *f) {
22488 fastcgi_process_free(f->next);
22491 buffer_free(f->unixsocket);
22492 buffer_free(f->connection_name);
22498 @@ -519,13 +476,13 @@
22499 f->bin_env = array_init();
22500 f->bin_env_copy = array_init();
22501 f->strip_request_uri = buffer_init();
22507 void fastcgi_host_free(fcgi_extension_host *h) {
22511 buffer_free(h->id);
22512 buffer_free(h->host);
22513 buffer_free(h->unixsocket);
22514 @@ -534,49 +491,49 @@
22515 buffer_free(h->strip_request_uri);
22516 array_free(h->bin_env);
22517 array_free(h->bin_env_copy);
22520 fastcgi_process_free(h->first);
22521 fastcgi_process_free(h->unused_procs);
22529 fcgi_exts *fastcgi_extensions_init() {
22532 f = calloc(1, sizeof(*f));
22538 void fastcgi_extensions_free(fcgi_exts *f) {
22545 for (i = 0; i < f->used; i++) {
22546 fcgi_extension *fe;
22553 for (j = 0; j < fe->used; j++) {
22554 fcgi_extension_host *h;
22560 fastcgi_host_free(h);
22564 buffer_free(fe->key);
22578 @@ -625,24 +582,25 @@
22582 - fe->hosts[fe->used++] = fh;
22583 + fe->hosts[fe->used++] = fh;
22590 INIT_FUNC(mod_fastcgi_init) {
22594 p = calloc(1, sizeof(*p));
22597 p->fcgi_env = buffer_init();
22600 p->path = buffer_init();
22601 - p->parse_response = buffer_init();
22603 + p->resp = http_response_init();
22605 p->statuskey = buffer_init();
22611 @@ -650,81 +608,82 @@
22612 FREE_FUNC(mod_fastcgi_free) {
22613 plugin_data *p = p_d;
22614 buffer_uint *r = &(p->fcgi_request_id);
22619 if (r->ptr) free(r->ptr);
22622 buffer_free(p->fcgi_env);
22623 buffer_free(p->path);
22624 - buffer_free(p->parse_response);
22625 buffer_free(p->statuskey);
22628 + http_response_free(p->resp);
22630 if (p->config_storage) {
22632 for (i = 0; i < srv->config_context->used; i++) {
22633 plugin_config *s = p->config_storage[i];
22642 for (j = 0; j < exts->used; j++) {
22643 fcgi_extension *ex;
22646 ex = exts->exts[j];
22649 for (n = 0; n < ex->used; n++) {
22651 fcgi_extension_host *host;
22654 host = ex->hosts[n];
22657 for (proc = host->first; proc; proc = proc->next) {
22658 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22660 - if (proc->is_local &&
22662 + if (proc->is_local &&
22663 !buffer_is_empty(proc->unixsocket)) {
22664 unlink(proc->unixsocket->ptr);
22669 for (proc = host->unused_procs; proc; proc = proc->next) {
22670 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22672 - if (proc->is_local &&
22674 + if (proc->is_local &&
22675 !buffer_is_empty(proc->unixsocket)) {
22676 unlink(proc->unixsocket->ptr);
22683 fastcgi_extensions_free(s->exts);
22684 array_free(s->ext_mapping);
22689 free(p->config_storage);
22696 return HANDLER_GO_ON;
22699 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
22703 if (!key || !val) return -1;
22706 dst = malloc(key_len + val_len + 3);
22707 memcpy(dst, key, key_len);
22708 dst[key_len] = '=';
22709 /* add the \0 from the value */
22710 memcpy(dst + key_len + 1, val, val_len + 1);
22713 if (env->size == 0) {
22715 env->ptr = malloc(env->size * sizeof(*env->ptr));
22716 @@ -732,9 +691,9 @@
22718 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22722 env->ptr[env->used++] = dst;
22728 @@ -753,15 +712,15 @@
22729 if (env->size == 0) {
22731 env->ptr = malloc(env->size * sizeof(*env->ptr));
22732 - } else if (env->size == env->used) {
22733 + } else if (env->size == env->used) {
22735 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22741 env->ptr[env->used++] = start;
22744 start = b->ptr + i + 1;
22747 @@ -794,7 +753,7 @@
22751 -static int fcgi_spawn_connection(server *srv,
22752 +static int fcgi_spawn_connection(server *srv,
22754 fcgi_extension_host *host,
22756 @@ -806,31 +765,27 @@
22758 struct sockaddr_in fcgi_addr_in;
22759 struct sockaddr *fcgi_addr;
22770 if (p->conf.debug) {
22771 log_error_write(srv, __FILE__, __LINE__, "sdb",
22772 "new proc, socket:", proc->port, proc->unixsocket);
22776 if (!buffer_is_empty(proc->unixsocket)) {
22777 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
22780 #ifdef HAVE_SYS_UN_H
22781 fcgi_addr_un.sun_family = AF_UNIX;
22782 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
22786 servlen = SUN_LEN(&fcgi_addr_un);
22788 - /* stevens says: */
22789 - servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
22792 socket_type = AF_UNIX;
22793 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
22795 @@ -844,108 +799,108 @@
22798 fcgi_addr_in.sin_family = AF_INET;
22801 if (buffer_is_empty(host->host)) {
22802 fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22804 struct hostent *he;
22807 /* set a usefull default */
22808 fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22813 if (NULL == (he = gethostbyname(host->host->ptr))) {
22814 - log_error_write(srv, __FILE__, __LINE__,
22815 - "sdb", "gethostbyname failed: ",
22816 + log_error_write(srv, __FILE__, __LINE__,
22817 + "sdb", "gethostbyname failed: ",
22818 h_errno, host->host);
22823 if (he->h_addrtype != AF_INET) {
22824 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
22829 if (he->h_length != sizeof(struct in_addr)) {
22830 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
22835 memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
22839 fcgi_addr_in.sin_port = htons(proc->port);
22840 servlen = sizeof(fcgi_addr_in);
22843 socket_type = AF_INET;
22844 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
22847 buffer_copy_string(proc->connection_name, "tcp:");
22848 buffer_append_string_buffer(proc->connection_name, host->host);
22849 buffer_append_string(proc->connection_name, ":");
22850 buffer_append_long(proc->connection_name, proc->port);
22854 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22855 - log_error_write(srv, __FILE__, __LINE__, "ss",
22856 + log_error_write(srv, __FILE__, __LINE__, "ss",
22857 "failed:", strerror(errno));
22862 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
22863 /* server is not up, spawn in */
22867 - if (errno != ENOENT &&
22869 + if (errno != ENOENT &&
22870 !buffer_is_empty(proc->unixsocket)) {
22871 unlink(proc->unixsocket->ptr);
22878 /* reopen socket */
22879 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22880 - log_error_write(srv, __FILE__, __LINE__, "ss",
22881 + log_error_write(srv, __FILE__, __LINE__, "ss",
22882 "socket failed:", strerror(errno));
22888 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
22889 - log_error_write(srv, __FILE__, __LINE__, "ss",
22890 + log_error_write(srv, __FILE__, __LINE__, "ss",
22891 "socketsockopt failed:", strerror(errno));
22896 /* create socket */
22897 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
22898 - log_error_write(srv, __FILE__, __LINE__, "sbs",
22899 - "bind failed for:",
22900 + log_error_write(srv, __FILE__, __LINE__, "sbs",
22901 + "bind failed for:",
22902 proc->connection_name,
22908 if (-1 == listen(fcgi_fd, 1024)) {
22909 - log_error_write(srv, __FILE__, __LINE__, "ss",
22910 + log_error_write(srv, __FILE__, __LINE__, "ss",
22911 "listen failed:", strerror(errno));
22918 switch ((child = fork())) {
22926 /* create environment */
22935 @@ -955,18 +910,18 @@
22936 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
22941 /* we don't need the client socket */
22942 for (i = 3; i < 256; i++) {
22947 /* build clean environment */
22948 if (host->bin_env_copy->used) {
22949 for (i = 0; i < host->bin_env_copy->used; i++) {
22950 data_string *ds = (data_string *)host->bin_env_copy->data[i];
22954 if (NULL != (ge = getenv(ds->value->ptr))) {
22955 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
22957 @@ -974,39 +929,39 @@
22959 for (i = 0; environ[i]; i++) {
22963 if (NULL != (eq = strchr(environ[i], '='))) {
22964 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
22970 /* create environment */
22971 for (i = 0; i < host->bin_env->used; i++) {
22972 data_string *ds = (data_string *)host->bin_env->data[i];
22975 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
22979 for (i = 0; i < env.used; i++) {
22980 /* search for PHP_FCGI_CHILDREN */
22981 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
22985 /* not found, add a default */
22986 if (i == env.used) {
22987 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
22991 env.ptr[env.used] = NULL;
22993 parse_binpath(&arg, host->bin_path);
22996 /* chdir into the base of the bin-path,
22997 * search for the last / */
22998 if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
23002 /* change to the physical directory */
23003 if (-1 == chdir(arg.ptr[0])) {
23005 @@ -1018,12 +973,12 @@
23008 execve(arg.ptr[0], arg.ptr, env.ptr);
23010 - log_error_write(srv, __FILE__, __LINE__, "sbs",
23012 + log_error_write(srv, __FILE__, __LINE__, "sbs",
23013 "execve failed for:", host->bin_path, strerror(errno));
23022 @@ -1031,17 +986,17 @@
23029 select(0, NULL, NULL, NULL, &tv);
23032 switch (waitpid(child, &status, WNOHANG)) {
23034 /* child still running after timeout, good */
23037 /* no PID found ? should never happen */
23038 - log_error_write(srv, __FILE__, __LINE__, "ss",
23039 + log_error_write(srv, __FILE__, __LINE__, "ss",
23040 "pid not found:", strerror(errno));
23043 @@ -1049,10 +1004,10 @@
23044 "the fastcgi-backend", host->bin_path, "failed to start:");
23045 /* the child should not terminate at all */
23046 if (WIFEXITED(status)) {
23047 - log_error_write(srv, __FILE__, __LINE__, "sdb",
23048 - "child exited with status",
23049 + log_error_write(srv, __FILE__, __LINE__, "sdb",
23050 + "child exited with status",
23051 WEXITSTATUS(status), host->bin_path);
23052 - log_error_write(srv, __FILE__, __LINE__, "s",
23053 + log_error_write(srv, __FILE__, __LINE__, "s",
23054 "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
23055 "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
23056 "in the output, NOT (cgi) NOR (cli)\n"
23057 @@ -1060,8 +1015,8 @@
23058 log_error_write(srv, __FILE__, __LINE__, "s",
23059 "If this is PHP on Gentoo add fastcgi to the USE flags");
23060 } else if (WIFSIGNALED(status)) {
23061 - log_error_write(srv, __FILE__, __LINE__, "sd",
23062 - "terminated by signal:",
23063 + log_error_write(srv, __FILE__, __LINE__, "sd",
23064 + "terminated by signal:",
23067 if (WTERMSIG(status) == 11) {
23068 @@ -1071,8 +1026,8 @@
23069 "If this is PHP try to remove the byte-code caches for now and try again.");
23072 - log_error_write(srv, __FILE__, __LINE__, "sd",
23073 - "child died somehow:",
23074 + log_error_write(srv, __FILE__, __LINE__, "sd",
23075 + "child died somehow:",
23079 @@ -1082,26 +1037,26 @@
23081 proc->last_used = srv->cur_ts;
23082 proc->is_local = 1;
23089 proc->is_local = 0;
23093 if (p->conf.debug) {
23094 log_error_write(srv, __FILE__, __LINE__, "sb",
23095 "(debug) socket is already used, won't spawn:",
23096 proc->connection_name);
23101 proc->state = PROC_STATE_RUNNING;
23102 host->active_procs++;
23111 @@ -1111,93 +1066,93 @@
23114 buffer *fcgi_mode = buffer_init();
23116 - config_values_t cv[] = {
23118 + config_values_t cv[] = {
23119 { "fastcgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
23120 { "fastcgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
23121 { "fastcgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
23122 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23126 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23129 for (i = 0; i < srv->config_context->used; i++) {
23134 s = malloc(sizeof(plugin_config));
23135 s->exts = fastcgi_extensions_init();
23137 s->ext_mapping = array_init();
23140 cv[0].destination = s->exts;
23141 cv[1].destination = &(s->debug);
23142 cv[2].destination = s->ext_mapping;
23145 p->config_storage[i] = s;
23146 ca = ((data_config *)srv->config_context->data[i])->value;
23149 if (0 != config_insert_values_global(srv, ca, cv)) {
23150 return HANDLER_ERROR;
23160 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
23162 data_array *da = (data_array *)du;
23165 if (du->type != TYPE_ARRAY) {
23166 - log_error_write(srv, __FILE__, __LINE__, "sss",
23167 + log_error_write(srv, __FILE__, __LINE__, "sss",
23168 "unexpected type for key: ", "fastcgi.server", "array of strings");
23171 return HANDLER_ERROR;
23176 - * fastcgi.server = ( "<ext>" => ( ... ),
23180 + * fastcgi.server = ( "<ext>" => ( ... ),
23181 * "<ext>" => ( ... ) )
23185 for (j = 0; j < da->value->used; j++) {
23187 data_array *da_ext = (data_array *)da->value->data[j];
23190 if (da->value->data[j]->type != TYPE_ARRAY) {
23191 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
23192 - "unexpected type for key: ", "fastcgi.server",
23193 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
23194 + "unexpected type for key: ", "fastcgi.server",
23195 "[", da->value->data[j]->key, "](string)");
23198 return HANDLER_ERROR;
23202 - * da_ext->key == name of the extension
23205 + * da_ext->key == name of the extension
23209 - * fastcgi.server = ( "<ext>" =>
23210 - * ( "<host>" => ( ... ),
23213 + * fastcgi.server = ( "<ext>" =>
23214 + * ( "<host>" => ( ... ),
23215 * "<host>" => ( ... )
23222 for (n = 0; n < da_ext->value->used; n++) {
23223 data_array *da_host = (data_array *)da_ext->value->data[n];
23226 fcgi_extension_host *host;
23228 - config_values_t fcv[] = {
23230 + config_values_t fcv[] = {
23231 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
23232 { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
23233 { "mode", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
23234 { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
23235 { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
23238 { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
23239 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
23240 { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
23241 @@ -1205,28 +1160,28 @@
23242 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
23243 { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
23244 { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
23247 { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
23248 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
23251 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
23252 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
23253 { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
23256 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23260 if (da_host->type != TYPE_ARRAY) {
23261 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23262 - "unexpected type for key:",
23263 - "fastcgi.server",
23264 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23265 + "unexpected type for key:",
23266 + "fastcgi.server",
23267 "[", da_host->key, "](string)");
23270 return HANDLER_ERROR;
23274 host = fastcgi_host_init();
23277 buffer_copy_string_buffer(host->id, da_host->key);
23279 host->check_local = 1;
23280 @@ -1238,13 +1193,13 @@
23281 host->disable_time = 60;
23282 host->break_scriptfilename_for_php = 0;
23283 host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
23286 fcv[0].destination = host->host;
23287 fcv[1].destination = host->docroot;
23288 fcv[2].destination = fcgi_mode;
23289 fcv[3].destination = host->unixsocket;
23290 fcv[4].destination = host->bin_path;
23293 fcv[5].destination = &(host->check_local);
23294 fcv[6].destination = &(host->port);
23295 fcv[7].destination = &(host->min_procs);
23296 @@ -1252,35 +1207,35 @@
23297 fcv[9].destination = &(host->max_load_per_proc);
23298 fcv[10].destination = &(host->idle_timeout);
23299 fcv[11].destination = &(host->disable_time);
23302 fcv[12].destination = host->bin_env;
23303 fcv[13].destination = host->bin_env_copy;
23304 fcv[14].destination = &(host->break_scriptfilename_for_php);
23305 fcv[15].destination = &(host->allow_xsendfile);
23306 fcv[16].destination = host->strip_request_uri;
23309 if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
23310 return HANDLER_ERROR;
23313 - if ((!buffer_is_empty(host->host) || host->port) &&
23315 + if ((!buffer_is_empty(host->host) || host->port) &&
23316 !buffer_is_empty(host->unixsocket)) {
23317 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23318 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23319 "either host/port or socket have to be set in:",
23322 da_ext->key, " => (",
23323 da_host->key, " ( ...");
23325 return HANDLER_ERROR;
23329 if (!buffer_is_empty(host->unixsocket)) {
23330 /* unix domain socket */
23333 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
23334 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23335 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23336 "unixsocket is too long in:",
23339 da_ext->key, " => (",
23340 da_host->key, " ( ...");
23342 @@ -1288,37 +1243,37 @@
23347 - if (buffer_is_empty(host->host) &&
23349 + if (buffer_is_empty(host->host) &&
23350 buffer_is_empty(host->bin_path)) {
23351 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23352 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23353 "host or binpath have to be set in:",
23356 da_ext->key, " => (",
23357 da_host->key, " ( ...");
23360 return HANDLER_ERROR;
23361 } else if (host->port == 0) {
23362 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23363 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23364 "port has to be set in:",
23367 da_ext->key, " => (",
23368 da_host->key, " ( ...");
23370 return HANDLER_ERROR;
23374 - if (!buffer_is_empty(host->bin_path)) {
23376 + if (!buffer_is_empty(host->bin_path)) {
23377 /* a local socket + self spawning */
23380 /* HACK: just to make sure the adaptive spawing is disabled */
23381 host->min_procs = host->max_procs;
23384 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
23385 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
23389 log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
23390 "--- fastcgi spawning local",
23391 @@ -1328,7 +1283,7 @@
23392 "\n\tmin-procs:", host->min_procs,
23393 "\n\tmax-procs:", host->max_procs);
23397 for (pno = 0; pno < host->min_procs; pno++) {
23400 @@ -1343,7 +1298,7 @@
23401 buffer_append_string(proc->unixsocket, "-");
23402 buffer_append_long(proc->unixsocket, pno);
23407 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
23408 "--- fastcgi spawning",
23409 @@ -1351,7 +1306,7 @@
23410 "\n\tsocket", host->unixsocket,
23411 "\n\tcurrent:", pno, "/", host->min_procs);
23415 if (fcgi_spawn_connection(srv, p, host, proc)) {
23416 log_error_write(srv, __FILE__, __LINE__, "s",
23417 "[ERROR]: spawning fcgi failed.");
23418 @@ -1359,35 +1314,35 @@
23421 fastcgi_status_init(srv, p->statuskey, host, proc);
23424 proc->next = host->first;
23425 if (host->first) host->first->prev = proc;
23428 host->first = proc;
23434 proc = fastcgi_process_init();
23435 proc->id = host->num_procs++;
23437 host->active_procs++;
23438 proc->state = PROC_STATE_RUNNING;
23441 if (buffer_is_empty(host->unixsocket)) {
23442 proc->port = host->port;
23444 buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
23448 fastcgi_status_init(srv, p->statuskey, host, proc);
23450 host->first = proc;
23453 host->min_procs = 1;
23454 host->max_procs = 1;
23458 if (!buffer_is_empty(fcgi_mode)) {
23459 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
23460 host->mode = FCGI_RESPONDER;
23461 @@ -1411,16 +1366,16 @@
23467 buffer_free(fcgi_mode);
23470 return HANDLER_GO_ON;
23473 static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
23474 hctx->state = state;
23475 hctx->state_timestamp = srv->cur_ts;
23481 @@ -1429,13 +1384,13 @@
23484 buffer_uint *r = &(p->fcgi_request_id);
23489 for (i = 0; i < r->used; i++) {
23490 if (r->ptr[i] > m) m = r->ptr[i];
23494 if (r->size == 0) {
23496 r->ptr = malloc(sizeof(*r->ptr) * r->size);
23497 @@ -1443,54 +1398,55 @@
23499 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
23503 r->ptr[r->used++] = ++m;
23509 static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
23511 buffer_uint *r = &(p->fcgi_request_id);
23516 for (i = 0; i < r->used; i++) {
23517 if (r->ptr[i] == request_id) break;
23521 if (i != r->used) {
23525 if (i != r->used - 1) {
23526 r->ptr[i] = r->ptr[r->used - 1];
23534 void fcgi_connection_close(server *srv, handler_ctx *hctx) {
23539 if (NULL == hctx) return;
23542 p = hctx->plugin_data;
23543 con = hctx->remote_conn;
23546 if (con->mode != p->id) {
23551 - if (hctx->fd != -1) {
23552 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23553 - fdevent_unregister(srv->ev, hctx->fd);
23556 + if (hctx->sock->fd != -1) {
23557 + fdevent_event_del(srv->ev, hctx->sock);
23558 + fdevent_unregister(srv->ev, hctx->sock);
23559 + closesocket(hctx->sock->fd);
23560 + hctx->sock->fd = -1;
23566 if (hctx->request_id != 0) {
23567 fcgi_requestid_del(srv, p, hctx->request_id);
23569 @@ -1499,111 +1455,111 @@
23570 if (hctx->got_proc) {
23571 /* after the connect the process gets a load */
23572 hctx->proc->load--;
23574 - status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
23576 + status_counter_dec(CONST_STR_LEN("fastcgi.active-requests"));
23578 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
23579 buffer_append_string(p->statuskey, ".load");
23581 - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
23582 + status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
23584 if (p->conf.debug) {
23585 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
23586 - "released proc:",
23587 - "pid:", hctx->proc->pid,
23588 - "socket:", hctx->proc->connection_name,
23589 + "released proc:",
23590 + "pid:", hctx->proc->pid,
23591 + "socket:", hctx->proc->connection_name,
23592 "load:", hctx->proc->load);
23599 handler_ctx_free(hctx);
23600 - con->plugin_ctx[p->id] = NULL;
23601 + con->plugin_ctx[p->id] = NULL;
23604 static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
23605 plugin_data *p = hctx->plugin_data;
23616 * connect was ok, connection was accepted
23617 * but the php accept loop checks after the accept if it should die or not.
23619 - * if yes we can only detect it at a write()
23622 + * if yes we can only detect it at a write()
23624 * next step is resetting this attemp and setup a connection again
23627 * if we have more then 5 reconnects for the same request, die
23634 * we have a connection but the child died by some other reason
23639 - if (hctx->fd != -1) {
23640 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23641 - fdevent_unregister(srv->ev, hctx->fd);
23643 + if (hctx->sock->fd != -1) {
23644 + fdevent_event_del(srv->ev, hctx->sock);
23645 + fdevent_unregister(srv->ev, hctx->sock);
23646 + close(hctx->sock->fd);
23649 + hctx->sock->fd = -1;
23653 fcgi_requestid_del(srv, p, hctx->request_id);
23656 fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
23659 hctx->request_id = 0;
23660 hctx->reconnects++;
23663 if (p->conf.debug > 2) {
23665 log_error_write(srv, __FILE__, __LINE__, "sdb",
23666 - "release proc for reconnect:",
23667 + "release proc for reconnect:",
23668 hctx->proc->pid, hctx->proc->connection_name);
23670 log_error_write(srv, __FILE__, __LINE__, "sb",
23671 - "release proc for reconnect:",
23672 + "release proc for reconnect:",
23673 hctx->host->unixsocket);
23677 - if (hctx->proc && hctx->got_proc) {
23678 + if (hctx->proc && hctx->got_proc) {
23679 hctx->proc->load--;
23682 /* perhaps another host gives us more luck */
23683 hctx->host->load--;
23691 static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
23692 plugin_data *p = p_d;
23695 fcgi_connection_close(srv, con->plugin_ctx[p->id]);
23698 return HANDLER_GO_ON;
23702 static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
23706 if (!key || !val) return -1;
23709 len = key_len + val_len;
23712 len += key_len > 127 ? 4 : 1;
23713 len += val_len > 127 ? 4 : 1;
23716 buffer_prepare_append(env, len);
23719 if (key_len > 127) {
23720 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
23721 env->ptr[env->used++] = (key_len >> 16) & 0xff;
23722 @@ -1612,7 +1568,7 @@
23724 env->ptr[env->used++] = (key_len >> 0) & 0xff;
23728 if (val_len > 127) {
23729 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
23730 env->ptr[env->used++] = (val_len >> 16) & 0xff;
23731 @@ -1621,12 +1577,12 @@
23733 env->ptr[env->used++] = (val_len >> 0) & 0xff;
23737 memcpy(env->ptr + env->used, key, key_len);
23738 env->used += key_len;
23739 memcpy(env->ptr + env->used, val, val_len);
23740 env->used += val_len;
23746 @@ -1639,11 +1595,11 @@
23747 header->contentLengthB1 = (contentLength >> 8) & 0xff;
23748 header->paddingLength = paddingLength;
23749 header->reserved = 0;
23760 @@ -1665,26 +1621,23 @@
23761 struct sockaddr_un fcgi_addr_un;
23766 fcgi_extension_host *host = hctx->host;
23767 fcgi_proc *proc = hctx->proc;
23768 - int fcgi_fd = hctx->fd;
23770 + int fcgi_fd = hctx->sock->fd;
23772 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
23775 if (!buffer_is_empty(proc->unixsocket)) {
23776 #ifdef HAVE_SYS_UN_H
23777 /* use the unix domain socket */
23778 fcgi_addr_un.sun_family = AF_UNIX;
23779 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
23782 servlen = SUN_LEN(&fcgi_addr_un);
23784 - /* stevens says: */
23785 - servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
23788 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
23791 if (buffer_is_empty(proc->connection_name)) {
23792 /* on remote spawing we have to set the connection-name now */
23793 buffer_copy_string(proc->connection_name, "unix:");
23794 @@ -1695,16 +1648,18 @@
23797 fcgi_addr_in.sin_family = AF_INET;
23799 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
23800 - log_error_write(srv, __FILE__, __LINE__, "sbs",
23801 - "converting IP-adress failed for", host->host,
23802 + log_error_write(srv, __FILE__, __LINE__, "sbs",
23803 + "converting IP-adress failed for", host->host,
23804 "\nBe sure to specify an IP address here");
23810 fcgi_addr_in.sin_port = htons(proc->port);
23811 servlen = sizeof(fcgi_addr_in);
23814 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
23816 if (buffer_is_empty(proc->connection_name)) {
23817 @@ -1715,20 +1670,20 @@
23818 buffer_append_long(proc->connection_name, proc->port);
23823 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
23824 - if (errno == EINPROGRESS ||
23825 + if (errno == EINPROGRESS ||
23826 errno == EALREADY ||
23828 if (hctx->conf.debug > 2) {
23829 - log_error_write(srv, __FILE__, __LINE__, "sb",
23830 + log_error_write(srv, __FILE__, __LINE__, "sb",
23831 "connect delayed, will continue later:", proc->connection_name);
23835 return CONNECTION_DELAYED;
23836 } else if (errno == EAGAIN) {
23837 if (hctx->conf.debug) {
23838 - log_error_write(srv, __FILE__, __LINE__, "sbsd",
23839 + log_error_write(srv, __FILE__, __LINE__, "sbsd",
23840 "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
23841 "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
23842 "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
23843 @@ -1736,8 +1691,8 @@
23845 return CONNECTION_OVERLOADED;
23847 - log_error_write(srv, __FILE__, __LINE__, "sssb",
23848 - "connect failed:",
23849 + log_error_write(srv, __FILE__, __LINE__, "sssb",
23850 + "connect failed:",
23851 strerror(errno), "on",
23852 proc->connection_name);
23854 @@ -1747,7 +1702,7 @@
23856 hctx->reconnects = 0;
23857 if (hctx->conf.debug > 1) {
23858 - log_error_write(srv, __FILE__, __LINE__, "sd",
23859 + log_error_write(srv, __FILE__, __LINE__, "sd",
23860 "connect succeeded: ", fcgi_fd);
23863 @@ -1756,21 +1711,21 @@
23865 static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
23869 for (i = 0; i < con->request.headers->used; i++) {
23873 ds = (data_string *)con->request.headers->data[i];
23876 if (ds->value->used && ds->key->used) {
23878 buffer_reset(srv->tmp_buf);
23881 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
23882 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
23883 srv->tmp_buf->used--;
23887 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23888 for (j = 0; j < ds->key->used - 1; j++) {
23890 @@ -1784,20 +1739,20 @@
23891 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23893 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23896 fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23901 for (i = 0; i < con->environment->used; i++) {
23905 ds = (data_string *)con->environment->data[i];
23908 if (ds->value->used && ds->key->used) {
23910 buffer_reset(srv->tmp_buf);
23913 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23914 for (j = 0; j < ds->key->used - 1; j++) {
23916 @@ -1811,11 +1766,11 @@
23917 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23919 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23922 fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23930 @@ -1824,24 +1779,24 @@
23931 FCGI_BeginRequestRecord beginRecord;
23932 FCGI_Header header;
23939 char b2[INET6_ADDRSTRLEN + 1];
23943 plugin_data *p = hctx->plugin_data;
23944 fcgi_extension_host *host= hctx->host;
23946 connection *con = hctx->remote_conn;
23947 server_socket *srv_sock = con->srv_socket;
23950 sock_addr our_addr;
23951 socklen_t our_addr_len;
23954 /* send FCGI_BEGIN_REQUEST */
23957 fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
23958 beginRecord.body.roleB0 = host->mode;
23959 beginRecord.body.roleB1 = 0;
23960 @@ -1849,21 +1804,21 @@
23961 memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
23963 b = chunkqueue_get_append_buffer(hctx->wb);
23966 buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
23969 /* send FCGI_PARAMS */
23970 buffer_prepare_copy(p->fcgi_env, 1024);
23973 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
23976 if (con->server_name->used) {
23977 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
23980 - s = inet_ntop(srv_sock->addr.plain.sa_family,
23981 - srv_sock->addr.plain.sa_family == AF_INET6 ?
23982 + s = inet_ntop(srv_sock->addr.plain.sa_family,
23983 + srv_sock->addr.plain.sa_family == AF_INET6 ?
23984 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
23985 (const void *) &(srv_sock->addr.ipv4.sin_addr),
23987 @@ -1872,50 +1827,50 @@
23989 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
23993 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
23999 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
24001 ntohs(srv_sock->addr.ipv4.sin_port)
24006 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
24009 /* get the server-side of the connection to the client */
24010 our_addr_len = sizeof(our_addr);
24012 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
24014 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
24015 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
24017 s = inet_ntop_cache_get_ip(srv, &(our_addr));
24019 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
24025 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
24027 ntohs(con->dst_addr.ipv4.sin_port)
24032 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
24035 s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
24036 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
24039 if (!buffer_is_empty(con->authed_user)) {
24040 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
24041 CONST_BUF_LEN(con->authed_user));
24045 if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
24046 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
24049 /* request.content_length < SSIZE_MAX, see request.c */
24050 ltostr(buf, con->request.content_length);
24051 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
24052 @@ -1930,12 +1885,12 @@
24055 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
24058 if (!buffer_is_empty(con->request.pathinfo)) {
24059 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
24062 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
24065 if (!buffer_is_empty(host->docroot)) {
24066 buffer_copy_string_buffer(p->path, host->docroot);
24068 @@ -1957,27 +1912,27 @@
24071 if (!buffer_is_empty(host->docroot)) {
24073 - * rewrite SCRIPT_FILENAME
24076 + * rewrite SCRIPT_FILENAME
24081 buffer_copy_string_buffer(p->path, host->docroot);
24082 buffer_append_string_buffer(p->path, con->uri.path);
24085 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24086 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
24088 buffer_copy_string_buffer(p->path, con->physical.path);
24090 - /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
24093 + /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
24095 * see src/sapi/cgi_main.c, init_request_info()
24097 if (host->break_scriptfilename_for_php) {
24098 buffer_append_string_buffer(p->path, con->request.pathinfo);
24102 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24103 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
24105 @@ -1987,7 +1942,7 @@
24109 - * stripping /app1 or /app1/ should lead to
24110 + * stripping /app1 or /app1/ should lead to
24114 @@ -2001,7 +1956,7 @@
24115 0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
24116 /* the left is the same */
24118 - fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24119 + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24120 con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
24121 con->request.orig_uri->used - (host->strip_request_uri->used - 2));
24123 @@ -2018,26 +1973,26 @@
24125 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
24129 s = get_http_method_name(con->request.http_method);
24130 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
24131 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
24132 s = get_http_version_name(con->request.http_version);
24133 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
24137 if (srv_sock->is_ssl) {
24138 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
24145 fcgi_env_add_request_headers(srv, con, p);
24148 fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
24149 buffer_append_memory(b, (const char *)&header, sizeof(header));
24150 buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
24153 fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
24154 buffer_append_memory(b, (const char *)&header, sizeof(header));
24156 @@ -2057,7 +2012,7 @@
24158 /* we announce toWrite octects
24159 * now take all the request_content chunk that we need to fill this request
24163 b = chunkqueue_get_append_buffer(hctx->wb);
24164 fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
24165 @@ -2080,16 +2035,16 @@
24166 if (weHave > weWant - written) weHave = weWant - written;
24168 if (p->conf.debug > 10) {
24169 - fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24170 - __FILE__, __LINE__,
24173 - req_c->file.length,
24174 + fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24175 + __FILE__, __LINE__,
24178 + req_c->file.length,
24179 req_c->file.name->ptr);
24182 assert(weHave != 0);
24185 chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
24187 req_c->offset += weHave;
24188 @@ -2104,7 +2059,7 @@
24189 * - we reference the tempfile from the request-content-queue several times
24190 * if the req_c is larger than FCGI_MAX_LENGTH
24191 * - we can't simply cleanup the request-content-queue as soon as possible
24192 - * as it would remove the tempfiles
24193 + * as it would remove the tempfiles
24194 * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
24195 * referencing chunk of the fastcgi-write-queue
24197 @@ -2141,7 +2096,7 @@
24198 req_c->offset += weHave;
24199 req_cq->bytes_out += weHave;
24203 hctx->wb->bytes_in += weHave;
24205 if (req_c->offset == req_c->mem->used - 1) {
24206 @@ -2155,12 +2110,12 @@
24212 b->used++; /* add virtual \0 */
24218 b = chunkqueue_get_append_buffer(hctx->wb);
24219 /* terminate STDIN */
24220 fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
24221 @@ -2175,118 +2130,19 @@
24222 if ((i+1) % 16 == 0) {
24224 for (j = i-15; j <= i; j++) {
24225 - fprintf(stderr, "%c",
24226 + fprintf(stderr, "%c",
24227 isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
24229 fprintf(stderr, "\n");
24237 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
24240 - handler_ctx *hctx = con->plugin_ctx[p->id];
24241 - fcgi_extension_host *host= hctx->host;
24245 - buffer_copy_string_buffer(p->parse_response, in);
24247 - /* search for \n */
24248 - for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
24249 - char *key, *value;
24253 - /* a good day. Someone has read the specs and is sending a \r\n to us */
24255 - if (ns > p->parse_response->ptr &&
24256 - *(ns-1) == '\r') {
24263 - if (NULL == (value = strchr(s, ':'))) {
24264 - /* we expect: "<key>: <value>\n" */
24268 - key_len = value - key;
24272 - while (*value == ' ' || *value == '\t') value++;
24274 - if (host->mode != FCGI_AUTHORIZER ||
24275 - !(con->http_status == 0 ||
24276 - con->http_status == 200)) {
24277 - /* authorizers shouldn't affect the response headers sent back to the client */
24279 - /* don't forward Status: */
24280 - if (0 != strncasecmp(key, "Status", key_len)) {
24281 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24282 - ds = data_response_init();
24284 - buffer_copy_string_len(ds->key, key, key_len);
24285 - buffer_copy_string(ds->value, value);
24287 - array_insert_unique(con->response.headers, (data_unset *)ds);
24291 - switch(key_len) {
24293 - if (0 == strncasecmp(key, "Date", key_len)) {
24294 - con->parsed_response |= HTTP_DATE;
24298 - if (0 == strncasecmp(key, "Status", key_len)) {
24299 - con->http_status = strtol(value, NULL, 10);
24300 - con->parsed_response |= HTTP_STATUS;
24304 - if (0 == strncasecmp(key, "Location", key_len)) {
24305 - con->parsed_response |= HTTP_LOCATION;
24309 - if (0 == strncasecmp(key, "Connection", key_len)) {
24310 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
24311 - con->parsed_response |= HTTP_CONNECTION;
24315 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
24316 - con->response.content_length = strtol(value, NULL, 10);
24317 - con->parsed_response |= HTTP_CONTENT_LENGTH;
24319 - if (con->response.content_length < 0) con->response.content_length = 0;
24327 - /* CGI/1.1 rev 03 - 7.2.1.2 */
24328 - if ((con->parsed_response & HTTP_LOCATION) &&
24329 - !(con->parsed_response & HTTP_STATUS)) {
24330 - con->http_status = 302;
24342 @@ -2327,9 +2183,9 @@
24346 - /* we have at least a header, now check how much me have to fetch */
24347 + /* we have at least a header, now check how much me have to fetch */
24348 header = (FCGI_Header *)(packet->b->ptr);
24351 packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
24352 packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
24353 packet->type = header->type;
24354 @@ -2348,7 +2204,7 @@
24355 size_t weHave = c->mem->used - c->offset - offset - 1;
24357 if (weHave > weWant) weHave = weWant;
24360 buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
24362 /* we only skipped the first 8 bytes as they are the fcgi header */
24363 @@ -2380,65 +2236,42 @@
24366 chunkqueue_remove_finished_chunks(hctx->rb);
24372 static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
24378 plugin_data *p = hctx->plugin_data;
24379 connection *con = hctx->remote_conn;
24380 - int fcgi_fd = hctx->fd;
24381 fcgi_extension_host *host= hctx->host;
24382 fcgi_proc *proc = hctx->proc;
24385 - * check how much we have to read
24387 - if (ioctl(hctx->fd, FIONREAD, &toread)) {
24388 - log_error_write(srv, __FILE__, __LINE__, "sd",
24389 - "unexpected end-of-file (perhaps the fastcgi process died):",
24394 - /* init read-buffer */
24396 - if (toread > 0) {
24399 - b = chunkqueue_get_append_buffer(hctx->rb);
24400 - buffer_prepare_copy(b, toread + 1);
24402 - /* append to read-buffer */
24403 - if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
24404 - log_error_write(srv, __FILE__, __LINE__, "sds",
24405 - "unexpected end-of-file (perhaps the fastcgi process died):",
24406 - fcgi_fd, strerror(errno));
24410 - /* this should be catched by the b > 0 above */
24414 - b->used = r + 1; /* one extra for the fake \0 */
24415 - b->ptr[b->used - 1] = '\0';
24417 - log_error_write(srv, __FILE__, __LINE__, "ssdsb",
24418 - "unexpected end-of-file (perhaps the fastcgi process died):",
24419 - "pid:", proc->pid,
24420 - "socket:", proc->connection_name);
24422 + /* in case we read nothing, check the return code
24423 + * if we got something, be happy :)
24425 + * Ok, to be honest:
24426 + * - it is fine to receive a EAGAIN on a second read() call
24427 + * - it might be fine they we get a con-close on a second read() call */
24428 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
24429 + case NETWORK_STATUS_WAIT_FOR_EVENT:
24430 + /* a EAGAIN after we read exactly the chunk-size */
24432 + ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
24434 + case NETWORK_STATUS_SUCCESS:
24437 + ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
24442 * parse the fastcgi packets and forward the content to the write-queue
24447 fastcgi_response_packet packet;
24449 @@ -2454,92 +2287,136 @@
24451 /* is the header already finished */
24452 if (0 == con->file_started) {
24457 - /* search for header terminator
24459 - * if we start with \r\n check if last packet terminated with \r\n
24460 - * if we start with \n check if last packet terminated with \n
24461 - * search for \r\n\r\n
24462 - * search for \n\n
24465 - if (hctx->response_header->used == 0) {
24466 - buffer_copy_string_buffer(hctx->response_header, packet.b);
24468 - buffer_append_string_buffer(hctx->response_header, packet.b);
24471 - if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
24472 - blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
24473 - hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
24474 - c += 4; /* point the the start of the response */
24475 - } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
24476 - blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
24477 - hctx->response_header->used = c - hctx->response_header->ptr + 2;
24478 - c += 2; /* point the the start of the response */
24480 - /* no luck, no header found */
24481 + int have_content_length = 0;
24482 + int need_more = 0;
24485 + /* append the current packet to the chunk queue */
24486 + chunkqueue_append_buffer(hctx->http_rb, packet.b);
24487 + http_response_reset(p->resp);
24489 + switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
24490 + case PARSE_ERROR:
24491 + /* parsing the response header failed */
24493 + con->http_status = 502; /* Bad Gateway */
24496 + case PARSE_NEED_MORE:
24498 + break; /* leave the loop */
24499 + case PARSE_SUCCESS:
24502 + /* should not happen */
24506 - /* parse the response header */
24507 - fcgi_response_parse(srv, con, p, hctx->response_header);
24508 + if (need_more) break;
24510 - con->file_started = 1;
24511 + chunkqueue_remove_finished_chunks(hctx->http_rb);
24513 + con->http_status = p->resp->status;
24514 + hctx->send_content_body = 1;
24516 - if (host->mode == FCGI_AUTHORIZER &&
24517 - (con->http_status == 0 ||
24518 - con->http_status == 200)) {
24519 - /* a authorizer with approved the static request, ignore the content here */
24520 - hctx->send_content_body = 0;
24523 - if (host->allow_xsendfile &&
24524 - NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
24525 - stat_cache_entry *sce;
24527 - if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
24530 - http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
24531 - hctx->send_content_body = 0; /* ignore the content */
24532 - joblist_append(srv, con);
24533 + /* handle the header fields */
24534 + if (host->mode == FCGI_AUTHORIZER) {
24535 + /* auth mode is a bit different */
24537 + if (con->http_status == 0 ||
24538 + con->http_status == 200) {
24539 + /* a authorizer with approved the static request, ignore the content here */
24540 + hctx->send_content_body = 0;
24544 + /* copy the http-headers */
24545 + for (i = 0; i < p->resp->headers->used; i++) {
24546 + const char *ign[] = { "Status", NULL };
24550 + data_string *header = (data_string *)p->resp->headers->data[i];
24552 + /* ignore all headers in AUTHORIZER mode */
24553 + if (host->mode == FCGI_AUTHORIZER) continue;
24555 + /* some headers are ignored by default */
24556 + for (j = 0; ign[j]; j++) {
24557 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
24559 + if (ign[j]) continue;
24561 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
24562 + /* CGI/1.1 rev 03 - 7.2.1.2 */
24563 + con->http_status = 302;
24564 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
24565 + have_content_length = 1;
24566 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) ||
24567 + 0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
24569 + stat_cache_entry *sce;
24571 - if (hctx->send_content_body && blen > 1) {
24572 - /* enable chunked-transfer-encoding */
24573 + if (host->allow_xsendfile &&
24574 + HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
24575 + http_chunk_append_file(srv, con, header->value, 0, sce->st.st_size);
24576 + hctx->send_content_body = 0; /* ignore the content */
24578 + joblist_append(srv, con);
24581 + continue; /* ignore header */
24584 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24585 + ds = data_response_init();
24587 + buffer_copy_string_buffer(ds->key, header->key);
24588 + buffer_copy_string_buffer(ds->value, header->value);
24590 + array_insert_unique(con->response.headers, (data_unset *)ds);
24593 + /* header is complete ... go on with the body */
24595 + con->file_started = 1;
24597 + if (hctx->send_content_body) {
24598 + chunk *c = hctx->http_rb->first;
24600 + /* if we don't have a content-length enable chunked encoding
24603 + * TODO: move this to a later stage in the filter-queue
24605 if (con->request.http_version == HTTP_VERSION_1_1 &&
24606 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24607 + !have_content_length) {
24608 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24611 - http_chunk_append_mem(srv, con, c, blen);
24612 + /* copy the rest of the data */
24613 + for (c = hctx->http_rb->first; c; c = c->next) {
24614 + if (c->mem->used > 1) {
24615 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
24616 + c->offset = c->mem->used - 1;
24619 + chunkqueue_remove_finished_chunks(hctx->http_rb);
24620 joblist_append(srv, con);
24622 } else if (hctx->send_content_body && packet.b->used > 1) {
24623 - if (con->request.http_version == HTTP_VERSION_1_1 &&
24624 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24625 - /* enable chunked-transfer-encoding */
24626 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24629 http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
24630 joblist_append(srv, con);
24634 - log_error_write(srv, __FILE__, __LINE__, "sb",
24635 + log_error_write(srv, __FILE__, __LINE__, "sb",
24636 "FastCGI-stderr:", packet.b);
24640 case FCGI_END_REQUEST:
24641 con->file_finished = 1;
24644 if (host->mode != FCGI_AUTHORIZER ||
24645 !(con->http_status == 0 ||
24646 con->http_status == 200)) {
24647 @@ -2547,39 +2424,39 @@
24648 http_chunk_append_mem(srv, con, NULL, 0);
24649 joblist_append(srv, con);
24656 - log_error_write(srv, __FILE__, __LINE__, "sd",
24657 + log_error_write(srv, __FILE__, __LINE__, "sd",
24658 "FastCGI: header.type not handled: ", packet.type);
24661 buffer_free(packet.b);
24668 static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
24672 for (proc = host->first; proc; proc = proc->next) {
24675 if (p->conf.debug > 2) {
24676 - log_error_write(srv, __FILE__, __LINE__, "sbdddd",
24678 + log_error_write(srv, __FILE__, __LINE__, "sbdddd",
24680 proc->connection_name,
24690 * if the remote side is overloaded, we check back after <n> seconds
24694 switch (proc->state) {
24695 case PROC_STATE_KILLED:
24696 @@ -2592,13 +2469,13 @@
24698 case PROC_STATE_OVERLOADED:
24699 if (srv->cur_ts <= proc->disabled_until) break;
24702 proc->state = PROC_STATE_RUNNING;
24703 host->active_procs++;
24705 - log_error_write(srv, __FILE__, __LINE__, "sbdb",
24706 - "fcgi-server re-enabled:",
24707 - host->host, host->port,
24709 + log_error_write(srv, __FILE__, __LINE__, "sbdb",
24710 + "fcgi-server re-enabled:",
24711 + host->host, host->port,
24714 case PROC_STATE_DIED_WAIT_FOR_PID:
24715 @@ -2606,7 +2483,7 @@
24716 if (!proc->is_local) break;
24718 /* the child should not terminate at all */
24721 switch(waitpid(proc->pid, &status, WNOHANG)) {
24723 /* child is still alive */
24724 @@ -2616,45 +2493,45 @@
24726 if (WIFEXITED(status)) {
24728 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
24729 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
24730 "child exited, pid:", proc->pid,
24731 "status:", WEXITSTATUS(status));
24733 } else if (WIFSIGNALED(status)) {
24734 - log_error_write(srv, __FILE__, __LINE__, "sd",
24735 - "child signaled:",
24736 + log_error_write(srv, __FILE__, __LINE__, "sd",
24737 + "child signaled:",
24740 - log_error_write(srv, __FILE__, __LINE__, "sd",
24741 - "child died somehow:",
24742 + log_error_write(srv, __FILE__, __LINE__, "sd",
24743 + "child died somehow:",
24748 proc->state = PROC_STATE_DIED;
24753 /* fall through if we have a dead proc now */
24754 if (proc->state != PROC_STATE_DIED) break;
24756 case PROC_STATE_DIED:
24757 - /* local proc get restarted by us,
24758 + /* local proc get restarted by us,
24759 * remote ones hopefully by the admin */
24762 if (proc->is_local) {
24763 /* we still have connections bound to this proc,
24764 * let them terminate first */
24765 if (proc->load != 0) break;
24768 /* restart the child */
24771 if (p->conf.debug) {
24772 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
24773 "--- fastcgi spawning",
24774 "\n\tsocket", proc->connection_name,
24775 "\n\tcurrent:", 1, "/", host->min_procs);
24779 if (fcgi_spawn_connection(srv, p, host, proc)) {
24780 log_error_write(srv, __FILE__, __LINE__, "s",
24781 "ERROR: spawning fcgi failed.");
24782 @@ -2662,18 +2539,18 @@
24785 if (srv->cur_ts <= proc->disabled_until) break;
24788 proc->state = PROC_STATE_RUNNING;
24789 host->active_procs++;
24791 - log_error_write(srv, __FILE__, __LINE__, "sb",
24792 - "fcgi-server re-enabled:",
24794 + log_error_write(srv, __FILE__, __LINE__, "sb",
24795 + "fcgi-server re-enabled:",
24796 proc->connection_name);
24806 @@ -2682,19 +2559,19 @@
24807 fcgi_extension_host *host= hctx->host;
24808 connection *con = hctx->remote_conn;
24814 - /* sanity check */
24815 + /* sanity check */
24817 ((!host->host->used || !host->port) && !host->unixsocket->used)) {
24818 - log_error_write(srv, __FILE__, __LINE__, "sxddd",
24819 + log_error_write(srv, __FILE__, __LINE__, "sxddd",
24820 "write-req: error",
24824 host->unixsocket->used);
24827 hctx->proc->disabled_until = srv->cur_ts + 10;
24828 hctx->proc->state = PROC_STATE_DIED;
24830 @@ -2705,12 +2582,12 @@
24831 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
24833 socklen_t socket_error_len = sizeof(socket_error);
24836 /* try to finish the connect() */
24837 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24838 - log_error_write(srv, __FILE__, __LINE__, "ss",
24839 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24840 + log_error_write(srv, __FILE__, __LINE__, "ss",
24841 "getsockopt failed:", strerror(errno));
24844 hctx->proc->disabled_until = srv->cur_ts + 10;
24845 hctx->proc->state = PROC_STATE_DIED;
24847 @@ -2719,12 +2596,12 @@
24848 if (socket_error != 0) {
24849 if (!hctx->proc->is_local || p->conf.debug) {
24850 /* local procs get restarted */
24853 log_error_write(srv, __FILE__, __LINE__, "sssb",
24854 - "establishing connection failed:", strerror(socket_error),
24855 + "establishing connection failed:", strerror(socket_error),
24856 "socket:", hctx->proc->connection_name);
24860 hctx->proc->disabled_until = srv->cur_ts + 5;
24862 if (hctx->proc->is_local) {
24863 @@ -2732,17 +2609,17 @@
24865 hctx->proc->state = PROC_STATE_DIED;
24869 hctx->proc->state = PROC_STATE_DIED;
24872 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24873 buffer_append_string(p->statuskey, ".died");
24875 - status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24877 + status_counter_inc(CONST_BUF_LEN(p->statuskey));
24879 return HANDLER_ERROR;
24881 - /* go on with preparing the request */
24882 + /* go on with preparing the request */
24883 hctx->state = FCGI_STATE_PREPARE_WRITE;
24886 @@ -2755,14 +2632,14 @@
24887 /* do we have a running process for this host (max-procs) ? */
24890 - for (proc = hctx->host->first;
24891 - proc && proc->state != PROC_STATE_RUNNING;
24892 + for (proc = hctx->host->first;
24893 + proc && proc->state != PROC_STATE_RUNNING;
24894 proc = proc->next);
24897 /* all childs are dead */
24898 if (proc == NULL) {
24899 - hctx->fde_ndx = -1;
24901 + hctx->sock->fde_ndx = -1;
24903 return HANDLER_ERROR;
24906 @@ -2775,50 +2652,50 @@
24909 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
24911 - if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
24913 + if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
24914 if (errno == EMFILE ||
24916 - log_error_write(srv, __FILE__, __LINE__, "sd",
24917 - "wait for fd at connection:", con->fd);
24919 + log_error_write(srv, __FILE__, __LINE__, "sd",
24920 + "wait for fd at connection:", con->sock->fd);
24922 return HANDLER_WAIT_FOR_FD;
24925 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
24927 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
24928 "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
24929 return HANDLER_ERROR;
24931 - hctx->fde_ndx = -1;
24933 + hctx->sock->fde_ndx = -1;
24937 - fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
24939 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
24940 - log_error_write(srv, __FILE__, __LINE__, "ss",
24942 + fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
24944 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
24945 + log_error_write(srv, __FILE__, __LINE__, "ss",
24946 "fcntl failed:", strerror(errno));
24949 return HANDLER_ERROR;
24953 if (hctx->proc->is_local) {
24954 hctx->pid = hctx->proc->pid;
24958 switch (fcgi_establish_connection(srv, hctx)) {
24959 case CONNECTION_DELAYED:
24960 /* connection is in progress, wait for an event and call getsockopt() below */
24962 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
24965 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
24967 fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
24968 return HANDLER_WAIT_FOR_EVENT;
24969 case CONNECTION_OVERLOADED:
24970 /* cool down the backend, it is overloaded
24973 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24974 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24975 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
24976 "reconnects:", hctx->reconnects,
24977 "load:", host->load);
24978 @@ -2830,8 +2707,8 @@
24979 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24980 buffer_append_string(p->statuskey, ".overloaded");
24982 - status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24984 + status_counter_inc(CONST_BUF_LEN(p->statuskey));
24986 return HANDLER_ERROR;
24987 case CONNECTION_DEAD:
24988 /* we got a hard error from the backend like
24989 @@ -2840,67 +2717,67 @@
24991 * for check if the host is back in 5 seconds
24995 hctx->proc->disabled_until = srv->cur_ts + 5;
24996 if (hctx->proc->is_local) {
24997 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
24999 hctx->proc->state = PROC_STATE_DIED;
25002 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
25004 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
25005 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
25006 "reconnects:", hctx->reconnects,
25007 "load:", host->load);
25010 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
25011 buffer_append_string(p->statuskey, ".died");
25013 - status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
25014 + status_counter_inc(CONST_BUF_LEN(p->statuskey));
25016 return HANDLER_ERROR;
25017 case CONNECTION_OK:
25018 /* everything is ok, go on */
25020 fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
25024 case CONNECTION_UNSET:
25029 case FCGI_STATE_PREPARE_WRITE:
25030 /* ok, we have the connection */
25033 hctx->proc->load++;
25034 hctx->proc->last_used = srv->cur_ts;
25035 hctx->got_proc = 1;
25037 - status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
25038 - status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
25040 + status_counter_inc(CONST_STR_LEN("fastcgi.requests"));
25041 + status_counter_inc(CONST_STR_LEN("fastcgi.active-requests"));
25043 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
25044 buffer_append_string(p->statuskey, ".connected");
25046 - status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
25047 + status_counter_inc(CONST_BUF_LEN(p->statuskey));
25049 /* the proc-load */
25050 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
25051 buffer_append_string(p->statuskey, ".load");
25053 - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
25054 + status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->proc->load);
25056 /* the host-load */
25057 fastcgi_status_copy_procname(p->statuskey, hctx->host, NULL);
25058 buffer_append_string(p->statuskey, ".load");
25060 - status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->host->load);
25061 + status_counter_set(CONST_BUF_LEN(p->statuskey), hctx->host->load);
25063 if (p->conf.debug) {
25064 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
25066 - "pid:", hctx->proc->pid,
25067 - "socket:", hctx->proc->connection_name,
25069 + "pid:", hctx->proc->pid,
25070 + "socket:", hctx->proc->connection_name,
25071 "load:", hctx->proc->load);
25074 @@ -2908,74 +2785,75 @@
25075 if (hctx->request_id == 0) {
25076 hctx->request_id = fcgi_requestid_new(srv, p);
25078 - log_error_write(srv, __FILE__, __LINE__, "sd",
25079 + log_error_write(srv, __FILE__, __LINE__, "sd",
25080 "fcgi-request is already in use:", hctx->request_id);
25085 fcgi_create_env(srv, hctx, hctx->request_id);
25088 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
25092 case FCGI_STATE_WRITE:
25093 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
25094 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
25096 chunkqueue_remove_finished_chunks(hctx->wb);
25102 - /* the connection got dropped after accept()
25104 - * this is most of the time a PHP which dies
25105 + /* the connection got dropped after accept()
25107 + * this is most of the time a PHP which dies
25108 * after PHP_FCGI_MAX_REQUESTS
25113 if (hctx->wb->bytes_out == 0 &&
25114 hctx->reconnects < 5) {
25115 - usleep(10000); /* take away the load of the webserver
25116 - * to let the php a chance to restart
25118 + usleep(10000); /* take away the load of the webserver
25119 + * to let the php a chance to restart
25123 fcgi_reconnect(srv, hctx);
25126 return HANDLER_WAIT_FOR_FD;
25130 /* not reconnected ... why
25133 * far@#lighttpd report this for FreeBSD
25138 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
25140 + log_error_write(srv, __FILE__, __LINE__, "ssosd",
25141 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
25142 "write-offset:", hctx->wb->bytes_out,
25143 "reconnect attempts:", hctx->reconnects);
25146 return HANDLER_ERROR;
25149 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25151 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25153 return HANDLER_WAIT_FOR_EVENT;
25155 - log_error_write(srv, __FILE__, __LINE__, "ssd",
25156 + log_error_write(srv, __FILE__, __LINE__, "ssd",
25157 "write failed:", strerror(errno), errno);
25160 return HANDLER_ERROR;
25164 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
25165 /* we don't need the out event anymore */
25166 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
25167 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25168 + fdevent_event_del(srv->ev, hctx->sock);
25169 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25170 fcgi_set_state(srv, hctx, FCGI_STATE_READ);
25172 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25174 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25176 return HANDLER_WAIT_FOR_EVENT;
25179 @@ -2987,7 +2865,7 @@
25180 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
25181 return HANDLER_ERROR;
25185 return HANDLER_WAIT_FOR_EVENT;
25188 @@ -2996,18 +2874,18 @@
25190 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
25191 plugin_data *p = p_d;
25194 handler_ctx *hctx = con->plugin_ctx[p->id];
25196 fcgi_extension_host *host;
25199 if (NULL == hctx) return HANDLER_GO_ON;
25203 if (con->mode != p->id) return HANDLER_GO_ON;
25205 /* we don't have a host yet, choose one
25206 - * -> this happens in the first round
25207 + * -> this happens in the first round
25208 * and when the host died and we have to select a new one */
25209 if (hctx->host == NULL) {
25211 @@ -3016,23 +2894,23 @@
25212 /* get best server */
25213 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
25214 host = hctx->ext->hosts[k];
25217 /* we should have at least one proc that can do something */
25218 if (host->active_procs == 0) continue;
25220 if (used == -1 || host->load < used) {
25229 /* found a server */
25231 /* all hosts are down */
25233 fcgi_connection_close(srv, hctx);
25236 con->http_status = 500;
25237 con->mode = DIRECT;
25239 @@ -3040,16 +2918,16 @@
25242 host = hctx->ext->hosts[ndx];
25245 - * if check-local is disabled, use the uri.path handler
25249 + * if check-local is disabled, use the uri.path handler
25254 /* init handler-context */
25257 - /* we put a connection on this host, move the other new connections to other hosts
25258 + /* we put a connection on this host, move the other new connections to other hosts
25260 * as soon as hctx->host is unassigned, decrease the load again */
25261 hctx->host->load++;
25262 @@ -3063,7 +2941,7 @@
25263 case HANDLER_ERROR:
25268 if (hctx->state == FCGI_STATE_INIT ||
25269 hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25270 if (proc) host->active_procs--;
25271 @@ -3078,7 +2956,7 @@
25272 return HANDLER_WAIT_FOR_FD;
25274 fcgi_connection_close(srv, hctx);
25277 buffer_reset(con->physical.path);
25278 con->mode = DIRECT;
25279 con->http_status = 500;
25280 @@ -3088,12 +2966,12 @@
25283 fcgi_connection_close(srv, hctx);
25286 buffer_reset(con->physical.path);
25287 con->mode = DIRECT;
25288 con->http_status = 503;
25289 joblist_append(srv, con); /* really ? */
25292 return HANDLER_FINISHED;
25294 case HANDLER_WAIT_FOR_EVENT:
25295 @@ -3115,7 +2993,7 @@
25296 handler_ctx *hctx = ctx;
25297 connection *con = hctx->remote_conn;
25298 plugin_data *p = hctx->plugin_data;
25301 fcgi_proc *proc = hctx->proc;
25302 fcgi_extension_host *host= hctx->host;
25304 @@ -3125,8 +3003,8 @@
25309 - if (host->mode == FCGI_AUTHORIZER &&
25311 + if (host->mode == FCGI_AUTHORIZER &&
25312 (con->http_status == 200 ||
25313 con->http_status == 0)) {
25315 @@ -3136,26 +3014,26 @@
25318 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
25321 buffer_copy_string_buffer(con->physical.path, host->docroot);
25322 buffer_append_string_buffer(con->physical.path, con->uri.path);
25323 fcgi_connection_close(srv, hctx);
25326 con->mode = DIRECT;
25327 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
25330 fcgi_connection_close(srv, hctx);
25334 joblist_append(srv, con);
25335 return HANDLER_FINISHED;
25337 if (proc->pid && proc->state != PROC_STATE_DIED) {
25341 /* only fetch the zombie if it is not already done */
25344 switch(waitpid(proc->pid, &status, WNOHANG)) {
25346 /* child is still alive */
25347 @@ -3165,60 +3043,61 @@
25349 /* the child should not terminate at all */
25350 if (WIFEXITED(status)) {
25351 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
25352 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
25353 "child exited, pid:", proc->pid,
25354 "status:", WEXITSTATUS(status));
25355 } else if (WIFSIGNALED(status)) {
25356 - log_error_write(srv, __FILE__, __LINE__, "sd",
25357 - "child signaled:",
25358 + log_error_write(srv, __FILE__, __LINE__, "sd",
25359 + "child signaled:",
25362 - log_error_write(srv, __FILE__, __LINE__, "sd",
25363 - "child died somehow:",
25364 + log_error_write(srv, __FILE__, __LINE__, "sd",
25365 + "child died somehow:",
25370 if (p->conf.debug) {
25371 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
25372 "--- fastcgi spawning",
25373 "\n\tsocket", proc->connection_name,
25374 "\n\tcurrent:", 1, "/", host->min_procs);
25378 if (fcgi_spawn_connection(srv, p, host, proc)) {
25379 /* respawning failed, retry later */
25380 proc->state = PROC_STATE_DIED;
25382 - log_error_write(srv, __FILE__, __LINE__, "s",
25383 + log_error_write(srv, __FILE__, __LINE__, "s",
25384 "respawning failed, will retry later");
25393 if (con->file_started == 0) {
25394 /* nothing has been send out yet, try to use another child */
25397 if (hctx->wb->bytes_out == 0 &&
25398 hctx->reconnects < 5) {
25399 fcgi_reconnect(srv, hctx);
25401 - log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25403 + log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25404 "response not received, request not sent",
25405 - "on socket:", proc->connection_name,
25406 + "on socket:", proc->connection_name,
25407 "for", con->uri.path, ", reconnecting");
25410 return HANDLER_WAIT_FOR_FD;
25413 - log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25415 + log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25416 "response not received, request sent:", hctx->wb->bytes_out,
25417 - "on socket:", proc->connection_name,
25418 + "on socket:", proc->connection_name,
25419 "for", con->uri.path, ", closing connection");
25422 fcgi_connection_close(srv, hctx);
25425 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
25426 buffer_reset(con->physical.path);
25427 con->http_status = 500;
25428 @@ -3226,76 +3105,76 @@
25430 /* response might have been already started, kill the connection */
25431 fcgi_connection_close(srv, hctx);
25433 - log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25435 + log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25436 "response already sent out, but backend returned error",
25437 - "on socket:", proc->connection_name,
25438 + "on socket:", proc->connection_name,
25439 "for", con->uri.path, ", terminating connection");
25442 connection_set_state(srv, con, CON_STATE_ERROR);
25450 joblist_append(srv, con);
25451 return HANDLER_FINISHED;
25456 if (revents & FDEVENT_OUT) {
25457 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
25458 hctx->state == FCGI_STATE_WRITE) {
25459 /* we are allowed to send something out
25462 * 1. in a unfinished connect() call
25463 * 2. in a unfinished write() call (long POST request)
25465 return mod_fastcgi_handle_subrequest(srv, con, p);
25467 - log_error_write(srv, __FILE__, __LINE__, "sd",
25468 - "got a FDEVENT_OUT and didn't know why:",
25469 + log_error_write(srv, __FILE__, __LINE__, "sd",
25470 + "got a FDEVENT_OUT and didn't know why:",
25476 /* perhaps this issue is already handled */
25477 if (revents & FDEVENT_HUP) {
25478 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25479 /* getoptsock will catch this one (right ?)
25481 - * if we are in connect we might get a EINPROGRESS
25482 - * in the first call and a FDEVENT_HUP in the
25484 + * if we are in connect we might get a EINPROGRESS
25485 + * in the first call and a FDEVENT_HUP in the
25489 * FIXME: as it is a bit ugly.
25493 return mod_fastcgi_handle_subrequest(srv, con, p);
25494 } else if (hctx->state == FCGI_STATE_READ &&
25495 hctx->proc->port == 0) {
25499 * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
25500 * even if the FCGI_FIN packet is not received yet
25503 - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25504 - "error: unexpected close of fastcgi connection for",
25505 + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25506 + "error: unexpected close of fastcgi connection for",
25508 - "(no fastcgi process on host:",
25509 + "(no fastcgi process on host:",
25518 connection_set_state(srv, con, CON_STATE_ERROR);
25519 fcgi_connection_close(srv, hctx);
25520 joblist_append(srv, con);
25522 } else if (revents & FDEVENT_ERR) {
25523 - log_error_write(srv, __FILE__, __LINE__, "s",
25524 + log_error_write(srv, __FILE__, __LINE__, "s",
25525 "fcgi: got a FDEVENT_ERR. Don't know why.");
25526 /* kill all connections to the fastcgi process */
25528 @@ -3304,45 +3183,42 @@
25529 fcgi_connection_close(srv, hctx);
25530 joblist_append(srv, con);
25534 return HANDLER_FINISHED;
25536 -#define PATCH(x) \
25537 - p->conf.x = s->x;
25539 static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
25541 plugin_config *s = p->config_storage[0];
25545 - PATCH(ext_mapping);
25548 + PATCH_OPTION(exts);
25549 + PATCH_OPTION(debug);
25550 + PATCH_OPTION(ext_mapping);
25552 /* skip the first, the global context */
25553 for (i = 1; i < srv->config_context->used; i++) {
25554 data_config *dc = (data_config *)srv->config_context->data[i];
25555 s = p->config_storage[i];
25558 /* condition didn't match */
25559 if (!config_check_cond(srv, con, dc)) continue;
25563 for (j = 0; j < dc->value->used; j++) {
25564 data_unset *du = dc->value->data[j];
25567 if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
25569 + PATCH_OPTION(exts);
25570 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
25572 + PATCH_OPTION(debug);
25573 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
25574 - PATCH(ext_mapping);
25575 + PATCH_OPTION(ext_mapping);
25586 static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
25587 plugin_data *p = p_d;
25588 @@ -3351,16 +3227,16 @@
25590 fcgi_extension *extension = NULL;
25591 fcgi_extension_host *host = NULL;
25594 /* Possibly, we processed already this request */
25595 if (con->file_started == 1) return HANDLER_GO_ON;
25597 fn = uri_path_handler ? con->uri.path : con->physical.path;
25599 if (buffer_is_empty(fn)) return HANDLER_GO_ON;
25602 s_len = fn->used - 1;
25605 fcgi_patch_connection(srv, con, p);
25607 /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
25608 @@ -3368,24 +3244,24 @@
25609 * fastcgi.map-extensions = ( ".php3" => ".php" )
25611 * fastcgi.server = ( ".php" => ... )
25616 /* check if extension-mapping matches */
25617 for (k = 0; k < p->conf.ext_mapping->used; k++) {
25618 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
25619 size_t ct_len; /* length of the config entry */
25622 if (ds->key->used == 0) continue;
25625 ct_len = ds->key->used - 1;
25628 if (s_len < ct_len) continue;
25631 /* found a mapping */
25632 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
25633 /* check if we know the extension */
25636 /* we can reuse k here */
25637 for (k = 0; k < p->conf.exts->used; k++) {
25638 extension = p->conf.exts->exts[k];
25639 @@ -3407,15 +3283,15 @@
25640 /* check if extension matches */
25641 for (k = 0; k < p->conf.exts->used; k++) {
25642 size_t ct_len; /* length of the config entry */
25645 extension = p->conf.exts->exts[k];
25648 if (extension->key->used == 0) continue;
25651 ct_len = extension->key->used - 1;
25654 if (s_len < ct_len) continue;
25657 /* check extension in the form "/fcgi_pattern" */
25658 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
25660 @@ -3441,10 +3317,10 @@
25664 - /* we found one host that is alive */
25665 + /* we found one host that is alive */
25671 /* sorry, we don't have a server alive for this ext */
25672 buffer_reset(con->physical.path);
25673 @@ -3459,72 +3335,72 @@
25674 "on", extension->key,
25679 return HANDLER_FINISHED;
25682 /* a note about no handler is not sent yey */
25683 extension->note_is_sent = 0;
25686 - * if check-local is disabled, use the uri.path handler
25689 + * if check-local is disabled, use the uri.path handler
25694 /* init handler-context */
25695 if (uri_path_handler) {
25696 if (host->check_local == 0) {
25701 hctx = handler_ctx_init();
25704 hctx->remote_conn = con;
25705 hctx->plugin_data = p;
25707 hctx->ext = extension;
25711 hctx->conf.exts = p->conf.exts;
25712 hctx->conf.debug = p->conf.debug;
25715 con->plugin_ctx[p->id] = hctx;
25721 if (con->conf.log_request_handling) {
25722 - log_error_write(srv, __FILE__, __LINE__, "s",
25723 + log_error_write(srv, __FILE__, __LINE__, "s",
25724 "handling it in mod_fastcgi");
25727 - /* the prefix is the SCRIPT_NAME,
25729 + /* the prefix is the SCRIPT_NAME,
25730 * everthing from start to the next slash
25731 * this is important for check-local = "disable"
25734 * if prefix = /admin.fcgi
25737 * /admin.fcgi/foo/bar
25740 * SCRIPT_NAME = /admin.fcgi
25741 * PATH_INFO = /foo/bar
25744 * if prefix = /fcgi-bin/
25747 * /fcgi-bin/foo/bar
25750 * SCRIPT_NAME = /fcgi-bin/foo
25757 /* the rewrite is only done for /prefix/? matches */
25758 if (extension->key->ptr[0] == '/' &&
25759 con->uri.path->used > extension->key->used &&
25760 NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
25761 - /* rewrite uri.path and pathinfo */
25763 + /* rewrite uri.path and pathinfo */
25765 buffer_copy_string(con->request.pathinfo, pathinfo);
25768 con->uri.path->used -= con->request.pathinfo->used - 1;
25769 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
25771 @@ -3532,19 +3408,19 @@
25774 hctx = handler_ctx_init();
25777 hctx->remote_conn = con;
25778 hctx->plugin_data = p;
25780 hctx->ext = extension;
25783 hctx->conf.exts = p->conf.exts;
25784 hctx->conf.debug = p->conf.debug;
25787 con->plugin_ctx[p->id] = hctx;
25793 if (con->conf.log_request_handling) {
25794 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
25796 @@ -3566,19 +3442,19 @@
25797 JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
25798 plugin_data *p = p_d;
25799 handler_ctx *hctx = con->plugin_ctx[p->id];
25802 if (hctx == NULL) return HANDLER_GO_ON;
25804 - if (hctx->fd != -1) {
25805 + if (hctx->sock->fd != -1) {
25806 switch (hctx->state) {
25807 case FCGI_STATE_READ:
25808 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25810 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25813 case FCGI_STATE_CONNECT_DELAYED:
25814 case FCGI_STATE_WRITE:
25815 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25817 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25820 case FCGI_STATE_INIT:
25822 @@ -3595,7 +3471,7 @@
25824 static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
25825 plugin_data *p = p_d;
25828 fcgi_connection_close(srv, con->plugin_ctx[p->id]);
25830 return HANDLER_GO_ON;
25831 @@ -3604,16 +3480,39 @@
25832 TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
25833 plugin_data *p = p_d;
25839 /* perhaps we should kill a connect attempt after 10-15 seconds
25842 * currently we wait for the TCP timeout which is on Linux 180 seconds
25849 + for (i = 0; i < srv->conns->used; i++) {
25850 + connection *con = srv->conns->ptr[i];
25851 + handler_ctx *hctx = con->plugin_ctx[p->id];
25853 + /* if a connection is ours and is in handle-req for more than max-request-time
25854 + * kill the connection */
25856 + if (con->mode != p->id) continue;
25857 + if (con->state != CON_STATE_HANDLE_REQUEST) continue;
25858 + if (srv->cur_ts < con->request_start + 60) continue;
25860 + /* the request is waiting for a FCGI_STDOUT since 60 seconds */
25862 + /* kill the connection */
25864 + log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
25866 + fcgi_connection_close(srv, hctx);
25868 + con->mode = DIRECT;
25869 + con->http_status = 500;
25871 + joblist_append(srv, con);
25874 /* check all childs if they are still up */
25876 for (i = 0; i < srv->config_context->used; i++) {
25877 @@ -3628,45 +3527,45 @@
25878 fcgi_extension *ex;
25880 ex = exts->exts[j];
25883 for (n = 0; n < ex->used; n++) {
25887 unsigned long sum_load = 0;
25888 fcgi_extension_host *host;
25891 host = ex->hosts[n];
25894 fcgi_restart_dead_procs(srv, p, host);
25897 for (proc = host->first; proc; proc = proc->next) {
25898 sum_load += proc->load;
25902 if (host->num_procs &&
25903 host->num_procs < host->max_procs &&
25904 (sum_load / host->num_procs) > host->max_load_per_proc) {
25905 /* overload, spawn new child */
25906 if (p->conf.debug) {
25907 - log_error_write(srv, __FILE__, __LINE__, "s",
25908 + log_error_write(srv, __FILE__, __LINE__, "s",
25909 "overload detected, spawning a new child");
25913 for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
25917 if (proc == host->unused_procs) host->unused_procs = proc->next;
25920 if (proc->next) proc->next->prev = NULL;
25925 proc = fastcgi_process_init();
25926 proc->id = host->max_id++;
25933 if (buffer_is_empty(host->unixsocket)) {
25934 proc->port = host->port + proc->id;
25936 @@ -3674,13 +3573,13 @@
25937 buffer_append_string(proc->unixsocket, "-");
25938 buffer_append_long(proc->unixsocket, proc->id);
25942 if (fcgi_spawn_connection(srv, p, host, proc)) {
25943 log_error_write(srv, __FILE__, __LINE__, "s",
25944 "ERROR: spawning fcgi failed.");
25945 return HANDLER_ERROR;
25950 proc->next = host->first;
25952 @@ -3688,56 +3587,56 @@
25954 host->first = proc;
25958 for (proc = host->first; proc; proc = proc->next) {
25959 if (proc->load != 0) break;
25960 if (host->num_procs <= host->min_procs) break;
25961 if (proc->pid == 0) continue;
25964 if (srv->cur_ts - proc->last_used > host->idle_timeout) {
25965 /* a proc is idling for a long time now,
25969 if (p->conf.debug) {
25970 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25971 - "idle-timeout reached, terminating child:",
25972 - "socket:", proc->connection_name,
25973 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25974 + "idle-timeout reached, terminating child:",
25975 + "socket:", proc->connection_name,
25982 if (proc->next) proc->next->prev = proc->prev;
25983 if (proc->prev) proc->prev->next = proc->next;
25986 if (proc->prev == NULL) host->first = proc->next;
25990 proc->next = host->unused_procs;
25993 if (host->unused_procs) host->unused_procs->prev = proc;
25994 host->unused_procs = proc;
25997 kill(proc->pid, SIGTERM);
26000 proc->state = PROC_STATE_KILLED;
26002 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
26004 - "socket:", proc->connection_name,
26006 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
26008 + "socket:", proc->connection_name,
26015 /* proc is now in unused, let the next second handle the next process */
26022 for (proc = host->unused_procs; proc; proc = proc->next) {
26026 if (proc->pid == 0) continue;
26029 switch (waitpid(proc->pid, &status, WNOHANG)) {
26031 /* child still running after timeout, good */
26032 @@ -3745,10 +3644,10 @@
26034 if (errno != EINTR) {
26035 /* no PID found ? should never happen */
26036 - log_error_write(srv, __FILE__, __LINE__, "sddss",
26037 + log_error_write(srv, __FILE__, __LINE__, "sddss",
26038 "pid ", proc->pid, proc->state,
26039 "not found:", strerror(errno));
26043 if (errno == ECHILD) {
26044 /* someone else has cleaned up for us */
26045 @@ -3762,25 +3661,26 @@
26046 /* the child should not terminate at all */
26047 if (WIFEXITED(status)) {
26048 if (proc->state != PROC_STATE_KILLED) {
26049 - log_error_write(srv, __FILE__, __LINE__, "sdb",
26051 + log_error_write(srv, __FILE__, __LINE__, "sdb",
26053 WEXITSTATUS(status), proc->connection_name);
26055 } else if (WIFSIGNALED(status)) {
26056 if (WTERMSIG(status) != SIGTERM) {
26057 - log_error_write(srv, __FILE__, __LINE__, "sd",
26058 - "child signaled:",
26059 + log_error_write(srv, __FILE__, __LINE__, "sd",
26060 + "child signaled:",
26064 - log_error_write(srv, __FILE__, __LINE__, "sd",
26065 - "child died somehow:",
26066 + log_error_write(srv, __FILE__, __LINE__, "sd",
26067 + "child died somehow:",
26071 proc->state = PROC_STATE_UNSET;
26078 @@ -3804,8 +3704,8 @@
26079 p->handle_subrequest = mod_fastcgi_handle_subrequest;
26080 p->handle_joblist = mod_fastcgi_handle_joblist;
26081 p->handle_trigger = mod_fastcgi_handle_trigger;
26089 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c 2006-03-07 14:06:26.000000000 +0200
26090 +++ lighttpd-1.4.12/src/mod_flv_streaming.c 2006-07-16 00:26:04.000000000 +0300
26091 @@ -23,35 +23,35 @@
26101 plugin_config **config_storage;
26103 - plugin_config conf;
26105 + plugin_config conf;
26108 /* init the plugin data */
26109 INIT_FUNC(mod_flv_streaming_init) {
26113 p = calloc(1, sizeof(*p));
26116 p->query_str = buffer_init();
26117 p->get_params = array_init();
26123 /* detroy the plugin data */
26124 FREE_FUNC(mod_flv_streaming_free) {
26125 plugin_data *p = p_d;
26130 if (!p) return HANDLER_GO_ON;
26133 if (p->config_storage) {
26136 @@ -59,19 +59,19 @@
26137 plugin_config *s = p->config_storage[i];
26142 array_free(s->extensions);
26147 free(p->config_storage);
26151 buffer_free(p->query_str);
26152 array_free(p->get_params);
26158 return HANDLER_GO_ON;
26161 @@ -80,83 +80,80 @@
26162 SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
26163 plugin_data *p = p_d;
26166 - config_values_t cv[] = {
26168 + config_values_t cv[] = {
26169 { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
26170 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26174 if (!p) return HANDLER_ERROR;
26177 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26180 for (i = 0; i < srv->config_context->used; i++) {
26184 s = calloc(1, sizeof(plugin_config));
26185 s->extensions = array_init();
26188 cv[0].destination = s->extensions;
26191 p->config_storage[i] = s;
26194 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26195 return HANDLER_ERROR;
26200 return HANDLER_GO_ON;
26203 -#define PATCH(x) \
26204 - p->conf.x = s->x;
26205 static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
26207 plugin_config *s = p->config_storage[0];
26209 - PATCH(extensions);
26212 + PATCH_OPTION(extensions);
26214 /* skip the first, the global context */
26215 for (i = 1; i < srv->config_context->used; i++) {
26216 data_config *dc = (data_config *)srv->config_context->data[i];
26217 s = p->config_storage[i];
26220 /* condition didn't match */
26221 if (!config_check_cond(srv, con, dc)) continue;
26225 for (j = 0; j < dc->value->used; j++) {
26226 data_unset *du = dc->value->data[j];
26229 if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
26230 - PATCH(extensions);
26231 + PATCH_OPTION(extensions);
26241 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
26242 +static int split_get_params(array *get_params, buffer *qrystr) {
26245 char *key = NULL, *val = NULL;
26251 /* we need the \0 */
26252 for (i = 0; i < qrystr->used; i++) {
26253 switch(qrystr->ptr[i]) {
26256 val = qrystr->ptr + i + 1;
26259 qrystr->ptr[i] = '\0';
26268 case '\0': /* fin symbol */
26269 @@ -167,7 +164,7 @@
26270 /* terminate the value */
26271 qrystr->ptr[i] = '\0';
26273 - if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
26274 + if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
26275 ds = data_string_init();
26277 buffer_copy_string_len(ds->key, key, strlen(key));
26278 @@ -175,14 +172,14 @@
26280 array_insert_unique(get_params, (data_unset *)ds);
26284 key = qrystr->ptr + i + 1;
26295 @@ -190,34 +187,34 @@
26296 plugin_data *p = p_d;
26303 if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
26306 mod_flv_streaming_patch_connection(srv, con, p);
26308 s_len = con->physical.path->used - 1;
26311 for (k = 0; k < p->conf.extensions->used; k++) {
26312 data_string *ds = (data_string *)p->conf.extensions->data[k];
26313 int ct_len = ds->value->used - 1;
26316 if (ct_len > s_len) continue;
26317 if (ds->value->used == 0) continue;
26320 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
26321 data_string *get_param;
26322 stat_cache_entry *sce = NULL;
26326 - /* if there is a start=[0-9]+ in the header use it as start,
26327 + /* if there is a start=[0-9]+ in the header use it as start,
26328 * otherwise send the full file */
26330 array_reset(p->get_params);
26331 buffer_copy_string_buffer(p->query_str, con->uri.query);
26332 - split_get_params(srv, con, p->get_params, p->query_str);
26333 + split_get_params(p->get_params, p->query_str);
26335 if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
26336 return HANDLER_GO_ON;
26337 @@ -256,7 +253,7 @@
26338 return HANDLER_FINISHED;
26344 return HANDLER_GO_ON;
26346 @@ -266,13 +263,13 @@
26347 int mod_flv_streaming_plugin_init(plugin *p) {
26348 p->version = LIGHTTPD_VERSION_ID;
26349 p->name = buffer_init_string("flv_streaming");
26352 p->init = mod_flv_streaming_init;
26353 p->handle_physical = mod_flv_streaming_path_handler;
26354 p->set_defaults = mod_flv_streaming_set_defaults;
26355 p->cleanup = mod_flv_streaming_free;
26363 --- ../lighttpd-1.4.11/src/mod_indexfile.c 2005-09-30 01:08:53.000000000 +0300
26364 +++ lighttpd-1.4.12/src/mod_indexfile.c 2006-07-16 00:26:04.000000000 +0300
26367 #include "stat_cache.h"
26369 +#include "sys-strings.h"
26370 +#include "sys-files.h"
26371 /* plugin config for all request/connections */
26374 @@ -20,51 +22,51 @@
26383 plugin_config **config_storage;
26385 - plugin_config conf;
26387 + plugin_config conf;
26390 /* init the plugin data */
26391 INIT_FUNC(mod_indexfile_init) {
26395 p = calloc(1, sizeof(*p));
26398 p->tmp_buf = buffer_init();
26404 /* detroy the plugin data */
26405 FREE_FUNC(mod_indexfile_free) {
26406 plugin_data *p = p_d;
26411 if (!p) return HANDLER_GO_ON;
26414 if (p->config_storage) {
26416 for (i = 0; i < srv->config_context->used; i++) {
26417 plugin_config *s = p->config_storage[i];
26422 array_free(s->indexfiles);
26427 free(p->config_storage);
26431 buffer_free(p->tmp_buf);
26437 return HANDLER_GO_ON;
26440 @@ -73,131 +75,139 @@
26441 SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
26442 plugin_data *p = p_d;
26445 - config_values_t cv[] = {
26447 + config_values_t cv[] = {
26448 { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
26449 { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
26450 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26454 if (!p) return HANDLER_ERROR;
26457 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26460 for (i = 0; i < srv->config_context->used; i++) {
26464 s = calloc(1, sizeof(plugin_config));
26465 s->indexfiles = array_init();
26468 cv[0].destination = s->indexfiles;
26469 cv[1].destination = s->indexfiles; /* old name for [0] */
26472 p->config_storage[i] = s;
26475 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26476 return HANDLER_ERROR;
26481 return HANDLER_GO_ON;
26484 -#define PATCH(x) \
26485 - p->conf.x = s->x;
26486 static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
26488 plugin_config *s = p->config_storage[0];
26490 - PATCH(indexfiles);
26493 + PATCH_OPTION(indexfiles);
26495 /* skip the first, the global context */
26496 for (i = 1; i < srv->config_context->used; i++) {
26497 data_config *dc = (data_config *)srv->config_context->data[i];
26498 s = p->config_storage[i];
26501 /* condition didn't match */
26502 if (!config_check_cond(srv, con, dc)) continue;
26506 for (j = 0; j < dc->value->used; j++) {
26507 data_unset *du = dc->value->data[j];
26510 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
26511 - PATCH(indexfiles);
26512 + PATCH_OPTION(indexfiles);
26513 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
26514 - PATCH(indexfiles);
26515 + PATCH_OPTION(indexfiles);
26525 URIHANDLER_FUNC(mod_indexfile_subrequest) {
26526 plugin_data *p = p_d;
26528 stat_cache_entry *sce = NULL;
26531 if (con->uri.path->used == 0) return HANDLER_GO_ON;
26532 if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
26535 mod_indexfile_patch_connection(srv, con, p);
26538 + /* is the physical-path really a dir ? */
26539 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
26540 + return HANDLER_GO_ON;
26543 + if (!S_ISDIR(sce->st.st_mode)) {
26544 + return HANDLER_GO_ON;
26547 if (con->conf.log_request_handling) {
26548 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile");
26549 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
26555 for (k = 0; k < p->conf.indexfiles->used; k++) {
26556 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
26559 if (ds->value && ds->value->ptr[0] == '/') {
26560 - /* if the index-file starts with a prefix as use this file as
26561 + /* if the index-file starts with a prefix as use this file as
26562 * index-generator */
26563 buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
26565 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
26566 + PATHNAME_APPEND_SLASH(p->tmp_buf);
26568 buffer_append_string_buffer(p->tmp_buf, ds->value);
26571 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26572 if (errno == EACCES) {
26573 con->http_status = 403;
26574 buffer_reset(con->physical.path);
26577 return HANDLER_FINISHED;
26581 if (errno != ENOENT &&
26582 errno != ENOTDIR) {
26583 /* we have no idea what happend. let's tell the user so. */
26586 con->http_status = 500;
26589 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
26590 "file not found ... or so: ", strerror(errno),
26592 "->", con->physical.path);
26595 buffer_reset(con->physical.path);
26598 return HANDLER_FINISHED;
26604 /* rewrite uri.path to the real path (/ -> /index.php) */
26605 buffer_append_string_buffer(con->uri.path, ds->value);
26606 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
26609 /* fce is already set up a few lines above */
26612 return HANDLER_GO_ON;
26617 return HANDLER_GO_ON;
26619 @@ -207,13 +217,13 @@
26620 int mod_indexfile_plugin_init(plugin *p) {
26621 p->version = LIGHTTPD_VERSION_ID;
26622 p->name = buffer_init_string("indexfile");
26625 p->init = mod_indexfile_init;
26626 p->handle_subrequest_start = mod_indexfile_subrequest;
26627 p->set_defaults = mod_indexfile_set_defaults;
26628 p->cleanup = mod_indexfile_free;
26636 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c 2006-01-14 20:35:10.000000000 +0200
26637 +++ lighttpd-1.4.12/src/mod_mysql_vhost.c 2006-07-20 00:57:19.000000000 +0300
26639 -#include <unistd.h>
26643 -#include <strings.h>
26644 +#include <string.h>
26646 #ifdef HAVE_CONFIG_H
26647 #include "config.h"
26650 +#ifdef HAVE_MYSQL_H
26651 +# ifdef HAVE_LIBMYSQL
26652 +# define HAVE_MYSQL
26659 @@ -16,61 +21,40 @@
26662 #include "stat_cache.h"
26663 -#ifdef DEBUG_MOD_MYSQL_VHOST
26666 +#include "sys-files.h"
26669 - * Plugin for lighttpd to use MySQL
26670 - * for domain to directory lookups,
26671 - * i.e virtual hosts (vhosts).
26673 - * Optionally sets fcgi_offset and fcgi_arg
26674 - * in preparation for fcgi.c to handle
26675 - * per-user fcgi chroot jails.
26677 - * /ada@riksnet.se 2004-12-06
26679 +#include "mod_sql_vhost_core.h"
26683 +#define CORE_PLUGIN "mod_sql_vhost_core"
26693 - buffer *hostname;
26694 - unsigned short port;
26698 buffer *mysql_post;
26700 + mod_sql_vhost_core_plugin_config *core;
26703 /* global plugin data */
26711 plugin_config **config_storage;
26713 - plugin_config conf;
26715 + plugin_config conf;
26718 -/* per connection plugin data */
26720 - buffer *server_name;
26721 - buffer *document_root;
26722 - buffer *fcgi_arg;
26723 - unsigned fcgi_offset;
26724 -} plugin_connection_data;
26725 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost);
26727 /* init the plugin data */
26728 INIT_FUNC(mod_mysql_vhost_init) {
26732 p = calloc(1, sizeof(*p));
26734 p->tmp_buf = buffer_init();
26735 @@ -83,144 +67,77 @@
26736 plugin_data *p = p_d;
26741 - log_error_write(srv, __FILE__, __LINE__, "ss",
26742 - "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
26745 if (!p) return HANDLER_GO_ON;
26748 if (p->config_storage) {
26750 for (i = 0; i < srv->config_context->used; i++) {
26751 plugin_config *s = p->config_storage[i];
26756 mysql_close(s->mysql);
26758 - buffer_free(s->mydb);
26759 - buffer_free(s->myuser);
26760 - buffer_free(s->mypass);
26761 - buffer_free(s->mysock);
26763 buffer_free(s->mysql_pre);
26764 buffer_free(s->mysql_post);
26769 free(p->config_storage);
26771 buffer_free(p->tmp_buf);
26775 - return HANDLER_GO_ON;
26778 -/* handle the plugin per connection data */
26779 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
26781 - plugin_data *p = p_d;
26782 - plugin_connection_data *c = con->plugin_ctx[p->id];
26787 - log_error_write(srv, __FILE__, __LINE__, "ss",
26788 - "mod_mysql_connection_data", c ? "old" : "NEW");
26792 - c = calloc(1, sizeof(*c));
26794 - c->server_name = buffer_init();
26795 - c->document_root = buffer_init();
26796 - c->fcgi_arg = buffer_init();
26797 - c->fcgi_offset = 0;
26799 - return con->plugin_ctx[p->id] = c;
26802 -/* destroy the plugin per connection data */
26803 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
26804 - plugin_data *p = p_d;
26805 - plugin_connection_data *c = con->plugin_ctx[p->id];
26810 - log_error_write(srv, __FILE__, __LINE__, "ss",
26811 - "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
26814 - if (!c) return HANDLER_GO_ON;
26816 - buffer_free(c->server_name);
26817 - buffer_free(c->document_root);
26818 - buffer_free(c->fcgi_arg);
26819 - c->fcgi_offset = 0;
26824 - con->plugin_ctx[p->id] = NULL;
26825 return HANDLER_GO_ON;
26828 /* set configuration values */
26829 SERVER_FUNC(mod_mysql_vhost_set_defaults) {
26830 plugin_data *p = p_d;
26831 + mod_sql_vhost_core_plugin_data *core_config;
26836 - config_values_t cv[] = {
26837 - { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26838 - { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26839 - { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26840 - { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26841 - { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26842 - { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
26843 - { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },
26844 - { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26847 + /* our very own plugin storage, one entry for each conditional
26849 + * srv->config_context->used is the number of conditionals
26851 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26854 + /* get the config of the core-plugin */
26855 + core_config = plugin_get_config(srv, CORE_PLUGIN);
26858 + /* walk through all conditionals and check for assignments */
26859 for (i = 0; i < srv->config_context->used; i++) {
26866 + /* get the config from the core plugin for this conditional-context */
26867 s = calloc(1, sizeof(plugin_config));
26868 - s->mydb = buffer_init();
26869 - s->myuser = buffer_init();
26870 - s->mypass = buffer_init();
26871 - s->mysock = buffer_init();
26872 - s->hostname = buffer_init();
26873 - s->port = 0; /* default port for mysql */
26874 - sel = buffer_init();
26877 + s->core = core_config->config_storage[i];
26881 s->mysql_pre = buffer_init();
26882 s->mysql_post = buffer_init();
26884 - cv[0].destination = s->mydb;
26885 - cv[1].destination = s->myuser;
26886 - cv[2].destination = s->mypass;
26887 - cv[3].destination = s->mysock;
26888 - cv[4].destination = sel;
26889 - cv[5].destination = s->hostname;
26890 - cv[6].destination = &(s->port);
26893 p->config_storage[i] = s;
26895 - if (config_insert_values_global(srv,
26896 - ((data_config *)srv->config_context->data[i])->value,
26897 - cv)) return HANDLER_ERROR;
26899 - s->mysql_pre = buffer_init();
26900 - s->mysql_post = buffer_init();
26903 + /* check if we are the plugin for this backend */
26904 + if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
26906 + /* attach us to the core-plugin */
26907 + s->core->backend_data = p;
26908 + s->core->get_vhost = mod_mysql_vhost_get_vhost;
26910 + sel = buffer_init();
26911 + buffer_copy_string_buffer(sel, s->core->select_vhost);
26913 if (sel->used && (qmark = index(sel->ptr, '?'))) {
26915 buffer_copy_string(s->mysql_pre, sel->ptr);
26916 @@ -228,35 +145,38 @@
26918 buffer_copy_string_buffer(s->mysql_pre, sel);
26921 + buffer_free(sel);
26930 * - password, default: empty
26931 * - socket, default: mysql default
26932 * - hostname, if set overrides socket
26933 * - port, default: 3306
26937 /* all have to be set */
26938 - if (!(buffer_is_empty(s->myuser) ||
26939 - buffer_is_empty(s->mydb))) {
26940 + if (!(buffer_is_empty(s->core->user) ||
26941 + buffer_is_empty(s->core->db))) {
26946 if (NULL == (s->mysql = mysql_init(NULL))) {
26947 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
26950 return HANDLER_ERROR;
26952 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
26954 - if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
26955 - FOO(mydb), s->port, FOO(mysock), 0)) {
26956 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
26958 + s->mysql->free_me = 1;
26960 + if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
26961 + FOO(db), s->core->port, FOO(sock), 0)) {
26962 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
26965 return HANDLER_ERROR;
26968 @@ -265,61 +185,47 @@
26969 /* otherwise we cannot be sure that mysql is fd i-1 */
26970 if (-1 == (fd = open("/dev/null", 0))) {
26972 - fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26973 + fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26982 return HANDLER_GO_ON;
26985 -#define PATCH(x) \
26986 - p->conf.x = s->x;
26987 static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
26990 plugin_config *s = p->config_storage[0];
26992 - PATCH(mysql_pre);
26993 - PATCH(mysql_post);
26999 + PATCH_OPTION(mysql_pre);
27000 + PATCH_OPTION(mysql_post);
27001 + PATCH_OPTION(mysql);
27003 /* skip the first, the global context */
27004 for (i = 1; i < srv->config_context->used; i++) {
27005 data_config *dc = (data_config *)srv->config_context->data[i];
27006 s = p->config_storage[i];
27009 /* condition didn't match */
27010 if (!config_check_cond(srv, con, dc)) continue;
27012 - /* merge config */
27013 - for (j = 0; j < dc->value->used; j++) {
27014 - data_unset *du = dc->value->data[j];
27016 - if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
27017 - PATCH(mysql_pre);
27018 - PATCH(mysql_post);
27025 + PATCH_OPTION(mysql);
27026 + PATCH_OPTION(mysql_pre);
27027 + PATCH_OPTION(mysql_post);
27037 -/* handle document root request */
27038 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
27040 + * get the vhost info from the database
27042 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
27043 plugin_data *p = p_d;
27044 - plugin_connection_data *c;
27045 - stat_cache_entry *sce;
27049 @@ -332,13 +238,6 @@
27051 if (!p->conf.mysql) return HANDLER_GO_ON;
27053 - /* sets up connection data if not done yet */
27054 - c = mod_mysql_vhost_connection_data(srv, con, p_d);
27056 - /* check if cached this connection */
27057 - if (c->server_name->used && /* con->uri.authority->used && */
27058 - buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
27060 /* build and run SQL query */
27061 buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
27062 if (p->conf.mysql_post->used) {
27063 @@ -347,77 +246,43 @@
27065 if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
27066 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
27069 + mysql_free_result(result);
27070 + return HANDLER_GO_ON;
27072 result = mysql_store_result(p->conf.mysql);
27073 cols = mysql_num_fields(result);
27074 row = mysql_fetch_row(result);
27076 if (!row || cols < 1) {
27077 /* no such virtual host */
27078 mysql_free_result(result);
27079 return HANDLER_GO_ON;
27082 - /* sanity check that really is a directory */
27083 - buffer_copy_string(p->tmp_buf, row[0]);
27084 - BUFFER_APPEND_SLASH(p->tmp_buf);
27086 - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
27087 - log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
27090 - if (!S_ISDIR(sce->st.st_mode)) {
27091 - log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
27094 + buffer_copy_string(docroot, row[0]);
27096 - /* cache the data */
27097 - buffer_copy_string_buffer(c->server_name, con->uri.authority);
27098 - buffer_copy_string_buffer(c->document_root, p->tmp_buf);
27100 - /* fcgi_offset and fcgi_arg are optional */
27101 - if (cols > 1 && row[1]) {
27102 - c->fcgi_offset = atoi(row[1]);
27104 - if (cols > 2 && row[2]) {
27105 - buffer_copy_string(c->fcgi_arg, row[2]);
27107 - c->fcgi_arg->used = 0;
27110 - c->fcgi_offset = c->fcgi_arg->used = 0;
27112 mysql_free_result(result);
27114 - /* fix virtual server and docroot */
27115 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
27116 - buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
27119 - log_error_write(srv, __FILE__, __LINE__, "sbbdb",
27120 - result ? "NOT CACHED" : "cached",
27121 - con->server_name, con->physical.doc_root,
27122 - c->fcgi_offset, c->fcgi_arg);
27124 - return HANDLER_GO_ON;
27126 -ERR500: if (result) mysql_free_result(result);
27127 - con->http_status = 500; /* Internal Error */
27128 - return HANDLER_FINISHED;
27129 + return HANDLER_GO_ON;
27132 /* this function is called at dlopen() time and inits the callbacks */
27133 int mod_mysql_vhost_plugin_init(plugin *p) {
27136 p->version = LIGHTTPD_VERSION_ID;
27137 p->name = buffer_init_string("mysql_vhost");
27139 p->init = mod_mysql_vhost_init;
27140 p->cleanup = mod_mysql_vhost_cleanup;
27141 - p->handle_request_done = mod_mysql_vhost_handle_connection_close;
27143 p->set_defaults = mod_mysql_vhost_set_defaults;
27144 - p->handle_docroot = mod_mysql_vhost_handle_docroot;
27146 + ds = data_string_init();
27147 + buffer_copy_string(ds->value, CORE_PLUGIN);
27148 + array_insert_unique(p->required_plugins, (data_unset *)ds);
27153 --- ../lighttpd-1.4.11/src/mod_proxy.c 2006-01-31 13:01:22.000000000 +0200
27154 +++ lighttpd-1.4.12/src/mod_proxy.c 2006-07-19 20:02:55.000000000 +0300
27156 #include <sys/types.h>
27158 -#include <unistd.h>
27161 #include <string.h>
27164 #include "inet_ntop_cache.h"
27166 +#include "network.h"
27168 +#include "http_resp.h"
27175 #include "sys-socket.h"
27176 +#include "sys-files.h"
27177 +#include "sys-strings.h"
27179 #define data_proxy data_fastcgi
27180 #define data_proxy_init data_fastcgi_init
27181 @@ -38,22 +42,25 @@
27182 #define PROXY_RETRY_TIMEOUT 60
27186 - * the proxy module is based on the fastcgi module
27189 + * the proxy module is based on the fastcgi module
27191 * 28.06.2004 Jan Kneschke The first release
27192 * 01.07.2004 Evgeny Rodichev Several bugfixes and cleanups
27193 * - co-ordinate up- and downstream flows correctly (proxy_demux_response
27194 * and proxy_handle_fdevent)
27195 * - correctly transfer upstream http_response_status;
27196 * - some unused structures removed.
27199 * TODO: - delay upstream read if write_queue is too large
27200 * (to prevent memory eating, like in apache). Shoud be
27202 * - persistent connection with upstream servers
27209 PROXY_BALANCE_UNSET,
27210 PROXY_BALANCE_FAIR,
27211 @@ -66,26 +73,33 @@
27214 proxy_balance_t balance;
27216 + array *last_used_backends; /* "extension" : last_used_backend */
27223 buffer *parse_response;
27224 buffer *balance_buf;
27229 + array *ignore_headers;
27231 plugin_config **config_storage;
27234 plugin_config conf;
27238 - PROXY_STATE_INIT,
27239 - PROXY_STATE_CONNECT,
27240 - PROXY_STATE_PREPARE_WRITE,
27241 - PROXY_STATE_WRITE,
27242 - PROXY_STATE_READ,
27243 - PROXY_STATE_ERROR
27245 + PROXY_STATE_INIT,
27246 + PROXY_STATE_CONNECT,
27247 + PROXY_STATE_PREPARE_WRITE,
27248 + PROXY_STATE_WRITE,
27249 + PROXY_STATE_RESPONSE_HEADER,
27250 + PROXY_STATE_RESPONSE_CONTENT,
27251 + PROXY_STATE_ERROR
27252 } proxy_connection_state_t;
27254 enum { PROXY_STDOUT, PROXY_END_REQUEST };
27255 @@ -93,19 +107,16 @@
27257 proxy_connection_state_t state;
27258 time_t state_timestamp;
27263 - buffer *response;
27264 - buffer *response_header;
27268 - int fd; /* fd to the proxy process */
27269 - int fde_ndx; /* index into the fd-event buffer */
27272 + iosocket *sock; /* fd to the proxy process */
27274 size_t path_info_offset; /* start of path_info in uri.path */
27277 connection *remote_conn; /* dump pointer */
27278 plugin_data *plugin_data; /* dump pointer */
27280 @@ -116,69 +127,89 @@
27282 static handler_ctx * handler_ctx_init() {
27283 handler_ctx * hctx;
27287 hctx = calloc(1, sizeof(*hctx));
27290 hctx->state = PROXY_STATE_INIT;
27293 - hctx->response = buffer_init();
27294 - hctx->response_header = buffer_init();
27296 hctx->wb = chunkqueue_init();
27297 + hctx->rb = chunkqueue_init();
27299 + hctx->sock = iosocket_init();
27302 - hctx->fde_ndx = -1;
27307 static void handler_ctx_free(handler_ctx *hctx) {
27308 - buffer_free(hctx->response);
27309 - buffer_free(hctx->response_header);
27310 chunkqueue_free(hctx->wb);
27312 + chunkqueue_free(hctx->rb);
27314 + iosocket_free(hctx->sock);
27319 INIT_FUNC(mod_proxy_init) {
27324 + char *hop2hop_headers[] = {
27331 p = calloc(1, sizeof(*p));
27333 - p->parse_response = buffer_init();
27335 p->balance_buf = buffer_init();
27337 + p->ignore_headers = array_init();
27338 + p->resp = http_response_init();
27340 + for (i = 0; hop2hop_headers[i]; i++) {
27343 + if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
27344 + ds = data_string_init();
27347 + buffer_copy_string(ds->key, hop2hop_headers[i]);
27348 + buffer_copy_string(ds->value, hop2hop_headers[i]);
27349 + array_insert_unique(p->ignore_headers, (data_unset *)ds);
27356 FREE_FUNC(mod_proxy_free) {
27357 plugin_data *p = p_d;
27362 - buffer_free(p->parse_response);
27363 - buffer_free(p->balance_buf);
27365 if (p->config_storage) {
27367 for (i = 0; i < srv->config_context->used; i++) {
27368 plugin_config *s = p->config_storage[i];
27373 array_free(s->extensions);
27375 + array_free(s->last_used_backends);
27380 free(p->config_storage);
27384 + array_free(p->ignore_headers);
27385 + buffer_free(p->balance_buf);
27386 + http_response_free(p->resp);
27391 return HANDLER_GO_ON;
27394 @@ -186,37 +217,38 @@
27395 plugin_data *p = p_d;
27399 - config_values_t cv[] = {
27401 + config_values_t cv[] = {
27402 { "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
27403 { "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
27404 { "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
27405 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27409 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
27412 for (i = 0; i < srv->config_context->used; i++) {
27417 s = malloc(sizeof(plugin_config));
27418 - s->extensions = array_init();
27419 + s->extensions = array_init();
27420 + s->last_used_backends = array_init();
27424 cv[0].destination = s->extensions;
27425 cv[1].destination = &(s->debug);
27426 cv[2].destination = p->balance_buf;
27428 buffer_reset(p->balance_buf);
27431 p->config_storage[i] = s;
27432 ca = ((data_config *)srv->config_context->data[i])->value;
27435 if (0 != config_insert_values_global(srv, ca, cv)) {
27436 return HANDLER_ERROR;
27440 if (buffer_is_empty(p->balance_buf)) {
27441 s->balance = PROXY_BALANCE_FAIR;
27442 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
27443 @@ -226,99 +258,99 @@
27444 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
27445 s->balance = PROXY_BALANCE_HASH;
27447 - log_error_write(srv, __FILE__, __LINE__, "sb",
27448 - "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27449 + log_error_write(srv, __FILE__, __LINE__, "sb",
27450 + "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27451 return HANDLER_ERROR;
27454 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
27456 data_array *da = (data_array *)du;
27459 if (du->type != TYPE_ARRAY) {
27460 - log_error_write(srv, __FILE__, __LINE__, "sss",
27461 + log_error_write(srv, __FILE__, __LINE__, "sss",
27462 "unexpected type for key: ", "proxy.server", "array of strings");
27465 return HANDLER_ERROR;
27471 * proxy.server = ( "<ext>" => ...,
27476 for (j = 0; j < da->value->used; j++) {
27477 data_array *da_ext = (data_array *)da->value->data[j];
27481 if (da_ext->type != TYPE_ARRAY) {
27482 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
27483 - "unexpected type for key: ", "proxy.server",
27484 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
27485 + "unexpected type for key: ", "proxy.server",
27486 "[", da->value->data[j]->key, "](string)");
27489 return HANDLER_ERROR;
27493 - * proxy.server = ( "<ext>" =>
27494 - * ( "<host>" => ( ... ),
27497 + * proxy.server = ( "<ext>" =>
27498 + * ( "<host>" => ( ... ),
27499 * "<host>" => ( ... )
27506 for (n = 0; n < da_ext->value->used; n++) {
27507 data_array *da_host = (data_array *)da_ext->value->data[n];
27513 - config_values_t pcv[] = {
27515 + config_values_t pcv[] = {
27516 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
27517 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
27518 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27522 if (da_host->type != TYPE_ARRAY) {
27523 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27524 - "unexpected type for key:",
27526 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27527 + "unexpected type for key:",
27529 "[", da_ext->value->data[n]->key, "](string)");
27532 return HANDLER_ERROR;
27536 df = data_proxy_init();
27542 buffer_copy_string_buffer(df->key, da_host->key);
27545 pcv[0].destination = df->host;
27546 pcv[1].destination = &(df->port);
27549 if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
27550 return HANDLER_ERROR;
27554 if (buffer_is_empty(df->host)) {
27555 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27556 - "missing key (string):",
27557 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27558 + "missing key (string):",
27565 return HANDLER_ERROR;
27569 /* if extension already exists, take it */
27572 if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
27573 dfa = data_array_init();
27576 buffer_copy_string_buffer(dfa->key, da_ext->key);
27579 array_insert_unique(dfa->value, (data_unset *)df);
27580 array_insert_unique(s->extensions, (data_unset *)dfa);
27582 @@ -328,67 +360,76 @@
27588 return HANDLER_GO_ON;
27591 void proxy_connection_close(server *srv, handler_ctx *hctx) {
27596 if (NULL == hctx) return;
27599 p = hctx->plugin_data;
27600 con = hctx->remote_conn;
27602 - if (hctx->fd != -1) {
27603 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27604 - fdevent_unregister(srv->ev, hctx->fd);
27607 + if (hctx->sock->fd != -1) {
27608 + fdevent_event_del(srv->ev, hctx->sock);
27609 + fdevent_unregister(srv->ev, hctx->sock);
27611 + close(hctx->sock->fd);
27616 handler_ctx_free(hctx);
27617 - con->plugin_ctx[p->id] = NULL;
27618 + con->plugin_ctx[p->id] = NULL;
27621 static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
27622 struct sockaddr *proxy_addr;
27623 struct sockaddr_in proxy_addr_in;
27627 plugin_data *p = hctx->plugin_data;
27628 data_proxy *host= hctx->host;
27629 - int proxy_fd = hctx->fd;
27631 + int proxy_fd = hctx->sock->fd;
27633 memset(&proxy_addr, 0, sizeof(proxy_addr));
27636 proxy_addr_in.sin_family = AF_INET;
27637 proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
27638 proxy_addr_in.sin_port = htons(host->port);
27639 servlen = sizeof(proxy_addr_in);
27642 proxy_addr = (struct sockaddr *) &proxy_addr_in;
27645 if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
27646 - if (errno == EINPROGRESS || errno == EALREADY) {
27648 + errno = WSAGetLastError();
27652 + case WSAEWOULDBLOCK:
27654 + case EINPROGRESS:
27656 if (p->conf.debug) {
27657 - log_error_write(srv, __FILE__, __LINE__, "sd",
27658 + log_error_write(srv, __FILE__, __LINE__, "sd",
27659 "connect delayed:", proxy_fd);
27666 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
27669 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
27670 "connect failed:", proxy_fd, strerror(errno), errno);
27676 + fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
27677 if (p->conf.debug) {
27678 - log_error_write(srv, __FILE__, __LINE__, "sd",
27679 + log_error_write(srv, __FILE__, __LINE__, "sd",
27680 "connect succeeded: ", proxy_fd);
27683 @@ -396,51 +437,52 @@
27686 void proxy_set_header(connection *con, const char *key, const char *value) {
27687 - data_string *ds_dst;
27688 + data_string *ds_dst;
27690 - if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27691 - ds_dst = data_string_init();
27694 - buffer_copy_string(ds_dst->key, key);
27695 - buffer_copy_string(ds_dst->value, value);
27696 - array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27697 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27698 + ds_dst = data_string_init();
27701 + buffer_copy_string(ds_dst->key, key);
27702 + buffer_copy_string(ds_dst->value, value);
27703 + array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27706 void proxy_append_header(connection *con, const char *key, const char *value) {
27707 - data_string *ds_dst;
27708 + data_string *ds_dst;
27710 - if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27711 - ds_dst = data_string_init();
27714 - buffer_copy_string(ds_dst->key, key);
27715 - buffer_append_string(ds_dst->value, value);
27716 - array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27717 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27718 + ds_dst = data_string_init();
27721 + buffer_copy_string(ds_dst->key, key);
27722 + buffer_append_string(ds_dst->value, value);
27723 + array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27727 static int proxy_create_env(server *srv, handler_ctx *hctx) {
27731 connection *con = hctx->remote_conn;
27732 + plugin_data *p = hctx->plugin_data;
27738 b = chunkqueue_get_append_buffer(hctx->wb);
27742 buffer_copy_string(b, get_http_method_name(con->request.http_method));
27743 BUFFER_APPEND_STRING_CONST(b, " ");
27746 buffer_append_string_buffer(b, con->request.uri);
27747 BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
27749 proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
27750 - /* http_host is NOT is just a pointer to a buffer
27751 + /* http_host is NOT is just a pointer to a buffer
27752 * which is NULL if it is not set */
27753 - if (con->request.http_host &&
27754 + if (con->request.http_host &&
27755 !buffer_is_empty(con->request.http_host)) {
27756 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
27758 @@ -449,24 +491,25 @@
27759 /* request header */
27760 for (i = 0; i < con->request.headers->used; i++) {
27764 ds = (data_string *)con->request.headers->data[i];
27766 - if (ds->value->used && ds->key->used) {
27767 - if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27769 - buffer_append_string_buffer(b, ds->key);
27770 - BUFFER_APPEND_STRING_CONST(b, ": ");
27771 - buffer_append_string_buffer(b, ds->value);
27772 - BUFFER_APPEND_STRING_CONST(b, "\r\n");
27775 + if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
27777 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27778 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
27780 + buffer_append_string_buffer(b, ds->key);
27781 + BUFFER_APPEND_STRING_CONST(b, ": ");
27782 + buffer_append_string_buffer(b, ds->value);
27783 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
27787 BUFFER_APPEND_STRING_CONST(b, "\r\n");
27790 hctx->wb->bytes_in += b->used - 1;
27794 if (con->request.content_length) {
27795 chunkqueue *req_cq = con->request_content_queue;
27797 @@ -479,7 +522,7 @@
27799 /* we announce toWrite octects
27800 * now take all the request_content chunk that we need to fill this request
27804 switch (req_c->type) {
27806 @@ -507,223 +550,150 @@
27808 req_c->offset += weHave;
27809 req_cq->bytes_out += weHave;
27812 hctx->wb->bytes_in += weHave;
27829 static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
27830 hctx->state = state;
27831 hctx->state_timestamp = srv->cur_ts;
27837 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27839 - int http_response_status = -1;
27843 - /* \r\n -> \0\0 */
27845 - buffer_copy_string_buffer(p->parse_response, in);
27847 - for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
27848 - char *key, *value;
27856 - if (-1 == http_response_status) {
27857 - /* The first line of a Response message is the Status-Line */
27859 - for (key=s; *key && *key != ' '; key++);
27862 - http_response_status = (int) strtol(key, NULL, 10);
27863 - if (http_response_status <= 0) http_response_status = 502;
27865 - http_response_status = 502;
27868 - con->http_status = http_response_status;
27869 - con->parsed_response |= HTTP_STATUS;
27873 - if (NULL == (value = strchr(s, ':'))) {
27874 - /* now we expect: "<key>: <value>\n" */
27880 - key_len = value - key;
27884 - while (*value == ' ' || *value == '\t') value++;
27888 - switch(key_len) {
27890 - if (0 == strncasecmp(key, "Date", key_len)) {
27891 - con->parsed_response |= HTTP_DATE;
27895 - if (0 == strncasecmp(key, "Location", key_len)) {
27896 - con->parsed_response |= HTTP_LOCATION;
27900 - if (0 == strncasecmp(key, "Connection", key_len)) {
27905 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
27906 - con->response.content_length = strtol(value, NULL, 10);
27907 - con->parsed_response |= HTTP_CONTENT_LENGTH;
27914 - if (copy_header) {
27915 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27916 - ds = data_response_init();
27918 - buffer_copy_string_len(ds->key, key, key_len);
27919 - buffer_copy_string(ds->value, value);
27921 - array_insert_unique(con->response.headers, (data_unset *)ds);
27929 static int proxy_demux_response(server *srv, handler_ctx *hctx) {
27934 plugin_data *p = hctx->plugin_data;
27935 connection *con = hctx->remote_conn;
27936 - int proxy_fd = hctx->fd;
27938 - /* check how much we have to read */
27939 - if (ioctl(hctx->fd, FIONREAD, &b)) {
27940 - log_error_write(srv, __FILE__, __LINE__, "sd",
27941 - "ioctl failed: ",
27943 + chunkqueue *next_queue = NULL;
27946 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
27947 + case NETWORK_STATUS_SUCCESS:
27948 + /* we got content */
27950 + case NETWORK_STATUS_WAIT_FOR_EVENT:
27952 + case NETWORK_STATUS_CONNECTION_CLOSE:
27953 + /* we are done, get out of here */
27954 + con->file_finished = 1;
27956 + /* close the chunk-queue with a empty chunk */
27964 + /* looks like we got some content
27966 + * split off the header from the incoming stream
27969 - if (p->conf.debug) {
27970 - log_error_write(srv, __FILE__, __LINE__, "sd",
27971 - "proxy - have to read:", b);
27973 + if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
27975 + int have_content_length = 0;
27978 - if (hctx->response->used == 0) {
27979 - /* avoid too small buffer */
27980 - buffer_prepare_append(hctx->response, b + 1);
27981 - hctx->response->used = 1;
27983 - buffer_prepare_append(hctx->response, hctx->response->used + b);
27986 - if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
27987 - log_error_write(srv, __FILE__, __LINE__, "sds",
27988 - "unexpected end-of-file (perhaps the proxy process died):",
27989 - proxy_fd, strerror(errno));
27993 - /* this should be catched by the b > 0 above */
27996 - hctx->response->used += r;
27997 - hctx->response->ptr[hctx->response->used - 1] = '\0';
28000 - log_error_write(srv, __FILE__, __LINE__, "sdsbs",
28001 - "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
28003 + http_response_reset(p->resp);
28005 - if (0 == con->got_response) {
28006 - con->got_response = 1;
28007 - buffer_prepare_copy(hctx->response_header, 128);
28010 - if (0 == con->file_started) {
28013 - /* search for the \r\n\r\n in the string */
28014 - if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
28015 - size_t hlen = c - hctx->response->ptr + 4;
28016 - size_t blen = hctx->response->used - hlen - 1;
28019 - buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
28021 - log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
28023 - /* parse the response header */
28024 - proxy_response_parse(srv, con, p, hctx->response_header);
28026 - /* enable chunked-transfer-encoding */
28027 - if (con->request.http_version == HTTP_VERSION_1_1 &&
28028 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
28029 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28030 + /* the response header is not fully received yet,
28032 + * extract the http-response header from the rb-cq
28034 + switch (http_response_parse_cq(hctx->rb, p->resp)) {
28035 + case PARSE_ERROR:
28036 + /* parsing failed */
28038 + con->http_status = 502; /* Bad Gateway */
28040 + case PARSE_NEED_MORE:
28042 + case PARSE_SUCCESS:
28043 + con->http_status = p->resp->status;
28045 + chunkqueue_remove_finished_chunks(hctx->rb);
28047 + /* copy the http-headers */
28048 + for (i = 0; i < p->resp->headers->used; i++) {
28049 + const char *ign[] = { "Status", "Connection", NULL };
28053 + data_string *header = (data_string *)p->resp->headers->data[i];
28055 + /* some headers are ignored by default */
28056 + for (j = 0; ign[j]; j++) {
28057 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
28059 + if (ign[j]) continue;
28061 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
28062 + /* CGI/1.1 rev 03 - 7.2.1.2 */
28063 + if (con->http_status == 0) con->http_status = 302;
28064 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
28065 + have_content_length = 1;
28068 - con->file_started = 1;
28070 - http_chunk_append_mem(srv, con, c + 4, blen + 1);
28071 - joblist_append(srv, con);
28073 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
28074 + ds = data_response_init();
28076 - hctx->response->used = 0;
28077 + buffer_copy_string_buffer(ds->key, header->key);
28078 + buffer_copy_string_buffer(ds->value, header->value);
28080 + array_insert_unique(con->response.headers, (data_unset *)ds);
28083 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
28084 - joblist_append(srv, con);
28085 - hctx->response->used = 0;
28087 + con->file_started = 1;
28089 + if (con->request.http_version == HTTP_VERSION_1_1 &&
28090 + !have_content_length) {
28091 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
28094 + hctx->state = PROXY_STATE_RESPONSE_CONTENT;
28099 - /* reading from upstream done */
28100 - con->file_finished = 1;
28102 - http_chunk_append_mem(srv, con, NULL, 0);
28103 - joblist_append(srv, con);
28110 + /* FIXME: pass the response-header to the other plugins to
28111 + * setup the filter-queue
28113 + * - use next-queue instead of con->write_queue
28116 + next_queue = con->write_queue;
28118 + assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
28120 + /* FIXME: if we have a content-length or chunked-encoding
28123 + * for now we wait for EOF on the socket */
28125 + /* copy the content to the next cq */
28126 + for (c = hctx->rb->first; c; c = c->next) {
28127 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
28129 + c->offset = c->mem->used - 1;
28132 + chunkqueue_remove_finished_chunks(hctx->rb);
28133 + joblist_append(srv, con);
28139 @@ -731,32 +701,32 @@
28140 data_proxy *host= hctx->host;
28141 plugin_data *p = hctx->plugin_data;
28142 connection *con = hctx->remote_conn;
28148 - (!host->host->used || !host->port)) return -1;
28152 + (!host->host->used || !host->port)) return -1;
28154 switch(hctx->state) {
28155 case PROXY_STATE_INIT:
28156 - if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28157 + if (-1 == (hctx->sock->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28158 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
28159 return HANDLER_ERROR;
28161 - hctx->fde_ndx = -1;
28163 + hctx->sock->fde_ndx = -1;
28167 - fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
28169 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28171 + fdevent_register(srv->ev, hctx->sock, proxy_handle_fdevent, hctx);
28173 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
28174 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
28177 return HANDLER_ERROR;
28184 case PROXY_STATE_CONNECT:
28185 /* try to finish the connect() */
28186 if (hctx->state == PROXY_STATE_INIT) {
28187 @@ -764,16 +734,16 @@
28188 switch (proxy_establish_connection(srv, hctx)) {
28190 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
28193 /* connection is in progress, wait for an event and call getsockopt() below */
28195 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28198 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28200 return HANDLER_WAIT_FOR_EVENT;
28202 /* if ECONNREFUSED choose another connection -> FIXME */
28203 - hctx->fde_ndx = -1;
28205 + hctx->sock->fde_ndx = -1;
28207 return HANDLER_ERROR;
28209 /* everything is ok, go on */
28210 @@ -782,152 +752,152 @@
28213 socklen_t socket_error_len = sizeof(socket_error);
28215 - /* we don't need it anymore */
28216 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28218 + /* we don't need it anymore */
28219 + fdevent_event_del(srv->ev, hctx->sock);
28221 /* try to finish the connect() */
28222 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28223 - log_error_write(srv, __FILE__, __LINE__, "ss",
28224 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28225 + log_error_write(srv, __FILE__, __LINE__, "ss",
28226 "getsockopt failed:", strerror(errno));
28229 return HANDLER_ERROR;
28231 if (socket_error != 0) {
28232 log_error_write(srv, __FILE__, __LINE__, "ss",
28233 - "establishing connection failed:", strerror(socket_error),
28234 + "establishing connection failed:", strerror(socket_error),
28235 "port:", hctx->host->port);
28238 return HANDLER_ERROR;
28240 if (p->conf.debug) {
28241 - log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
28242 + log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
28247 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
28249 case PROXY_STATE_PREPARE_WRITE:
28250 proxy_create_env(srv, hctx);
28253 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
28257 case PROXY_STATE_WRITE:;
28258 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
28259 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
28261 chunkqueue_remove_finished_chunks(hctx->wb);
28264 - if (errno != EAGAIN &&
28265 - errno != EINTR) {
28266 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28268 - return HANDLER_ERROR;
28270 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28272 + case NETWORK_STATUS_FATAL_ERROR:
28273 + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28275 - return HANDLER_WAIT_FOR_EVENT;
28277 + return HANDLER_ERROR;
28278 + case NETWORK_STATUS_WAIT_FOR_EVENT:
28280 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28282 + return HANDLER_WAIT_FOR_EVENT;
28285 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28286 - proxy_set_state(srv, hctx, PROXY_STATE_READ);
28287 + proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
28289 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28290 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28291 + fdevent_event_del(srv->ev, hctx->sock);
28292 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
28294 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28296 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
28298 return HANDLER_WAIT_FOR_EVENT;
28302 return HANDLER_WAIT_FOR_EVENT;
28303 - case PROXY_STATE_READ:
28304 + case PROXY_STATE_RESPONSE_CONTENT:
28305 + case PROXY_STATE_RESPONSE_HEADER:
28306 /* waiting for a response */
28308 return HANDLER_WAIT_FOR_EVENT;
28310 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28311 return HANDLER_ERROR;
28315 return HANDLER_GO_ON;
28318 -#define PATCH(x) \
28319 - p->conf.x = s->x;
28320 static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
28322 plugin_config *s = p->config_storage[0];
28324 - PATCH(extensions);
28329 + PATCH_OPTION(extensions);
28330 + PATCH_OPTION(debug);
28331 + PATCH_OPTION(balance);
28332 + PATCH_OPTION(last_used_backends);
28334 /* skip the first, the global context */
28335 for (i = 1; i < srv->config_context->used; i++) {
28336 data_config *dc = (data_config *)srv->config_context->data[i];
28337 s = p->config_storage[i];
28340 /* condition didn't match */
28341 if (!config_check_cond(srv, con, dc)) continue;
28345 for (j = 0; j < dc->value->used; j++) {
28346 data_unset *du = dc->value->data[j];
28349 if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
28350 - PATCH(extensions);
28351 + PATCH_OPTION(extensions);
28352 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
28354 + PATCH_OPTION(debug);
28355 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
28357 + PATCH_OPTION(balance);
28358 + PATCH_OPTION(last_used_backends);
28368 SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
28369 plugin_data *p = p_d;
28372 handler_ctx *hctx = con->plugin_ctx[p->id];
28376 if (NULL == hctx) return HANDLER_GO_ON;
28378 mod_proxy_patch_connection(srv, con, p);
28385 if (con->mode != p->id) return HANDLER_GO_ON;
28388 /* ok, create the request */
28389 switch(proxy_write_request(srv, hctx)) {
28390 case HANDLER_ERROR:
28391 - log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
28392 + log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
28399 /* disable this server */
28400 host->is_disabled = 1;
28401 host->disable_ts = srv->cur_ts;
28404 proxy_connection_close(srv, hctx);
28406 - /* reset the enviroment and restart the sub-request */
28408 + /* reset the enviroment and restart the sub-request */
28409 buffer_reset(con->physical.path);
28410 con->mode = DIRECT;
28412 joblist_append(srv, con);
28414 - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28415 - * and hope that the childs will be restarted
28417 + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28418 + * and hope that the childs will be restarted
28422 return HANDLER_WAIT_FOR_FD;
28423 @@ -938,7 +908,7 @@
28429 if (con->file_started == 1) {
28430 return HANDLER_FINISHED;
28432 @@ -951,13 +921,14 @@
28433 handler_ctx *hctx = ctx;
28434 connection *con = hctx->remote_conn;
28435 plugin_data *p = hctx->plugin_data;
28440 if ((revents & FDEVENT_IN) &&
28441 - hctx->state == PROXY_STATE_READ) {
28442 + (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
28443 + hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
28445 if (p->conf.debug) {
28446 - log_error_write(srv, __FILE__, __LINE__, "sd",
28447 + log_error_write(srv, __FILE__, __LINE__, "sd",
28448 "proxy: fdevent-in", hctx->state);
28451 @@ -965,11 +936,15 @@
28455 + log_error_write(srv, __FILE__, __LINE__, "sd",
28456 + "proxy: request done", hctx->sock->fd);
28457 hctx->host->usage--;
28460 + http_chunk_append_mem(srv, con, NULL, 0);
28463 proxy_connection_close(srv, hctx);
28466 joblist_append(srv, con);
28467 return HANDLER_FINISHED;
28469 @@ -982,53 +957,53 @@
28470 /* response might have been already started, kill the connection */
28471 connection_set_state(srv, con, CON_STATE_ERROR);
28475 joblist_append(srv, con);
28476 return HANDLER_FINISHED;
28481 if (revents & FDEVENT_OUT) {
28482 if (p->conf.debug) {
28483 - log_error_write(srv, __FILE__, __LINE__, "sd",
28484 + log_error_write(srv, __FILE__, __LINE__, "sd",
28485 "proxy: fdevent-out", hctx->state);
28488 if (hctx->state == PROXY_STATE_CONNECT ||
28489 hctx->state == PROXY_STATE_WRITE) {
28490 /* we are allowed to send something out
28493 * 1. in a unfinished connect() call
28494 * 2. in a unfinished write() call (long POST request)
28496 return mod_proxy_handle_subrequest(srv, con, p);
28498 - log_error_write(srv, __FILE__, __LINE__, "sd",
28499 + log_error_write(srv, __FILE__, __LINE__, "sd",
28500 "proxy: out", hctx->state);
28505 /* perhaps this issue is already handled */
28506 if (revents & FDEVENT_HUP) {
28507 if (p->conf.debug) {
28508 - log_error_write(srv, __FILE__, __LINE__, "sd",
28509 + log_error_write(srv, __FILE__, __LINE__, "sd",
28510 "proxy: fdevent-hup", hctx->state);
28514 if (hctx->state == PROXY_STATE_CONNECT) {
28515 /* connect() -> EINPROGRESS -> HUP */
28519 - * what is proxy is doing if it can't reach the next hop ?
28521 + * what is proxy is doing if it can't reach the next hop ?
28526 proxy_connection_close(srv, hctx);
28527 joblist_append(srv, con);
28530 con->http_status = 503;
28531 con->mode = DIRECT;
28534 return HANDLER_FINISHED;
28537 @@ -1038,13 +1013,13 @@
28538 joblist_append(srv, con);
28539 } else if (revents & FDEVENT_ERR) {
28540 /* kill all connections to the proxy process */
28543 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
28545 joblist_append(srv, con);
28546 proxy_connection_close(srv, hctx);
28550 return HANDLER_FINISHED;
28553 @@ -1058,44 +1033,48 @@
28555 data_array *extension = NULL;
28556 size_t path_info_offset;
28558 + data_integer *last_used_backend;
28559 + data_proxy *host = NULL;
28560 + handler_ctx *hctx = NULL;
28562 + array *backends = NULL;
28564 /* Possibly, we processed already this request */
28565 if (con->file_started == 1) return HANDLER_GO_ON;
28568 mod_proxy_patch_connection(srv, con, p);
28571 fn = con->uri.path;
28573 if (fn->used == 0) {
28574 return HANDLER_ERROR;
28578 s_len = fn->used - 1;
28582 path_info_offset = 0;
28584 - if (p->conf.debug) {
28585 + if (p->conf.debug) {
28586 log_error_write(srv, __FILE__, __LINE__, "s", "proxy - start");
28589 /* check if extension matches */
28590 for (k = 0; k < p->conf.extensions->used; k++) {
28594 extension = (data_array *)p->conf.extensions->data[k];
28597 if (extension->key->used == 0) continue;
28600 ct_len = extension->key->used - 1;
28603 if (s_len < ct_len) continue;
28606 /* check extension in the form "/proxy_pattern" */
28607 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
28608 if (s_len > ct_len + 1) {
28612 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
28613 path_info_offset = pi_offset - fn->ptr;
28615 @@ -1106,12 +1085,14 @@
28621 if (k == p->conf.extensions->used) {
28622 return HANDLER_GO_ON;
28625 - if (p->conf.debug) {
28626 + backends = extension->value;
28628 + if (p->conf.debug) {
28629 log_error_write(srv, __FILE__, __LINE__, "s", "proxy - ext found");
28632 @@ -1120,34 +1101,34 @@
28633 /* hash balancing */
28635 if (p->conf.debug) {
28636 - log_error_write(srv, __FILE__, __LINE__, "sd",
28637 - "proxy - used hash balancing, hosts:", extension->value->used);
28638 + log_error_write(srv, __FILE__, __LINE__, "sd",
28639 + "proxy - used hash balancing, hosts:", backends->used);
28642 - for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
28643 - data_proxy *host = (data_proxy *)extension->value->data[k];
28644 + for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
28645 unsigned long cur_max;
28647 - if (host->is_disabled) continue;
28649 + data_proxy *cur = (data_proxy *)backends->data[k];
28651 + if (cur->is_disabled) continue;
28653 cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
28654 - generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
28655 + generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
28656 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
28659 if (p->conf.debug) {
28660 - log_error_write(srv, __FILE__, __LINE__, "sbbbd",
28661 + log_error_write(srv, __FILE__, __LINE__, "sbbbd",
28662 "proxy - election:",
28666 con->uri.authority,
28670 - if ((last_max == ULONG_MAX) || /* first round */
28671 - (cur_max > last_max)) {
28672 + if (host == NULL || (cur_max > last_max)) {
28673 last_max = cur_max;
28680 @@ -1155,19 +1136,20 @@
28681 case PROXY_BALANCE_FAIR:
28682 /* fair balancing */
28683 if (p->conf.debug) {
28684 - log_error_write(srv, __FILE__, __LINE__, "s",
28685 + log_error_write(srv, __FILE__, __LINE__, "s",
28686 "proxy - used fair balancing");
28689 - for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28690 - data_proxy *host = (data_proxy *)extension->value->data[k];
28692 - if (host->is_disabled) continue;
28694 - if (host->usage < max_usage) {
28695 - max_usage = host->usage;
28698 + /* try to find the host with the lowest load */
28699 + for (k = 0, max_usage = 0; k < backends->used; k++) {
28700 + data_proxy *cur = (data_proxy *)backends->data[k];
28702 + if (cur->is_disabled) continue;
28704 + if (NULL == host || cur->usage < max_usage) {
28705 + max_usage = cur->usage;
28711 @@ -1175,89 +1157,100 @@
28712 case PROXY_BALANCE_RR:
28714 if (p->conf.debug) {
28715 - log_error_write(srv, __FILE__, __LINE__, "s",
28716 + log_error_write(srv, __FILE__, __LINE__, "s",
28717 "proxy - used round-robin balancing");
28720 /* just to be sure */
28721 - assert(extension->value->used < INT_MAX);
28723 - for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28724 - data_proxy *host = (data_proxy *)extension->value->data[k];
28726 - if (host->is_disabled) continue;
28728 - /* first usable ndx */
28729 - if (max_usage == INT_MAX) {
28732 + assert(backends->used < INT_MAX);
28734 - /* get next ndx */
28735 - if ((int)k > host->last_used_ndx) {
28737 - host->last_used_ndx = k;
28738 + /* send each request to another host:
28742 + * if we have three hosts it is
28744 + * 1 .. 2 .. 3 .. 1 .. 2 .. 3
28750 + /* walk through the list */
28751 + last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
28753 + if (NULL == last_used_backend) {
28754 + last_used_backend = data_integer_init();
28756 + buffer_copy_string_buffer(last_used_backend->key, extension->key);
28757 + last_used_backend->value = 0;
28759 + array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
28762 + /* scan all but the last host to see if they are up
28763 + * take the first running host */
28764 + for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
28765 + data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
28767 + if (cur->is_disabled) continue;
28771 + last_used_backend->value = k;
28776 - /* didn't found a higher id, wrap to the start */
28777 - if (ndx != -1 && max_usage != INT_MAX) {
28780 + if (NULL == host) {
28781 + /* we found nothing better, fallback to the last used backend
28782 + * and check if it is still up */
28783 + host = (data_proxy *)backends->data[last_used_backend->value];
28785 + if (host->is_disabled) host = NULL;
28793 - /* found a server */
28795 - data_proxy *host = (data_proxy *)extension->value->data[ndx];
28798 - * if check-local is disabled, use the uri.path handler
28802 - /* init handler-context */
28803 - handler_ctx *hctx;
28804 - hctx = handler_ctx_init();
28806 - hctx->path_info_offset = path_info_offset;
28807 - hctx->remote_conn = con;
28808 - hctx->plugin_data = p;
28809 - hctx->host = host;
28811 - con->plugin_ctx[p->id] = hctx;
28815 - con->mode = p->id;
28817 - if (p->conf.debug) {
28818 - log_error_write(srv, __FILE__, __LINE__, "sbd",
28819 - "proxy - found a host",
28820 - host->host, host->port);
28823 - return HANDLER_GO_ON;
28825 - /* no handler found */
28826 + /* we havn't found a host */
28827 + if (NULL == host) {
28828 con->http_status = 500;
28830 - log_error_write(srv, __FILE__, __LINE__, "sb",
28831 - "no proxy-handler found for:",
28833 + log_error_write(srv, __FILE__, __LINE__, "sb",
28834 + "no proxy-handler found for:",
28838 return HANDLER_FINISHED;
28841 + /* init handler-context */
28842 + hctx = handler_ctx_init();
28844 + hctx->path_info_offset = path_info_offset;
28845 + hctx->remote_conn = con;
28846 + hctx->plugin_data = p;
28847 + hctx->host = host;
28849 + con->plugin_ctx[p->id] = hctx;
28853 + /* we handle this request */
28854 + con->mode = p->id;
28856 + if (p->conf.debug) {
28857 + log_error_write(srv, __FILE__, __LINE__, "sbd",
28858 + "proxy - found a host",
28859 + host->host, host->port);
28862 return HANDLER_GO_ON;
28865 static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
28866 plugin_data *p = p_d;
28869 proxy_connection_close(srv, con->plugin_ctx[p->id]);
28871 return HANDLER_GO_ON;
28872 @@ -1276,11 +1269,11 @@
28874 for (i = 0; i < srv->config_context->used; i++) {
28875 plugin_config *s = p->config_storage[i];
28877 - if (!s) continue;
28879 + if (!s) continue;
28881 /* get the extensions for all configs */
28884 for (k = 0; k < s->extensions->used; k++) {
28885 data_array *extension = (data_array *)s->extensions->data[k];
28887 @@ -1290,8 +1283,8 @@
28889 if (!host->is_disabled ||
28890 srv->cur_ts - host->disable_ts < 5) continue;
28892 - log_error_write(srv, __FILE__, __LINE__, "sbd",
28894 + log_error_write(srv, __FILE__, __LINE__, "sbd",
28895 "proxy - re-enabled:",
28896 host->host, host->port);
28898 @@ -1317,8 +1310,8 @@
28899 p->handle_uri_clean = mod_proxy_check_extension;
28900 p->handle_subrequest = mod_proxy_handle_subrequest;
28901 p->handle_trigger = mod_proxy_trigger;
28909 --- ../lighttpd-1.4.11/src/mod_proxy_core.c 1970-01-01 03:00:00.000000000 +0300
28910 +++ lighttpd-1.4.12/src/mod_proxy_core.c 2006-07-19 20:02:55.000000000 +0300
28912 +#include <string.h>
28913 +#include <stdlib.h>
28914 +#include <fcntl.h>
28915 +#include <errno.h>
28916 +#include <ctype.h>
28918 +#include "buffer.h"
28919 +#include "array.h"
28923 +#include "plugin.h"
28924 +#include "joblist.h"
28925 +#include "sys-files.h"
28926 +#include "inet_ntop_cache.h"
28927 +#include "http_resp.h"
28928 +#include "http_chunk.h"
28929 +#include "crc32.h"
28931 +#include "mod_proxy_core_pool.h"
28932 +#include "mod_proxy_core_backend.h"
28933 +#include "mod_proxy_core_backlog.h"
28934 +#include "mod_proxy_core_rewrites.h"
28936 +#define CONFIG_PROXY_CORE_BALANCER "proxy-core.balancer"
28937 +#define CONFIG_PROXY_CORE_PROTOCOL "proxy-core.protocol"
28938 +#define CONFIG_PROXY_CORE_DEBUG "proxy-core.debug"
28939 +#define CONFIG_PROXY_CORE_BACKENDS "proxy-core.backends"
28940 +#define CONFIG_PROXY_CORE_REWRITE_REQUEST "proxy-core.rewrite-request"
28941 +#define CONFIG_PROXY_CORE_REWRITE_RESPONSE "proxy-core.rewrite-response"
28944 + PROXY_PROTOCOL_UNSET,
28945 + PROXY_PROTOCOL_HTTP,
28946 + PROXY_PROTOCOL_HTTPS,
28947 + PROXY_PROTOCOL_FASTCGI,
28948 + PROXY_PROTOCOL_SCGI
28949 +} proxy_protocol_t;
28952 + proxy_backends *backends;
28954 + proxy_backlog *backlog;
28956 + proxy_rewrites *request_rewrites;
28957 + proxy_rewrites *response_rewrites;
28961 + proxy_balance_t balancer;
28962 + proxy_protocol_t protocol;
28970 + array *possible_balancers;
28971 + array *possible_protocols;
28973 + /* for parsing only */
28974 + array *backends_arr;
28975 + buffer *protocol_buf;
28976 + buffer *balance_buf;
28978 + buffer *replace_buf;
28980 + plugin_config **config_storage;
28982 + plugin_config conf;
28985 +int array_insert_int(array *a, const char *key, int val) {
28986 + data_integer *di;
28988 + if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
28989 + di = data_integer_init();
28992 + buffer_copy_string(di->key, key);
28994 + array_insert_unique(a, (data_unset *)di);
28999 +INIT_FUNC(mod_proxy_core_init) {
29002 + p = calloc(1, sizeof(*p));
29004 + /* create some backends as long as we don't have the config-parser */
29006 + p->possible_balancers = array_init();
29007 + array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
29008 + array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_HASH);
29009 + array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_RR);
29011 + p->possible_protocols = array_init();
29012 + array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
29013 + array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
29014 + array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
29015 + array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
29017 + p->balance_buf = buffer_init();
29018 + p->protocol_buf = buffer_init();
29019 + p->replace_buf = buffer_init();
29020 + p->backends_arr = array_init();
29022 + p->resp = http_response_init();
29027 +FREE_FUNC(mod_proxy_core_free) {
29028 + plugin_data *p = p_d;
29030 + if (!p) return HANDLER_GO_ON;
29032 + if (p->config_storage) {
29034 + for (i = 0; i < srv->config_context->used; i++) {
29035 + plugin_config *s = p->config_storage[i];
29037 + if (!s) continue;
29039 + proxy_backends_free(s->backends);
29040 + proxy_backlog_free(s->backlog);
29045 + free(p->config_storage);
29048 + array_free(p->possible_protocols);
29049 + array_free(p->possible_balancers);
29050 + array_free(p->backends_arr);
29052 + buffer_free(p->balance_buf);
29053 + buffer_free(p->protocol_buf);
29054 + buffer_free(p->replace_buf);
29056 + http_response_free(p->resp);
29060 + return HANDLER_GO_ON;
29063 +static handler_t mod_proxy_core_config_parse_rewrites(proxy_rewrites *dest, array *src, const char *config_key) {
29067 + if (NULL != (du = array_get_element(src, config_key))) {
29068 + data_array *keys = (data_array *)du;
29070 + if (keys->type != TYPE_ARRAY) {
29071 + ERROR("%s = <...>",
29074 + return HANDLER_ERROR;
29078 + * proxy-core.rewrite-request = (
29079 + * "_uri" => ( ... )
29083 + for (j = 0; j < keys->value->used; j++) {
29085 + data_array *headers = (data_array *)keys->value->data[j];
29087 + /* keys->key should be "_uri" and the value a array of rewrite */
29088 + if (headers->type != TYPE_ARRAY) {
29089 + ERROR("%s = ( %s => <...> ) has to a array",
29091 + BUF_STR(headers->key));
29093 + return HANDLER_ERROR;
29096 + if (headers->value->used > 1) {
29097 + ERROR("%s = ( %s => <...> ) has to a array with only one element",
29099 + BUF_STR(headers->key));
29101 + return HANDLER_ERROR;
29105 + for (k = 0; k < headers->value->used; k++) {
29106 + data_string *rewrites = (data_string *)headers->value->data[k];
29107 + proxy_rewrite *rw;
29109 + /* keys->key should be "_uri" and the value a array of rewrite */
29110 + if (rewrites->type != TYPE_STRING) {
29111 + ERROR("%s = ( \"%s\" => ( \"%s\" => <value> ) ) has to a string",
29113 + BUF_STR(headers->key),
29114 + BUF_STR(rewrites->key));
29116 + return HANDLER_ERROR;
29119 + rw = proxy_rewrite_init();
29121 + if (0 != proxy_rewrite_set_regex(rw, rewrites->key)) {
29122 + return HANDLER_ERROR;
29124 + buffer_copy_string_buffer(rw->replace, rewrites->value);
29125 + buffer_copy_string_buffer(rw->match, rewrites->key);
29126 + buffer_copy_string_buffer(rw->header, headers->key);
29128 + proxy_rewrites_add(dest, rw);
29133 + return HANDLER_GO_ON;
29137 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
29138 + plugin_data *p = p_d;
29141 + config_values_t cv[] = {
29142 + { CONFIG_PROXY_CORE_BACKENDS, NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
29143 + { CONFIG_PROXY_CORE_DEBUG, NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
29144 + { CONFIG_PROXY_CORE_BALANCER, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
29145 + { CONFIG_PROXY_CORE_PROTOCOL, NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
29146 + { CONFIG_PROXY_CORE_REWRITE_REQUEST, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
29147 + { CONFIG_PROXY_CORE_REWRITE_RESPONSE, NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION },/* 5 */
29148 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
29151 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
29153 + for (i = 0; i < srv->config_context->used; i++) {
29154 + plugin_config *s;
29156 + proxy_backend *backend;
29158 + array_reset(p->backends_arr);
29159 + buffer_reset(p->balance_buf);
29160 + buffer_reset(p->protocol_buf);
29162 + s = malloc(sizeof(plugin_config));
29164 + s->balancer = PROXY_BALANCE_UNSET;
29165 + s->protocol = PROXY_PROTOCOL_UNSET;
29166 + s->backends = proxy_backends_init();
29167 + s->backlog = proxy_backlog_init();
29168 + s->response_rewrites = proxy_rewrites_init();
29169 + s->request_rewrites = proxy_rewrites_init();
29171 + cv[0].destination = p->backends_arr;
29172 + cv[1].destination = &(s->debug);
29173 + cv[2].destination = p->balance_buf; /* parse into a constant */
29174 + cv[3].destination = p->protocol_buf; /* parse into a constant */
29176 + buffer_reset(p->balance_buf);
29178 + p->config_storage[i] = s;
29179 + ca = ((data_config *)srv->config_context->data[i])->value;
29181 + if (0 != config_insert_values_global(srv, ca, cv)) {
29182 + return HANDLER_ERROR;
29185 + if (!buffer_is_empty(p->balance_buf)) {
29186 + data_integer *di;
29188 + if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
29189 + ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
29191 + return HANDLER_ERROR;
29194 + s->balancer = di->value;
29197 + if (!buffer_is_empty(p->protocol_buf)) {
29198 + data_integer *di;
29200 + if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
29201 + ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
29203 + return HANDLER_ERROR;
29206 + s->protocol = di->value;
29209 + if (p->backends_arr->used) {
29210 + backend = proxy_backend_init();
29212 + /* check if the backends have a valid host-name */
29213 + for (j = 0; j < p->backends_arr->used; j++) {
29214 + data_string *ds = (data_string *)p->backends_arr->data[j];
29216 + /* the values should be ips or hostnames */
29217 + if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
29218 + return HANDLER_ERROR;
29222 + proxy_backends_add(s->backends, backend);
29225 + if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->request_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_REQUEST)) {
29226 + return HANDLER_ERROR;
29229 + if (HANDLER_GO_ON != mod_proxy_core_config_parse_rewrites(s->response_rewrites, ca, CONFIG_PROXY_CORE_REWRITE_RESPONSE)) {
29230 + return HANDLER_ERROR;
29234 + return HANDLER_GO_ON;
29239 + PROXY_STATE_UNSET,
29240 + PROXY_STATE_CONNECTING,
29241 + PROXY_STATE_CONNECTED,
29242 + PROXY_STATE_WRITE_REQUEST_HEADER,
29243 + PROXY_STATE_WRITE_REQUEST_BODY,
29244 + PROXY_STATE_READ_RESPONSE_HEADER,
29245 + PROXY_STATE_READ_RESPONSE_BODY
29249 + proxy_connection *proxy_con;
29250 + proxy_backend *proxy_backend;
29252 + connection *remote_con;
29254 + array *request_headers;
29260 + * - the encoded_rb is the raw network stuff
29261 + * - the rb is filtered through the stream decoder
29263 + * - wb is the normal bytes stream
29264 + * - encoded_wb is encoded for the network by the stream encoder
29266 + chunkqueue *recv;
29267 + chunkqueue *recv_raw;
29268 + chunkqueue *send_raw;
29269 + chunkqueue *send;
29271 + off_t bytes_read;
29272 + off_t content_length;
29274 + proxy_state_t state;
29277 +proxy_session *proxy_session_init(void) {
29278 + proxy_session *sess;
29280 + sess = calloc(1, sizeof(*sess));
29282 + sess->state = PROXY_STATE_UNSET;
29283 + sess->request_headers = array_init();
29285 + sess->recv = chunkqueue_init();
29286 + sess->recv_raw = chunkqueue_init();
29287 + sess->send_raw = chunkqueue_init();
29288 + sess->send = chunkqueue_init();
29290 + sess->is_chunked = 0;
29295 +void proxy_session_free(proxy_session *sess) {
29296 + if (!sess) return;
29298 + array_free(sess->request_headers);
29300 + chunkqueue_free(sess->recv);
29301 + chunkqueue_free(sess->recv_raw);
29302 + chunkqueue_free(sess->send_raw);
29303 + chunkqueue_free(sess->send);
29308 +handler_t proxy_connection_connect(proxy_connection *con) {
29311 + if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
29314 + fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
29316 + con->sock->fd = fd;
29317 + con->sock->fde_ndx = -1;
29318 + con->sock->type = IOSOCKET_TYPE_SOCKET;
29320 + if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
29322 + case EINPROGRESS:
29325 + return HANDLER_WAIT_FOR_EVENT;
29328 + con->sock->fd = -1;
29330 + return HANDLER_ERROR;
29334 + return HANDLER_GO_ON;
29338 + * event-handler for idling connections
29340 + * unused (idling) keep-alive connections are not bound to a session
29341 + * and need their own event-handler
29343 + * if the connection closes (we get a FDEVENT_IN), close our side too and
29344 + * let the trigger-func handle the cleanup
29346 + * @see proxy_trigger
29350 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
29351 + server *srv = (server *)s;
29352 + proxy_connection *proxy_con = ctx;
29354 + if (revents & FDEVENT_IN) {
29355 + switch (proxy_con->state) {
29356 + case PROXY_CONNECTION_STATE_IDLE:
29357 + proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29359 + /* close + unregister have to be in the same call,
29360 + * otherwise we get a events for a re-opened fd */
29362 + fdevent_event_del(srv->ev, proxy_con->sock);
29365 + case PROXY_CONNECTION_STATE_CLOSED:
29366 + /* poll() is state-driven, we will get events as long as it isn't disabled
29367 + * the close() above should disable the events too */
29368 + ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
29371 + ERROR("invalid connection state: %d, should be idle", proxy_con->state);
29376 + return HANDLER_GO_ON;
29379 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
29382 + for (c = cq->first; c && skip; c = c->next) {
29383 + if (skip > c->mem->used - c->offset - 1) {
29384 + skip -= c->mem->used - c->offset - 1;
29386 + c->offset += skip;
29394 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
29397 + if (raw->first == NULL) return 0;
29399 + if (sess->is_chunked) {
29401 + /* the start should always be a chunk-length */
29402 + off_t chunk_len = 0;
29403 + char *err = NULL;
29404 + int chunklen_strlen = 0;
29406 + off_t we_have = 0, we_need = 0;
29410 + if (c->mem->used == 0) return 0;
29412 + chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
29413 + if (!(*err == ' ' || *err == '\r' || *err == ';')) {
29414 + if (*err == '\0') {
29415 + /* we just need more data */
29421 + if (chunk_len < 0) {
29422 + ERROR("chunk_len is negative: %Ld", chunk_len);
29426 + chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
29427 + chunklen_strlen++; /* skip the err-char */
29430 + ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
29435 + /* bingo, chunk-header is finished */
29440 + chunklen_strlen++;
29441 + } while (ch != '\n' && c != '\0');
29443 + if (ch != '\n') {
29444 + ERROR("%s", "missing the CRLF");
29448 + we_need = chunk_len + chunklen_strlen + 2;
29449 + /* do we have the full chunk ? */
29450 + for (c = raw->first; c; c = c->next) {
29451 + we_have += c->mem->used - 1 - c->offset;
29453 + /* we have enough, jump out */
29454 + if (we_have > we_need) break;
29457 + /* get more data */
29458 + if (we_have < we_need) {
29462 + /* skip the chunk-header */
29463 + chunkqueue_skip(raw, chunklen_strlen);
29465 + /* final chunk */
29466 + if (chunk_len == 0) {
29467 + chunkqueue_skip(raw, 2);
29472 + /* we have enough, copy the data */
29473 + for (c = raw->first; c && chunk_len; c = c->next) {
29474 + off_t we_want = 0;
29475 + buffer *b = chunkqueue_get_append_buffer(decoded);
29477 + we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
29479 + buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
29481 + c->offset += we_want;
29482 + chunk_len -= we_want;
29485 + /* skip the \r\n */
29486 + chunkqueue_skip(raw, 2);
29488 + /* we are done, give the connection to someone else */
29489 + chunkqueue_remove_finished_chunks(raw);
29492 + /* no chunked encoding, ok, perhaps a content-length ? */
29494 + chunkqueue_remove_finished_chunks(raw);
29495 + for (c = raw->first; c; c = c->next) {
29498 + if (c->mem->used == 0) continue;
29500 + b = chunkqueue_get_append_buffer(decoded);
29502 + sess->bytes_read += c->mem->used - c->offset - 1;
29504 + buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
29506 + c->offset = c->mem->used - 1;
29508 + if (sess->bytes_read == sess->content_length) {
29513 + if (sess->bytes_read == sess->content_length) {
29514 + return 1; /* finished */
29520 +/* don't call any proxy functions directly */
29521 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
29522 + server *srv = (server *)s;
29523 + proxy_session *sess = ctx;
29525 + if (revents & FDEVENT_OUT) {
29526 + switch (sess->state) {
29527 + case PROXY_STATE_CONNECTING: /* delayed connect */
29528 + case PROXY_STATE_WRITE_REQUEST_HEADER:
29529 + case PROXY_STATE_WRITE_REQUEST_BODY:
29530 + /* we are still connection */
29532 + joblist_append(srv, sess->remote_con);
29535 + ERROR("oops, unexpected state for fdevent-out %d", sess->state);
29538 + } else if (revents & FDEVENT_IN) {
29541 + switch (sess->state) {
29542 + case PROXY_STATE_READ_RESPONSE_HEADER:
29543 + /* call our header parser */
29544 + joblist_append(srv, sess->remote_con);
29546 + case PROXY_STATE_READ_RESPONSE_BODY:
29547 + /* we should be in the WRITE state now,
29548 + * just read in the content and forward it to the outgoing connection
29551 + chunkqueue_remove_finished_chunks(sess->recv_raw);
29552 + switch (srv->network_backend_read(srv, sess->remote_con, sess->proxy_con->sock, sess->recv_raw)) {
29553 + case NETWORK_STATUS_CONNECTION_CLOSE:
29554 + fdevent_event_del(srv->ev,sess->proxy_con->sock);
29556 + /* the connection is gone
29557 + * make the connect */
29558 + sess->remote_con->file_finished = 1;
29559 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29561 + case NETWORK_STATUS_SUCCESS:
29562 + /* read even more, do we have all the content */
29564 + /* how much do we want to read ? */
29566 + /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
29568 + switch (proxy_http_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
29576 + /* we are done */
29577 + sess->remote_con->file_finished = 1;
29581 + chunkqueue_remove_finished_chunks(sess->recv_raw);
29583 + /* copy the content to the next cq */
29584 + for (c = sess->recv->first; c; c = c->next) {
29585 + if (c->mem->used == 0) continue;
29587 + http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
29589 + c->offset = c->mem->used - 1;
29592 + chunkqueue_remove_finished_chunks(sess->recv);
29594 + if (sess->remote_con->file_finished) {
29595 + /* send final HTTP-Chunk packet */
29596 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
29601 + ERROR("%s", "oops, we failed to read");
29605 + joblist_append(srv, sess->remote_con);
29608 + ERROR("oops, unexpected state for fdevent-in %d", sess->state);
29613 + if (revents & FDEVENT_HUP) {
29614 + /* someone closed our connection */
29615 + switch (sess->state) {
29616 + case PROXY_STATE_CONNECTING:
29617 + /* let the getsockopt() catch this */
29618 + joblist_append(srv, sess->remote_con);
29621 + ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
29626 + return HANDLER_GO_ON;
29629 +int pcre_replace(pcre *match, buffer *replace, buffer *match_buf, buffer *result) {
29630 + const char *pattern = replace->ptr;
29631 + size_t pattern_len = replace->used - 1;
29637 + if ((n = pcre_exec(match, NULL, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
29638 + if (n != PCRE_ERROR_NOMATCH) {
29642 + const char **list;
29643 + size_t start, end;
29647 + pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
29649 + /* search for $[0-9] */
29651 + buffer_reset(result);
29653 + start = 0; end = pattern_len;
29654 + for (k = 0; k < pattern_len; k++) {
29655 + if ((pattern[k] == '$') &&
29656 + isdigit((unsigned char)pattern[k + 1])) {
29659 + size_t num = pattern[k + 1] - '0';
29663 + buffer_append_string_len(result, pattern + start, end - start);
29665 + /* n is always > 0 */
29666 + if (num < (size_t)n) {
29667 + buffer_append_string(result, list[num]);
29675 + buffer_append_string_len(result, pattern + start, pattern_len - start);
29684 + * generate a HTTP/1.1 proxy request from the set of request-headers
29686 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
29689 +int proxy_get_request_chunk(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29693 + b = chunkqueue_get_append_buffer(cq);
29695 + /* request line */
29696 + buffer_copy_string(b, get_http_method_name(con->request.http_method));
29697 + BUFFER_APPEND_STRING_CONST(b, " ");
29699 + /* check if we want to rewrite the uri */
29701 + for (i = 0; i < p->conf.request_rewrites->used; i++) {
29702 + proxy_rewrite *rw = p->conf.request_rewrites->ptr[i];
29704 + if (buffer_is_equal_string(rw->header, CONST_STR_LEN("_uri"))) {
29707 + if ((ret = pcre_replace(rw->regex, rw->replace, con->request.uri, p->replace_buf)) < 0) {
29709 + case PCRE_ERROR_NOMATCH:
29710 + /* hmm, ok. no problem */
29711 + buffer_append_string_buffer(b, con->request.uri);
29714 + TRACE("oops, pcre_replace failed with: %d", ret);
29718 + buffer_append_string_buffer(b, p->replace_buf);
29725 + if (i == p->conf.request_rewrites->used) {
29727 + buffer_append_string_buffer(b, con->request.uri);
29730 + BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
29732 + for (i = 0; i < sess->request_headers->used; i++) {
29735 + ds = (data_string *)sess->request_headers->data[i];
29737 + buffer_append_string_buffer(b, ds->key);
29738 + BUFFER_APPEND_STRING_CONST(b, ": ");
29739 + buffer_append_string_buffer(b, ds->value);
29740 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
29743 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
29748 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29749 + data_string *ds_dst;
29751 + if (NULL != (ds_dst = (data_string *)array_get_element(hdrs, key))) {
29752 + buffer_copy_string_len(ds_dst->value, value, val_len);
29756 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29757 + ds_dst = data_string_init();
29760 + buffer_copy_string_len(ds_dst->key, key, key_len);
29761 + buffer_copy_string_len(ds_dst->value, value, val_len);
29762 + array_insert_unique(hdrs, (data_unset *)ds_dst);
29765 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29766 + data_string *ds_dst;
29768 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29769 + ds_dst = data_string_init();
29772 + buffer_copy_string_len(ds_dst->key, key, key_len);
29773 + buffer_copy_string_len(ds_dst->value, value, val_len);
29774 + array_insert_unique(hdrs, (data_unset *)ds_dst);
29779 + * build the request-header array and call the backend specific request formater
29780 + * to fill the chunkqueue
29782 +int proxy_get_request_header(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29783 + /* request line */
29784 + const char *remote_ip;
29787 + remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
29788 + proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
29790 + /* http_host is NOT is just a pointer to a buffer
29791 + * which is NULL if it is not set */
29792 + if (con->request.http_host &&
29793 + !buffer_is_empty(con->request.http_host)) {
29794 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
29796 + if (con->conf.is_ssl) {
29797 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
29799 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
29802 + /* request header */
29803 + for (i = 0; i < con->request.headers->used; i++) {
29807 + ds = (data_string *)con->request.headers->data[i];
29809 + if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
29811 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
29812 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
29814 + for (k = 0; k < p->conf.request_rewrites->used; k++) {
29815 + proxy_rewrite *rw = p->conf.request_rewrites->ptr[k];
29817 + if (buffer_is_equal(rw->header, ds->key)) {
29820 + if ((ret = pcre_replace(rw->regex, rw->replace, ds->value, p->replace_buf)) < 0) {
29822 + case PCRE_ERROR_NOMATCH:
29823 + /* hmm, ok. no problem */
29824 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29827 + TRACE("oops, pcre_replace failed with: %d", ret);
29831 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(p->replace_buf));
29838 + if (k == p->conf.request_rewrites->used) {
29839 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29843 + proxy_get_request_chunk(srv, con, p, sess, sess->send_raw);
29849 + * parse the response header
29851 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
29852 + * - fastcgi needs some decoding for the protocol
29854 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29855 + int have_content_length = 0;
29858 + http_response_reset(p->resp);
29860 + switch (http_response_parse_cq(cq, p->resp)) {
29861 + case PARSE_ERROR:
29862 + /* parsing failed */
29864 + return PARSE_ERROR;
29865 + case PARSE_NEED_MORE:
29866 + return PARSE_NEED_MORE;
29867 + case PARSE_SUCCESS:
29868 + con->http_status = p->resp->status;
29870 + chunkqueue_remove_finished_chunks(cq);
29872 + sess->content_length = -1;
29874 + /* copy the http-headers */
29875 + for (i = 0; i < p->resp->headers->used; i++) {
29876 + const char *ign[] = { "Status", "Connection", NULL };
29880 + data_string *header = (data_string *)p->resp->headers->data[i];
29882 + /* some headers are ignored by default */
29883 + for (j = 0; ign[j]; j++) {
29884 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
29886 + if (ign[j]) continue;
29888 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
29889 + /* CGI/1.1 rev 03 - 7.2.1.2 */
29890 + if (con->http_status == 0) con->http_status = 302;
29891 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
29892 + have_content_length = 1;
29894 + sess->content_length = strtol(header->value->ptr, NULL, 10);
29896 + if (sess->content_length < 0) {
29897 + return PARSE_ERROR;
29899 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
29900 + if (strstr(header->value->ptr, "chunked")) {
29901 + sess->is_chunked = 1;
29903 + /* ignore the header */
29907 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
29908 + ds = data_response_init();
29912 + buffer_copy_string_buffer(ds->key, header->key);
29914 + for (k = 0; k < p->conf.response_rewrites->used; k++) {
29915 + proxy_rewrite *rw = p->conf.response_rewrites->ptr[k];
29917 + if (buffer_is_equal(rw->header, header->key)) {
29920 + if ((ret = pcre_replace(rw->regex, rw->replace, header->value, p->replace_buf)) < 0) {
29922 + case PCRE_ERROR_NOMATCH:
29923 + /* hmm, ok. no problem */
29924 + buffer_append_string_buffer(ds->value, header->value);
29927 + TRACE("oops, pcre_replace failed with: %d", ret);
29931 + buffer_append_string_buffer(ds->value, p->replace_buf);
29938 + if (k == p->conf.response_rewrites->used) {
29939 + buffer_copy_string_buffer(ds->value, header->value);
29942 + array_insert_unique(con->response.headers, (data_unset *)ds);
29945 + /* does the client allow us to send chunked encoding ? */
29946 + if (con->request.http_version == HTTP_VERSION_1_1 &&
29947 + !have_content_length) {
29948 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
29954 + return PARSE_SUCCESS; /* we have a full header */
29957 +/* we are event-driven
29959 + * the first entry is connect() call, if the doesn't need a event
29962 + * - connect (+ delayed connect)
29963 + * - write header + content
29964 + * - read header + content
29966 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
29967 + * tell the core we are ready to stream out the content.
29969 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29970 + /* do we have a connection ? */
29972 + if (sess->state == PROXY_STATE_UNSET) {
29973 + /* we are not started yet */
29974 + switch(proxy_connection_connect(sess->proxy_con)) {
29975 + case HANDLER_WAIT_FOR_EVENT:
29976 + /* waiting on the connect call */
29978 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29979 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29981 + sess->state = PROXY_STATE_CONNECTING;
29982 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
29984 + return HANDLER_WAIT_FOR_EVENT;
29985 + case HANDLER_GO_ON:
29986 + /* we are connected */
29987 + sess->state = PROXY_STATE_CONNECTED;
29988 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29989 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29992 + case HANDLER_ERROR:
29994 + /* not good, something failed */
29995 + return HANDLER_ERROR;
29998 + } else if (sess->state == PROXY_STATE_CONNECTING) {
29999 + int socket_error;
30000 + socklen_t socket_error_len = sizeof(socket_error);
30002 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30004 + if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
30005 + ERROR("getsockopt failed:", strerror(errno));
30007 + return HANDLER_ERROR;
30009 + if (socket_error != 0) {
30010 + switch (socket_error) {
30011 + case ECONNREFUSED:
30012 + /* there is no-one on the other side */
30013 + sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
30015 + TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
30017 + case EHOSTUNREACH:
30018 + /* there is no-one on the other side */
30019 + sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
30021 + TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
30024 + sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
30026 + TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
30028 + TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
30033 + sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
30035 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30036 + return HANDLER_COMEBACK;
30039 + sess->state = PROXY_STATE_CONNECTED;
30040 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
30043 + if (sess->state == PROXY_STATE_CONNECTED) {
30044 + /* build the header */
30045 + proxy_get_request_header(srv, con, p, sess);
30047 + sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
30050 + switch (sess->state) {
30051 + case PROXY_STATE_WRITE_REQUEST_HEADER:
30052 + /* create the request-packet */
30053 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30055 + switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
30056 + case NETWORK_STATUS_SUCCESS:
30057 + sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
30059 + case NETWORK_STATUS_WAIT_FOR_EVENT:
30060 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
30062 + return HANDLER_WAIT_FOR_EVENT;
30063 + case NETWORK_STATUS_CONNECTION_CLOSE:
30064 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30066 + /* this connection is closed, restart the request with a new connection */
30068 + return HANDLER_COMEBACK;
30070 + return HANDLER_ERROR;
30072 + /* fall through */
30073 + case PROXY_STATE_WRITE_REQUEST_BODY:
30074 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30075 + sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
30077 + case PROXY_STATE_READ_RESPONSE_HEADER:
30078 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30080 + chunkqueue_remove_finished_chunks(sess->recv_raw);
30082 + switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
30083 + case NETWORK_STATUS_SUCCESS:
30084 + /* we read everything from the socket, do we have a full header ? */
30086 + switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
30087 + case PARSE_ERROR:
30088 + con->http_status = 502; /* bad gateway */
30090 + return HANDLER_FINISHED;
30091 + case PARSE_NEED_MORE:
30092 + /* we need more */
30093 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30095 + return HANDLER_WAIT_FOR_EVENT;
30096 + case PARSE_SUCCESS:
30099 + return HANDLER_ERROR;
30102 + con->file_started = 1;
30104 + sess->state = PROXY_STATE_READ_RESPONSE_BODY;
30107 + * set the event to pass the content through to the server
30109 + * this triggers the event-handler
30110 + * @see proxy_handle_fdevent
30112 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30114 + return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
30115 + case NETWORK_STATUS_WAIT_FOR_EVENT:
30116 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30117 + return HANDLER_WAIT_FOR_EVENT;
30118 + case NETWORK_STATUS_CONNECTION_CLOSE:
30119 + if (chunkqueue_length(sess->recv_raw) == 0) {
30120 + /* the connection went away before we got something back */
30121 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
30124 + * we might run into a 'race-condition'
30126 + * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
30127 + * 2. new connection comes in, we use the idling connection [fd=14]
30128 + * 3. we write(), successful [to fd=27]
30129 + * 3. we read() ... and finally receive the close-event for the connection
30132 + con->http_status = 500;
30134 + ERROR("++ %s", "oops, connection got closed while we were reading from it");
30135 + return HANDLER_FINISHED;
30138 + ERROR("%s", "conn-close after header-read");
30142 + ERROR("++ %s", "oops, something went wrong while reading");
30143 + return HANDLER_ERROR;
30145 + case PROXY_STATE_READ_RESPONSE_BODY:
30146 + /* if we do everything right, we won't get call for this state-anymore */
30148 + ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
30153 + return HANDLER_GO_ON;
30156 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p) {
30159 + for (i = 0; i < p->conf.backends->used; i++) {
30160 + proxy_backend *backend = p->conf.backends->ptr[i];
30169 + * choose a available address from the address-pool
30171 + * the backend has different balancers
30173 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
30175 + proxy_address_pool *address_pool = backend->address_pool;
30176 + unsigned long last_max; /* for the HASH balancer */
30177 + proxy_address *address = NULL, *cur_address = NULL;
30178 + int active_addresses = 0, rand_ndx;
30180 + switch(backend->balancer) {
30181 + case PROXY_BALANCE_HASH:
30182 + /* hash balancing */
30184 + for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
30185 + unsigned long cur_max;
30187 + cur_address = address_pool->ptr[i];
30189 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30191 + cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
30192 + generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
30193 + generate_crc32c(CONST_BUF_LEN(con->uri.authority));
30195 + TRACE("hash-election: %s - %s - %s: %ld",
30196 + con->uri.path->ptr,
30197 + cur_address->name->ptr,
30198 + con->uri.authority->ptr,
30201 + if (address == NULL || (cur_max > last_max)) {
30202 + last_max = cur_max;
30204 + address = cur_address;
30209 + case PROXY_BALANCE_FAIR:
30210 + /* fair balancing */
30212 + for (i = 0; i < address_pool->used; i++) {
30213 + cur_address = address_pool->ptr[i];
30215 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30217 + /* the address is up, use it */
30219 + address = cur_address;
30225 + case PROXY_BALANCE_RR:
30226 + /* round robin */
30229 + * instead of real RoundRobin we just do a RandomSelect
30231 + * it is state-less and has the same distribution
30234 + active_addresses = 0;
30236 + for (i = 0; i < address_pool->used; i++) {
30237 + cur_address = address_pool->ptr[i];
30239 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30241 + active_addresses++;
30244 + rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
30246 + active_addresses = 0;
30247 + for (i = 0; i < address_pool->used; i++) {
30248 + cur_address = address_pool->ptr[i];
30250 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
30252 + address = cur_address;
30254 + if (rand_ndx == active_addresses++) break;
30265 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
30267 + plugin_config *s = p->config_storage[0];
30269 + /* global defaults */
30270 + PATCH_OPTION(balancer);
30271 + PATCH_OPTION(debug);
30272 + PATCH_OPTION(backends);
30273 + PATCH_OPTION(backlog);
30274 + PATCH_OPTION(protocol);
30275 + PATCH_OPTION(request_rewrites);
30276 + PATCH_OPTION(response_rewrites);
30278 + /* skip the first, the global context */
30279 + for (i = 1; i < srv->config_context->used; i++) {
30280 + data_config *dc = (data_config *)srv->config_context->data[i];
30281 + s = p->config_storage[i];
30283 + /* condition didn't match */
30284 + if (!config_check_cond(srv, con, dc)) continue;
30286 + /* merge config */
30287 + for (j = 0; j < dc->value->used; j++) {
30288 + data_unset *du = dc->value->data[j];
30290 + if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BACKENDS))) {
30291 + PATCH_OPTION(backends);
30292 + PATCH_OPTION(backlog);
30293 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_DEBUG))) {
30294 + PATCH_OPTION(debug);
30295 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_BALANCER))) {
30296 + PATCH_OPTION(balancer);
30297 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_PROTOCOL))) {
30298 + PATCH_OPTION(protocol);
30299 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_REQUEST))) {
30300 + PATCH_OPTION(request_rewrites);
30301 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN(CONFIG_PROXY_CORE_REWRITE_RESPONSE))) {
30302 + PATCH_OPTION(response_rewrites);
30311 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
30312 + plugin_data *p = p_d;
30313 + proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
30315 + /* check if we have a matching conditional for this request */
30317 + if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
30319 + mod_proxy_core_patch_connection(srv, con, p);
30321 + if (p->conf.backends->used == 0) return HANDLER_GO_ON;
30324 + * 0. build session
30325 + * 1. get a proxy connection
30326 + * 2. create the http-request header
30327 + * 3. stream the content to the backend
30328 + * 4. wait for http-response header
30329 + * 5. decode the response + parse the response
30330 + * 6. stream the response-content to the client
30331 + * 7. kill session
30335 + /* a session lives for a single request */
30336 + sess = proxy_session_init();
30338 + con->plugin_ctx[p->id] = sess;
30339 + con->mode = p->id;
30341 + sess->remote_con = con;
30344 + switch (sess->state) {
30345 + case PROXY_STATE_CONNECTING:
30346 + /* this connections is waited 10 seconds to connect to the backend
30347 + * and didn't got a successful connection yet, sending timeout */
30348 + if (srv->cur_ts - con->request_start > 10) {
30349 + con->http_status = 504; /* gateway timeout */
30350 + con->file_finished = 1;
30352 + if (sess->proxy_con) {
30353 + /* if we are waiting for a proxy-connection right now, close it */
30354 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30356 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30357 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30359 + proxy_connection_free(sess->proxy_con);
30361 + sess->proxy_con = NULL;
30364 + return HANDLER_FINISHED;
30367 + /* handle-request-timeout, */
30368 + if (srv->cur_ts - con->request_start > 60) {
30369 + TRACE("request runs longer than 60sec: current state: %d", sess->state);
30374 + /* if the WRITE fails from the start, restart the connection */
30376 + if (sess->proxy_con == NULL) {
30377 + proxy_address *address = NULL;
30378 + if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p))) {
30379 + /* no connection pool for this location */
30383 + sess->proxy_backend->balancer = p->conf.balancer;
30386 + * ask the balancer for the next address and
30387 + * check the connection pool if we have a connection open
30388 + * for that address
30390 + if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
30391 + /* we don't have any backends to connect to */
30392 + proxy_request *req;
30394 + /* connection pool is full, queue the request for now */
30395 + req = proxy_request_init();
30396 + req->added_ts = srv->cur_ts;
30399 + TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
30400 + proxy_backlog_push(p->conf.backlog, req);
30402 + /* no, not really a event,
30403 + * we just want to block the outer loop from stepping forward
30405 + * the trigger will bring this connection back into the game
30407 + return HANDLER_WAIT_FOR_EVENT;
30410 + if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
30411 + sess->proxy_backend->pool,
30413 + &(sess->proxy_con))) {
30414 + proxy_request *req;
30416 + /* connection pool is full, queue the request for now */
30417 + req = proxy_request_init();
30418 + req->added_ts = srv->cur_ts;
30421 + TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", con->uri.path->ptr, con->sock->fd);
30422 + proxy_backlog_push(p->conf.backlog, req);
30424 + /* no, not really a event,
30425 + * we just want to block the outer loop from stepping forward
30427 + * the trigger will bring this connection back into the game
30429 + return HANDLER_WAIT_FOR_EVENT;
30432 + /* a fresh connection, we need address for it */
30433 + if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
30434 + sess->state = PROXY_STATE_UNSET;
30435 + sess->bytes_read = 0;
30437 + /* we are already connected */
30438 + sess->state = PROXY_STATE_CONNECTED;
30440 + /* the connection was idling and using the fdevent_idle-handler
30441 + * switch it back to the normal proxy-event-handler */
30442 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30443 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30445 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
30446 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30450 + switch (proxy_state_engine(srv, con, p, sess)) {
30451 + case HANDLER_WAIT_FOR_EVENT:
30452 + return HANDLER_WAIT_FOR_EVENT;
30453 + case HANDLER_COMEBACK:
30454 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30456 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30457 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30459 + proxy_connection_free(sess->proxy_con);
30461 + sess->proxy_con = NULL;
30462 + /* restart the connection to the backend */
30463 + TRACE("%s", "write failed, restarting request");
30465 + case HANDLER_GO_ON:
30466 + return HANDLER_GO_ON;
30468 + return HANDLER_ERROR;
30472 + /* should not be reached */
30473 + return HANDLER_ERROR;
30477 + * end of the connection to the client
30479 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
30480 + plugin_data *p = p_d;
30482 + if (con->mode != p->id) return HANDLER_GO_ON;
30484 + return HANDLER_GO_ON;
30488 + * end of a request
30490 +CONNECTION_FUNC(mod_proxy_connection_reset) {
30491 + plugin_data *p = p_d;
30492 + proxy_session *sess = con->plugin_ctx[p->id];
30494 + if (con->mode != p->id) return HANDLER_GO_ON;
30496 + if (sess->proxy_con) {
30497 + switch (sess->proxy_con->state) {
30498 + case PROXY_CONNECTION_STATE_CONNECTED:
30499 + sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
30501 + /* ignore events as the FD is idle, we might get a HUP as the remote connection might close */
30502 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30503 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30505 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
30506 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30509 + case PROXY_CONNECTION_STATE_CLOSED:
30510 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30512 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30513 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30515 + proxy_connection_free(sess->proxy_con);
30517 + case PROXY_CONNECTION_STATE_IDLE:
30518 + TRACE("%s", "... connection is already back in the pool");
30521 + ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
30525 + /* if we have the connection in the backlog, remove it */
30526 + proxy_backlog_remove_connection(p->conf.backlog, con);
30530 + proxy_session_free(sess);
30532 + con->plugin_ctx[p->id] = NULL;
30534 + return HANDLER_GO_ON;
30540 + * cleanup dead connections once a second
30542 + * the idling event-handler can't cleanup connections itself and has to wait until the
30543 + * trigger cleans up
30545 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
30547 + proxy_request *req;
30549 + for (i = 0; i < p->backends->used; i++) {
30550 + proxy_backend *backend = p->backends->ptr[i];
30551 + proxy_connection_pool *pool = backend->pool;
30552 + proxy_address_pool *address_pool = backend->address_pool;
30554 + for (j = 0; j < pool->used; ) {
30555 + proxy_connection *proxy_con = pool->ptr[j];
30557 + /* remove-con is removing the current con and moves the good connections to the left
30558 + * no need to increment i */
30559 + if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
30560 + proxy_connection_pool_remove_connection(backend->pool, proxy_con);
30562 + fdevent_event_del(srv->ev, proxy_con->sock);
30563 + fdevent_unregister(srv->ev, proxy_con->sock);
30565 + proxy_connection_free(proxy_con);
30571 + /* active the disabled addresses again */
30572 + for (j = 0; j < address_pool->used; j++) {
30573 + proxy_address *address = address_pool->ptr[j];
30575 + if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
30577 + if (srv->cur_ts > address->disabled_until) {
30578 + address->disabled_until = 0;
30579 + address->state = PROXY_ADDRESS_STATE_ACTIVE;
30584 + /* wake up the connections from the backlog */
30585 + while ((req = proxy_backlog_shift(p->backlog))) {
30586 + connection *con = req->con;
30588 + joblist_append(srv, con);
30590 + proxy_request_free(req);
30593 + return HANDLER_GO_ON;
30596 +TRIGGER_FUNC(mod_proxy_trigger) {
30597 + plugin_data *p = p_d;
30600 + for (i = 0; i < srv->config_context->used; i++) {
30601 + mod_proxy_trigger_context(srv, p->config_storage[i]);
30604 + return HANDLER_GO_ON;
30607 +int mod_proxy_core_plugin_init(plugin *p) {
30608 + p->version = LIGHTTPD_VERSION_ID;
30609 + p->name = buffer_init_string("mod_proxy_core");
30611 + p->init = mod_proxy_core_init;
30612 + p->cleanup = mod_proxy_core_free;
30613 + p->set_defaults = mod_proxy_core_set_defaults;
30614 + p->handle_uri_clean = mod_proxy_core_check_extension;
30615 + p->handle_subrequest_start = mod_proxy_core_check_extension;
30616 + p->handle_subrequest = mod_proxy_core_check_extension;
30617 + p->connection_reset = mod_proxy_connection_reset;
30618 + p->handle_connection_close = mod_proxy_connection_close_callback;
30619 + p->handle_trigger = mod_proxy_trigger;
30625 --- ../lighttpd-1.4.11/src/mod_proxy_core.h 1970-01-01 03:00:00.000000000 +0300
30626 +++ lighttpd-1.4.12/src/mod_proxy_core.h 2006-07-18 13:03:40.000000000 +0300
30628 +#ifndef _MOD_PROXY_CORE_H_
30629 +#define _MOD_PROXY_CORE_H_
30631 +#include "buffer.h"
30634 +#define PROXY_BACKEND_CONNECT_PARAMS \
30635 + (server *srv, connection *con, void *p_d)
30637 +#define PROXY_BACKEND_CONNECT_RETVAL handler_t
30639 +#define PROXY_BACKEND_CONNECT(name) \
30640 + PROXY_BACKEND_CONNECT_RETVAL name PROXY_BACKEND_CONNECT_PARAMS
30642 +#define PROXY_BACKEND_CONNECT_PTR(name) \
30643 + PROXY_BACKEND_CONNECT_RETVAL (* name)PROXY_BACKEND_CONNECT_PARAMS
30646 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c 1970-01-01 03:00:00.000000000 +0300
30647 +++ lighttpd-1.4.12/src/mod_proxy_core_address.c 2006-07-20 00:57:20.000000000 +0300
30649 +#include <stdlib.h>
30650 +#include <string.h>
30653 +#include "sys-socket.h"
30654 +#include "mod_proxy_core_address.h"
30656 +proxy_address *proxy_address_init(void) {
30657 + proxy_address *address;
30659 + address = calloc(1, sizeof(*address));
30661 + address->name = buffer_init();
30666 +void proxy_address_free(proxy_address *address) {
30667 + if (!address) return;
30669 + buffer_free(address->name);
30675 +proxy_address_pool *proxy_address_pool_init(void) {
30676 + proxy_address_pool *address_pool;
30678 + address_pool = calloc(1, sizeof(*address_pool));
30680 + return address_pool;
30683 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
30684 + if (!address_pool) return;
30686 + FOREACH(address_pool, element, proxy_address_free(element));
30688 + if (address_pool->ptr) free(address_pool->ptr);
30690 + free(address_pool);
30693 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
30696 + /* check if this address is already known */
30698 + for (i = 0; i < address_pool->used; i++) {
30699 + proxy_address *pool_address = address_pool->ptr[i];
30701 + if (buffer_is_equal(address->name, pool_address->name)) {
30702 + TRACE("%s is already in the address-pool", BUF_STR(address->name));
30704 + proxy_address_free(address);
30710 + TRACE("adding %s to the address-pool", BUF_STR(address->name));
30712 + ARRAY_STATIC_PREPARE_APPEND(address_pool);
30714 + address_pool->ptr[address_pool->used++] = address;
30717 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
30718 + struct addrinfo *res = NULL, pref, *cur;
30720 + buffer *hostname = NULL, *port = NULL;
30723 + pref.ai_flags = 0;
30724 + pref.ai_family = PF_UNSPEC;
30725 + pref.ai_socktype = SOCK_STREAM;
30726 + pref.ai_protocol = 0;
30727 + pref.ai_addrlen = 0;
30728 + pref.ai_addr = NULL;
30729 + pref.ai_canonname = NULL;
30730 + pref.ai_next = NULL;
30732 + /* check the address style
30734 + * unix:/tmp/socket
30735 + * www.example.org
30736 + * www.example.org:80
30743 + if (buffer_is_empty(name)) return -1;
30745 + if (0 == strncmp(BUF_STR(name), "unix:", 5)) {
30746 + /* a unix domain socket */
30747 + ERROR("unix: scheme is not supported for %s", BUF_STR(name));
30749 + } else if (name->ptr[0] == '[') {
30750 + if (name->ptr[name->used - 1] == ']') {
30751 + /* no port-number attached */
30753 + hostname = buffer_init();
30754 + buffer_copy_string_len(hostname, BUF_STR(name) + 1, name->used - 3);
30755 + port = buffer_init_string("80");
30756 + } else if (NULL != (colon = strrchr(BUF_STR(name), ':'))) {
30757 + /* with port number */
30759 + hostname = buffer_init();
30760 + buffer_copy_string_len(hostname, BUF_STR(name) + 1, colon - BUF_STR(name) - 2);
30761 + port = buffer_init();
30762 + buffer_copy_string(port, colon + 1);
30765 + ERROR("this is neither [<ipv6-address>] nor [<ipv6-address>]:<port>: %s", BUF_STR(name));
30769 + } else if (name->ptr[name->used - 1] != ']' &&
30770 + NULL != (colon = strrchr(BUF_STR(name), ':'))) {
30772 + hostname = buffer_init();
30773 + buffer_copy_string_len(hostname, BUF_STR(name), colon - BUF_STR(name));
30774 + port = buffer_init();
30775 + buffer_copy_string(port, colon + 1);
30777 + /* no colon, just a IPv4 address or a domain name */
30779 + hostname = buffer_init_string(BUF_STR(name));
30780 + port = buffer_init_string("80");
30783 + TRACE("resolving %s on port %s", BUF_STR(hostname), BUF_STR(port));
30785 + if (0 != (ret = getaddrinfo(BUF_STR(hostname), BUF_STR(port), &pref, &res))) {
30786 + ERROR("getaddrinfo failed: %s", gai_strerror(ret));
30788 + buffer_free(hostname);
30789 + buffer_free(port);
30794 + buffer_free(hostname);
30795 + buffer_free(port);
30797 + for (cur = res; cur; cur = cur->ai_next) {
30798 + proxy_address *a = proxy_address_init();
30800 + memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
30802 + a->state = PROXY_ADDRESS_STATE_ACTIVE;
30803 + buffer_prepare_copy(a->name, 128);
30805 + switch (cur->ai_family) {
30807 + a->name->ptr[0] = '[';
30808 + inet_ntop(cur->ai_family, &(a->addr.ipv6.sin6_addr), a->name->ptr + 1, a->name->size - 2);
30809 + a->name->used = strlen(a->name->ptr) + 1;
30810 + buffer_append_string(a->name, "]:");
30811 + buffer_append_long(a->name, ntohs(a->addr.ipv6.sin6_port));
30814 + inet_ntop(cur->ai_family, &(a->addr.ipv4.sin_addr), a->name->ptr, a->name->size - 1);
30815 + a->name->used = strlen(a->name->ptr) + 1;
30817 + buffer_append_string(a->name, ":");
30818 + buffer_append_long(a->name, ntohs(a->addr.ipv4.sin_port));
30821 + ERROR("unknown address-family: %d", cur->ai_family);
30826 + proxy_address_pool_add(address_pool, a);
30829 + freeaddrinfo(res);
30835 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h 1970-01-01 03:00:00.000000000 +0300
30836 +++ lighttpd-1.4.12/src/mod_proxy_core_address.h 2006-07-18 13:03:40.000000000 +0300
30838 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
30839 +#define _MOD_PROXY_CORE_ADDRESS_H_
30842 +#include "buffer.h"
30843 +#include "sys-socket.h"
30844 +#include "array-static.h"
30847 + PROXY_ADDRESS_STATE_UNSET,
30848 + PROXY_ADDRESS_STATE_ACTIVE,
30849 + PROXY_ADDRESS_STATE_DISABLED,
30850 +} proxy_address_state_t;
30855 + buffer *name; /* a inet_ntoa() prepresentation of the address */
30857 + time_t last_used;
30858 + time_t disabled_until;
30860 + proxy_address_state_t state;
30863 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
30865 +proxy_address_pool *proxy_address_pool_init(void);
30866 +void proxy_address_pool_free(proxy_address_pool *address_pool);
30867 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
30868 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
30871 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c 1970-01-01 03:00:00.000000000 +0300
30872 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.c 2006-07-20 00:57:19.000000000 +0300
30874 +#include <stdlib.h>
30876 +#include "mod_proxy_core_backend.h"
30877 +#include "mod_proxy_core_pool.h"
30878 +#include "mod_proxy_core_address.h"
30880 +proxy_backend *proxy_backend_init(void) {
30881 + proxy_backend *backend;
30883 + backend = calloc(1, sizeof(*backend));
30884 + backend->pool = proxy_connection_pool_init();
30885 + backend->address_pool = proxy_address_pool_init();
30886 + backend->balancer = PROXY_BALANCE_RR;
30891 +void proxy_backend_free(proxy_backend *backend) {
30892 + if (!backend) return;
30894 + proxy_address_pool_free(backend->address_pool);
30895 + proxy_connection_pool_free(backend->pool);
30900 +proxy_backends *proxy_backends_init(void) {
30901 + proxy_backends *backends;
30903 + backends = calloc(1, sizeof(*backends));
30908 +void proxy_backends_free(proxy_backends *backends) {
30909 + FOREACH(backends, element, proxy_backend_free(element))
30911 + if (backends->ptr) free(backends->ptr);
30916 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
30917 + ARRAY_STATIC_PREPARE_APPEND(backends);
30919 + backends->ptr[backends->used++] = backend;
30921 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h 1970-01-01 03:00:00.000000000 +0300
30922 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.h 2006-07-18 13:03:40.000000000 +0300
30924 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
30925 +#define _MOD_PROXY_CORE_BACKEND_H_
30927 +#include "array-static.h"
30928 +#include "buffer.h"
30929 +#include "mod_proxy_core_address.h"
30930 +#include "mod_proxy_core_pool.h"
30931 +#include "sys-socket.h"
30934 + * a single DNS name might explode to several IP addresses
30937 + * - http://foo.bar/suburl/
30938 + * - https://foo.bar/suburl/
30939 + * - unix:/tmp/socket
30940 + * - tcp://foobar:1025/
30947 + * request-url-rewrite
30948 + * response-url-rewrite
30951 + PROXY_BALANCE_UNSET,
30952 + PROXY_BALANCE_FAIR,
30953 + PROXY_BALANCE_HASH,
30955 +} proxy_balance_t;
30960 + proxy_connection_pool *pool; /* pool of active connections */
30961 + int use_keepalive;
30963 + proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
30964 + proxy_balance_t balancer; /* how to choose a address from the address-pool */
30967 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
30969 +proxy_backend *proxy_backend_init(void);
30970 +void proxy_backend_free(proxy_backend *backend);
30972 +proxy_backends *proxy_backends_init(void);
30973 +void proxy_backends_free(proxy_backends *backends);
30974 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
30978 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c 1970-01-01 03:00:00.000000000 +0300
30979 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.c 2006-07-18 13:03:40.000000000 +0300
30981 +#include <stdlib.h>
30983 +#include "mod_proxy_core_backlog.h"
30984 +#include "array-static.h"
30986 +proxy_backlog *proxy_backlog_init(void) {
30987 + STRUCT_INIT(proxy_backlog, backlog);
30992 +void proxy_backlog_free(proxy_backlog *backlog) {
30993 + if (!backlog) return;
30998 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
30999 + /* first entry */
31000 + if (NULL == backlog->first) {
31001 + backlog->first = backlog->last = req;
31003 + backlog->last->next = req;
31004 + backlog->last = req;
31006 + backlog->length++;
31012 + * remove the first element from the backlog
31014 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
31015 + proxy_request *req = NULL;
31017 + if (!backlog->first) return req;
31019 + backlog->length--;
31021 + req = backlog->first;
31023 + backlog->first = req->next;
31025 + /* the backlog is empty */
31026 + if (backlog->first == NULL) backlog->last = NULL;
31031 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
31032 + proxy_request *req = NULL;
31034 + if (!backlog->first) return -1;
31035 + if (!con) return -1;
31037 + /* the first element is what we look for */
31038 + if (backlog->first->con == con) {
31039 + req = backlog->first;
31041 + backlog->first = req->next;
31042 + if (backlog->first == NULL) backlog->last = NULL;
31044 + backlog->length--;
31046 + proxy_request_free(req);
31052 + for (req = backlog->first; req && req->next; req = req->next) {
31053 + proxy_request *cur;
31055 + if (req->next->con != con) continue;
31057 + backlog->length--;
31058 + /* the next node is our searched connection */
31061 + req->next = cur->next;
31063 + /* the next node is the last one, make the current the new last */
31064 + if (cur == backlog->last) {
31065 + backlog->last = req;
31067 + cur->next = NULL;
31069 + proxy_request_free(req);
31077 +proxy_request *proxy_request_init(void) {
31078 + STRUCT_INIT(proxy_request, request);
31083 +void proxy_request_free(proxy_request *request) {
31084 + if (!request) return;
31090 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h 1970-01-01 03:00:00.000000000 +0300
31091 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.h 2006-07-18 13:03:40.000000000 +0300
31093 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
31094 +#define _MOD_PROXY_CORE_BACKLOG_H_
31096 +#include <sys/types.h>
31097 +#include <sys/time.h>
31099 +typedef struct _proxy_request {
31100 + void *con; /* a pointer to the client-connection, (type: connection) */
31102 + time_t added_ts; /* when was the entry added (for timeout handling) */
31104 + struct _proxy_request *next;
31108 + * a we can't get a connection from the pool, queue the request in the
31109 + * request queue (FIFO)
31111 + * - the queue is infinite
31112 + * - entries are removed after a timeout (status 504)
31115 + proxy_request *first; /* pull() does q->first = q->first->next */
31116 + proxy_request *last; /* push() does q->last = r */
31121 +proxy_backlog *proxy_backlog_init(void);
31122 +void proxy_backlog_free(proxy_backlog *backlog);
31125 + * append a request to the end
31127 + * @return 0 in success, -1 if full
31129 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
31132 + * remove the first request from the backlog
31134 + * @return NULL if backlog is empty, the request otherwise
31136 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
31138 + * remove the request with the connection 'con' from the backlog
31140 + * @return -1 if not found, 0 otherwise
31142 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
31144 +proxy_request *proxy_request_init(void);
31145 +void proxy_request_free(proxy_request *req);
31149 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c 1970-01-01 03:00:00.000000000 +0300
31150 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.c 2006-07-18 13:03:40.000000000 +0300
31153 +#include <stdlib.h>
31155 +#include "array-static.h"
31156 +#include "sys-files.h"
31158 +#include "mod_proxy_core_pool.h"
31160 +proxy_connection * proxy_connection_init(void) {
31161 + proxy_connection *con;
31163 + con = calloc(1, sizeof(*con));
31165 + con->sock = iosocket_init();
31170 +void proxy_connection_free(proxy_connection *con) {
31171 + if (!con) return;
31173 + iosocket_free(con->sock);
31178 +proxy_connection_pool *proxy_connection_pool_init(void) {
31179 + proxy_connection_pool *pool;
31181 + pool = calloc(1, sizeof(*pool));
31183 + /* default: max parallel connections to the backend
31185 + * this should match max-procs if we manage the procs ourself
31188 + pool->max_size = 8;
31193 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
31196 + if (!pool) return;
31198 + for (i = 0; i < pool->used; i++) {
31199 + proxy_connection_free(pool->ptr[i]);
31202 + if (pool->size) free(pool->ptr);
31207 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
31208 + ARRAY_STATIC_PREPARE_APPEND(pool);
31210 + pool->ptr[pool->used++] = c;
31213 + * remove the connection from the pool
31215 + * usually called on conn-shutdown
31217 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
31220 + if (pool->used == 0) return -1; /* empty */
31222 + for (i = 0; i < pool->used; i++) {
31223 + if (pool->ptr[i] == c) {
31228 + if (i == pool->used) return -1; /* not found */
31231 + * move all elements one to the left
31233 + * if the last element is going to be removed, skip the loop
31235 + for (; i < pool->used - 1; i++) {
31236 + pool->ptr[i] = pool->ptr[i + 1];
31244 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
31245 + proxy_connection *proxy_con = NULL;
31248 + /* search for a idling proxy connection with the given address */
31249 + for (i = 0; i < pool->used; i++) {
31250 + proxy_con = pool->ptr[i];
31252 + if (proxy_con->address == address &&
31253 + proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
31258 + if (i == pool->used) {
31259 + /* no idling connection found */
31261 + if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
31263 + proxy_con = proxy_connection_init();
31265 + proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
31266 + proxy_con->address = address;
31268 + proxy_connection_pool_add_connection(pool, proxy_con);
31270 + proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
31273 + *rcon = proxy_con;
31275 + return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
31279 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h 1970-01-01 03:00:00.000000000 +0300
31280 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.h 2006-07-18 13:03:40.000000000 +0300
31282 +#ifndef _MOD_PROXY_CORE_POOL_H_
31283 +#define _MOD_PROXY_CORE_POOL_H_
31285 +#include <sys/time.h>
31287 +#include "iosocket.h"
31288 +#include "array-static.h"
31289 +#include "mod_proxy_core_address.h"
31292 + PROXY_CONNECTION_STATE_UNSET,
31293 + PROXY_CONNECTION_STATE_CONNECTING,
31294 + PROXY_CONNECTION_STATE_CONNECTED,
31295 + PROXY_CONNECTION_STATE_IDLE,
31296 + PROXY_CONNECTION_STATE_CLOSED,
31297 +} proxy_connection_state_t;
31300 + * a connection to a proxy backend
31302 + * the connection is independent of the incoming request to allow keep-alive
31307 + time_t last_read; /* timeout handling for keep-alive connections */
31308 + time_t last_write;
31310 + proxy_address *address; /* the struct sock_addr for the sock */
31312 + proxy_connection_state_t state;
31313 +} proxy_connection;
31315 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
31318 + PROXY_CONNECTIONPOOL_UNSET,
31319 + PROXY_CONNECTIONPOOL_FULL,
31320 + PROXY_CONNECTIONPOOL_GOT_CONNECTION,
31321 +} proxy_connection_pool_t;
31323 +proxy_connection_pool *proxy_connection_pool_init(void);
31324 +void proxy_connection_pool_free(proxy_connection_pool *pool);
31326 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
31327 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
31329 +proxy_connection * proxy_connection_init(void);
31330 +void proxy_connection_free(proxy_connection *pool);
31334 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.c 1970-01-01 03:00:00.000000000 +0300
31335 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.c 2006-07-18 17:34:32.000000000 +0300
31337 +#include <stdlib.h>
31338 +#include <string.h>
31340 +#include "mod_proxy_core_rewrites.h"
31343 +proxy_rewrite *proxy_rewrite_init(void) {
31344 + STRUCT_INIT(proxy_rewrite, rewrite);
31346 + rewrite->header = buffer_init();
31347 + rewrite->match = buffer_init();
31348 + rewrite->replace = buffer_init();
31353 +void proxy_rewrite_free(proxy_rewrite *rewrite) {
31354 + if (!rewrite) return;
31356 + if (rewrite->regex) pcre_free(rewrite->regex);
31358 + buffer_free(rewrite->header);
31359 + buffer_free(rewrite->match);
31360 + buffer_free(rewrite->replace);
31365 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex) {
31366 + const char *errptr;
31369 + if (NULL == (rewrite->regex = pcre_compile(BUF_STR(regex),
31370 + 0, &errptr, &erroff, NULL))) {
31372 + TRACE("regex compilation for %s failed at %s", BUF_STR(regex), errptr);
31381 +proxy_rewrites *proxy_rewrites_init(void) {
31382 + STRUCT_INIT(proxy_rewrites, rewrites);
31387 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite) {
31388 + ARRAY_STATIC_PREPARE_APPEND(rewrites);
31390 + rewrites->ptr[rewrites->used++] = rewrite;
31393 +void proxy_rewrites_free(proxy_rewrites *rewrites) {
31394 + if (!rewrites) return;
31401 --- ../lighttpd-1.4.11/src/mod_proxy_core_rewrites.h 1970-01-01 03:00:00.000000000 +0300
31402 +++ lighttpd-1.4.12/src/mod_proxy_core_rewrites.h 2006-07-18 17:34:32.000000000 +0300
31404 +#ifndef _MOD_PROXY_CORE_REWRITES_H_
31405 +#define _MOD_PROXY_CORE_REWRITES_H_
31408 +#include "array-static.h"
31409 +#include "buffer.h"
31414 + pcre *regex; /* regex compiled from the <match> */
31420 +ARRAY_STATIC_DEF(proxy_rewrites, proxy_rewrite,);
31422 +proxy_rewrite *proxy_rewrite_init(void);
31423 +void proxy_rewrite_free(proxy_rewrite *rewrite);
31424 +int proxy_rewrite_set_regex(proxy_rewrite *rewrite, buffer *regex);
31426 +proxy_rewrites *proxy_rewrites_init(void);
31427 +void proxy_rewrites_add(proxy_rewrites *rewrites, proxy_rewrite *rewrite);
31428 +void proxy_rewrites_free(proxy_rewrites *rewrites);
31432 --- ../lighttpd-1.4.11/src/mod_redirect.c 2006-02-08 15:38:06.000000000 +0200
31433 +++ lighttpd-1.4.12/src/mod_redirect.c 2006-07-16 00:26:04.000000000 +0300
31434 @@ -22,35 +22,35 @@
31440 plugin_config **config_storage;
31442 - plugin_config conf;
31444 + plugin_config conf;
31447 INIT_FUNC(mod_redirect_init) {
31451 p = calloc(1, sizeof(*p));
31454 p->match_buf = buffer_init();
31455 p->location = buffer_init();
31461 FREE_FUNC(mod_redirect_free) {
31462 plugin_data *p = p_d;
31465 if (!p) return HANDLER_GO_ON;
31467 if (p->config_storage) {
31469 for (i = 0; i < srv->config_context->used; i++) {
31470 plugin_config *s = p->config_storage[i];
31473 pcre_keyvalue_buffer_free(s->redirect);
31478 free(p->config_storage);
31481 buffer_free(p->match_buf);
31482 buffer_free(p->location);
31488 return HANDLER_GO_ON;
31491 @@ -69,195 +69,137 @@
31492 plugin_data *p = p_d;
31496 - config_values_t cv[] = {
31498 + config_values_t cv[] = {
31499 { "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31500 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31504 if (!p) return HANDLER_ERROR;
31508 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31511 for (i = 0; i < srv->config_context->used; i++) {
31515 data_array *da = (data_array *)du;
31518 s = calloc(1, sizeof(plugin_config));
31519 s->redirect = pcre_keyvalue_buffer_init();
31522 cv[0].destination = s->redirect;
31525 p->config_storage[i] = s;
31526 ca = ((data_config *)srv->config_context->data[i])->value;
31529 if (0 != config_insert_values_global(srv, ca, cv)) {
31530 return HANDLER_ERROR;
31534 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
31535 /* no url.redirect defined */
31540 if (du->type != TYPE_ARRAY) {
31541 - log_error_write(srv, __FILE__, __LINE__, "sss",
31542 + log_error_write(srv, __FILE__, __LINE__, "sss",
31543 "unexpected type for key: ", "url.redirect", "array of strings");
31546 return HANDLER_ERROR;
31550 da = (data_array *)du;
31553 for (j = 0; j < da->value->used; j++) {
31554 if (da->value->data[j]->type != TYPE_STRING) {
31555 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
31556 - "unexpected type for key: ",
31558 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
31559 + "unexpected type for key: ",
31561 "[", da->value->data[j]->key, "](string)");
31564 return HANDLER_ERROR;
31567 - if (0 != pcre_keyvalue_buffer_append(s->redirect,
31569 + if (0 != pcre_keyvalue_buffer_append(s->redirect,
31570 ((data_string *)(da->value->data[j]))->key->ptr,
31571 ((data_string *)(da->value->data[j]))->value->ptr)) {
31573 - log_error_write(srv, __FILE__, __LINE__, "sb",
31575 + log_error_write(srv, __FILE__, __LINE__, "sb",
31576 "pcre-compile failed for", da->value->data[j]->key);
31582 return HANDLER_GO_ON;
31585 static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
31587 plugin_config *s = p->config_storage[0];
31590 p->conf.redirect = s->redirect;
31593 /* skip the first, the global context */
31594 for (i = 1; i < srv->config_context->used; i++) {
31595 data_config *dc = (data_config *)srv->config_context->data[i];
31596 s = p->config_storage[i];
31599 /* condition didn't match */
31600 if (!config_check_cond(srv, con, dc)) continue;
31604 for (j = 0; j < dc->value->used; j++) {
31605 data_unset *du = dc->value->data[j];
31608 if (0 == strcmp(du->key->ptr, "url.redirect")) {
31609 p->conf.redirect = s->redirect;
31610 p->conf.context = dc;
31619 static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
31621 plugin_data *p = p_data;
31630 * e.g. redirect /base/ to /index.php?section=base
31636 mod_redirect_patch_connection(srv, con, p);
31639 buffer_copy_string_buffer(p->match_buf, con->request.uri);
31641 - for (i = 0; i < p->conf.redirect->used; i++) {
31643 - pcre_extra *extra;
31644 - const char *pattern;
31645 - size_t pattern_len;
31647 - pcre_keyvalue *kv = p->conf.redirect->kv[i];
31652 - extra = kv->key_extra;
31653 - pattern = kv->value->ptr;
31654 - pattern_len = kv->value->used - 1;
31656 - if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31657 - if (n != PCRE_ERROR_NOMATCH) {
31658 - log_error_write(srv, __FILE__, __LINE__, "sd",
31659 - "execution error while matching: ", n);
31660 - return HANDLER_ERROR;
31663 - const char **list;
31664 - size_t start, end;
31668 - pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31670 - /* search for $[0-9] */
31672 - buffer_reset(p->location);
31674 - start = 0; end = pattern_len;
31675 - for (k = 0; k < pattern_len; k++) {
31676 - if ((pattern[k] == '$' || pattern[k] == '%') &&
31677 - isdigit((unsigned char)pattern[k + 1])) {
31680 - size_t num = pattern[k + 1] - '0';
31684 - buffer_append_string_len(p->location, pattern + start, end - start);
31686 - if (pattern[k] == '$') {
31687 - /* n is always > 0 */
31688 - if (num < (size_t)n) {
31689 - buffer_append_string(p->location, list[num]);
31692 - config_append_cond_match_buffer(con, p->conf.context, p->location, num);
31700 - buffer_append_string_len(p->location, pattern + start, pattern_len - start);
31704 - response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31706 - con->http_status = 301;
31707 - con->file_finished = 1;
31709 - return HANDLER_FINISHED;
31711 + i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
31714 + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31716 + con->http_status = 301;
31717 + con->file_finished = 1;
31719 + return HANDLER_FINISHED;
31721 + else if (i != PCRE_ERROR_NOMATCH) {
31722 + log_error_write(srv, __FILE__, __LINE__, "s",
31723 + "execution error while matching", i);
31735 return HANDLER_GO_ON;
31738 @@ -265,13 +207,13 @@
31739 int mod_redirect_plugin_init(plugin *p) {
31740 p->version = LIGHTTPD_VERSION_ID;
31741 p->name = buffer_init_string("redirect");
31744 p->init = mod_redirect_init;
31745 p->handle_uri_clean = mod_redirect_uri_handler;
31746 p->set_defaults = mod_redirect_set_defaults;
31747 p->cleanup = mod_redirect_free;
31755 --- ../lighttpd-1.4.11/src/mod_rewrite.c 2005-09-29 20:59:10.000000000 +0300
31756 +++ lighttpd-1.4.12/src/mod_rewrite.c 2006-07-16 00:26:03.000000000 +0300
31761 -#ifdef HAVE_PCRE_H
31771 - rewrite_rule **ptr;
31775 -} rewrite_rule_buffer;
31778 - rewrite_rule_buffer *rewrite;
31779 + pcre_keyvalue_buffer *rewrite;
31781 data_config *context; /* to which apply me */
31784 @@ -42,20 +26,20 @@
31790 plugin_config **config_storage;
31792 - plugin_config conf;
31794 + plugin_config conf;
31797 static handler_ctx * handler_ctx_init() {
31798 handler_ctx * hctx;
31801 hctx = calloc(1, sizeof(*hctx));
31804 hctx->state = REWRITE_STATE_UNSET;
31811 @@ -63,207 +47,136 @@
31815 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
31816 - rewrite_rule_buffer *kvb;
31818 - kvb = calloc(1, sizeof(*kvb));
31823 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
31824 -#ifdef HAVE_PCRE_H
31826 - const char *errptr;
31829 - if (!key) return -1;
31831 - if (kvb->size == 0) {
31835 - kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
31837 - for(i = 0; i < kvb->size; i++) {
31838 - kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31840 - } else if (kvb->used == kvb->size) {
31843 - kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
31845 - for(i = kvb->used; i < kvb->size; i++) {
31846 - kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31850 - if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
31851 - 0, &errptr, &erroff, NULL))) {
31856 - kvb->ptr[kvb->used]->value = buffer_init();
31857 - buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
31858 - kvb->ptr[kvb->used]->once = once;
31873 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
31874 -#ifdef HAVE_PCRE_H
31877 - for (i = 0; i < kvb->size; i++) {
31878 - if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
31879 - if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
31880 - free(kvb->ptr[i]);
31883 - if (kvb->ptr) free(kvb->ptr);
31890 INIT_FUNC(mod_rewrite_init) {
31894 p = calloc(1, sizeof(*p));
31897 p->match_buf = buffer_init();
31903 FREE_FUNC(mod_rewrite_free) {
31904 plugin_data *p = p_d;
31909 if (!p) return HANDLER_GO_ON;
31912 buffer_free(p->match_buf);
31913 if (p->config_storage) {
31915 for (i = 0; i < srv->config_context->used; i++) {
31916 plugin_config *s = p->config_storage[i];
31917 - rewrite_rule_buffer_free(s->rewrite);
31919 + pcre_keyvalue_buffer_free(s->rewrite);
31920 + buffer_free(s->once);
31924 free(p->config_storage);
31931 return HANDLER_GO_ON;
31934 static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
31938 if (NULL != (du = array_get_element(ca, option))) {
31939 data_array *da = (data_array *)du;
31943 if (du->type != TYPE_ARRAY) {
31944 - log_error_write(srv, __FILE__, __LINE__, "sss",
31945 + log_error_write(srv, __FILE__, __LINE__, "sss",
31946 "unexpected type for key: ", option, "array of strings");
31949 return HANDLER_ERROR;
31953 da = (data_array *)du;
31956 for (j = 0; j < da->value->used; j++) {
31957 if (da->value->data[j]->type != TYPE_STRING) {
31958 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
31959 - "unexpected type for key: ",
31961 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
31962 + "unexpected type for key: ",
31964 "[", da->value->data[j]->key, "](string)");
31967 return HANDLER_ERROR;
31970 - if (0 != rewrite_rule_buffer_append(s->rewrite,
31971 - ((data_string *)(da->value->data[j]))->key,
31972 - ((data_string *)(da->value->data[j]))->value,
31975 + if (0 != pcre_keyvalue_buffer_append(s->rewrite,
31976 + ((data_string *)(da->value->data[j]))->key->ptr,
31977 + ((data_string *)(da->value->data[j]))->value->ptr)) {
31979 - log_error_write(srv, __FILE__, __LINE__, "sb",
31980 + log_error_write(srv, __FILE__, __LINE__, "sb",
31981 "pcre-compile failed for", da->value->data[j]->key);
31983 - log_error_write(srv, __FILE__, __LINE__, "s",
31984 + log_error_write(srv, __FILE__, __LINE__, "s",
31985 "pcre support is missing, please install libpcre and the headers");
31990 + buffer_append_string_len(s->once, CONST_STR_LEN("1"));
31992 + buffer_append_string_len(s->once, CONST_STR_LEN("0"));
32001 SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
32002 plugin_data *p = p_d;
32005 - config_values_t cv[] = {
32007 + config_values_t cv[] = {
32008 { "url.rewrite-repeat", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
32009 { "url.rewrite-once", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
32011 - /* old names, still supported
32014 + /* old names, still supported
32016 * url.rewrite remapped to url.rewrite-once
32017 * url.rewrite-final is url.rewrite-once
32021 { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
32022 { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
32023 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32027 if (!p) return HANDLER_ERROR;
32031 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32034 for (i = 0; i < srv->config_context->used; i++) {
32039 s = calloc(1, sizeof(plugin_config));
32040 - s->rewrite = rewrite_rule_buffer_init();
32042 - cv[0].destination = s->rewrite;
32043 - cv[1].destination = s->rewrite;
32044 - cv[2].destination = s->rewrite;
32046 + s->rewrite = pcre_keyvalue_buffer_init();
32047 + s->once = buffer_init();
32049 p->config_storage[i] = s;
32050 ca = ((data_config *)srv->config_context->data[i])->value;
32053 if (0 != config_insert_values_global(srv, ca, cv)) {
32054 return HANDLER_ERROR;
32058 parse_config_entry(srv, s, ca, "url.rewrite-once", 1);
32059 parse_config_entry(srv, s, ca, "url.rewrite-final", 1);
32060 parse_config_entry(srv, s, ca, "url.rewrite", 1);
32061 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
32065 return HANDLER_GO_ON;
32068 @@ -271,157 +184,107 @@
32070 plugin_config *s = p->config_storage[0];
32071 p->conf.rewrite = s->rewrite;
32073 + p->conf.once = s->once;
32075 /* skip the first, the global context */
32076 for (i = 1; i < srv->config_context->used; i++) {
32077 data_config *dc = (data_config *)srv->config_context->data[i];
32078 s = p->config_storage[i];
32081 if (COMP_HTTP_URL == dc->comp) continue;
32084 /* condition didn't match */
32085 if (!config_check_cond(srv, con, dc)) continue;
32089 for (j = 0; j < dc->value->used; j++) {
32090 data_unset *du = dc->value->data[j];
32093 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
32094 p->conf.rewrite = s->rewrite;
32095 + p->conf.once = s->once;
32096 p->conf.context = dc;
32097 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
32098 p->conf.rewrite = s->rewrite;
32099 + p->conf.once = s->once;
32100 p->conf.context = dc;
32101 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
32102 p->conf.rewrite = s->rewrite;
32103 + p->conf.once = s->once;
32104 p->conf.context = dc;
32105 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
32106 p->conf.rewrite = s->rewrite;
32107 + p->conf.once = s->once;
32108 p->conf.context = dc;
32117 URIHANDLER_FUNC(mod_rewrite_con_reset) {
32118 plugin_data *p = p_d;
32124 if (con->plugin_ctx[p->id]) {
32125 handler_ctx_free(con->plugin_ctx[p->id]);
32126 con->plugin_ctx[p->id] = NULL;
32130 return HANDLER_GO_ON;
32133 URIHANDLER_FUNC(mod_rewrite_uri_handler) {
32135 plugin_data *p = p_d;
32145 * e.g. rewrite /base/ to /index.php?section=base
32151 if (con->plugin_ctx[p->id]) {
32152 hctx = con->plugin_ctx[p->id];
32155 if (hctx->loops++ > 100) {
32156 - log_error_write(srv, __FILE__, __LINE__, "s",
32157 + log_error_write(srv, __FILE__, __LINE__, "s",
32158 "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
32161 return HANDLER_ERROR;
32165 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
32169 mod_rewrite_patch_connection(srv, con, p);
32171 if (!p->conf.rewrite) return HANDLER_GO_ON;
32174 buffer_copy_string_buffer(p->match_buf, con->request.uri);
32176 - for (i = 0; i < p->conf.rewrite->used; i++) {
32178 - const char *pattern;
32179 - size_t pattern_len;
32181 - rewrite_rule *rule = p->conf.rewrite->ptr[i];
32185 - match = rule->key;
32186 - pattern = rule->value->ptr;
32187 - pattern_len = rule->value->used - 1;
32189 - if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
32190 - if (n != PCRE_ERROR_NOMATCH) {
32191 - log_error_write(srv, __FILE__, __LINE__, "sd",
32192 - "execution error while matching: ", n);
32193 - return HANDLER_ERROR;
32196 - const char **list;
32197 - size_t start, end;
32201 - pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
32203 - /* search for $[0-9] */
32205 - buffer_reset(con->request.uri);
32207 - start = 0; end = pattern_len;
32208 - for (k = 0; k < pattern_len; k++) {
32209 - if ((pattern[k] == '$' || pattern[k] == '%') &&
32210 - isdigit((unsigned char)pattern[k + 1])) {
32213 - size_t num = pattern[k + 1] - '0';
32217 - buffer_append_string_len(con->request.uri, pattern + start, end - start);
32219 - if (pattern[k] == '$') {
32220 - /* n is always > 0 */
32221 - if (num < (size_t)n) {
32222 - buffer_append_string(con->request.uri, list[num]);
32225 - config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
32233 - buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
32237 - hctx = handler_ctx_init();
32239 - con->plugin_ctx[p->id] = hctx;
32241 - if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
32243 - return HANDLER_COMEBACK;
32245 + i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
32248 + hctx = handler_ctx_init();
32250 + con->plugin_ctx[p->id] = hctx;
32252 + if (p->conf.once->ptr[i] == '1')
32253 + hctx->state = REWRITE_STATE_FINISHED;
32255 + return HANDLER_COMEBACK;
32257 + else if (i != PCRE_ERROR_NOMATCH) {
32258 + log_error_write(srv, __FILE__, __LINE__, "s",
32259 + "execution error while matching", i);
32267 @@ -434,17 +297,17 @@
32268 int mod_rewrite_plugin_init(plugin *p) {
32269 p->version = LIGHTTPD_VERSION_ID;
32270 p->name = buffer_init_string("rewrite");
32273 p->init = mod_rewrite_init;
32274 /* it has to stay _raw as we are matching on uri + querystring
32278 p->handle_uri_raw = mod_rewrite_uri_handler;
32279 p->set_defaults = mod_rewrite_set_defaults;
32280 p->cleanup = mod_rewrite_free;
32281 p->connection_reset = mod_rewrite_con_reset;
32289 --- ../lighttpd-1.4.11/src/mod_rrdtool.c 2005-08-22 01:52:24.000000000 +0300
32290 +++ lighttpd-1.4.12/src/mod_rrdtool.c 2006-07-18 13:03:40.000000000 +0300
32292 #include <stdlib.h>
32294 #include <string.h>
32295 -#include <unistd.h>
32299 @@ -20,10 +19,14 @@
32300 /* no need for waitpid if we don't have fork */
32301 #include <sys/wait.h>
32304 +#include "sys-files.h"
32305 +#include "sys-process.h"
32308 buffer *path_rrdtool_bin;
32312 double requests, *requests_ptr;
32313 double bytes_written, *bytes_written_ptr;
32314 double bytes_read, *bytes_read_ptr;
32315 @@ -31,84 +34,84 @@
32325 int read_fd, write_fd;
32329 int rrdtool_running;
32332 plugin_config **config_storage;
32333 plugin_config conf;
32336 INIT_FUNC(mod_rrd_init) {
32340 p = calloc(1, sizeof(*p));
32343 p->resp = buffer_init();
32344 p->cmd = buffer_init();
32350 FREE_FUNC(mod_rrd_free) {
32351 plugin_data *p = p_d;
32355 if (!p) return HANDLER_GO_ON;
32358 if (p->config_storage) {
32359 for (i = 0; i < srv->config_context->used; i++) {
32360 plugin_config *s = p->config_storage[i];
32363 buffer_free(s->path_rrdtool_bin);
32364 buffer_free(s->path_rrd);
32370 buffer_free(p->cmd);
32371 buffer_free(p->resp);
32374 free(p->config_storage);
32377 if (p->rrdtool_pid) {
32380 close(p->write_fd);
32383 /* collect status */
32384 waitpid(p->rrdtool_pid, &status, 0);
32392 return HANDLER_GO_ON;
32395 int mod_rrd_create_pipe(server *srv, plugin_data *p) {
32399 int to_rrdtool_fds[2];
32400 int from_rrdtool_fds[2];
32403 if (pipe(to_rrdtool_fds)) {
32404 - log_error_write(srv, __FILE__, __LINE__, "ss",
32405 + log_error_write(srv, __FILE__, __LINE__, "ss",
32406 "pipe failed: ", strerror(errno));
32411 if (pipe(from_rrdtool_fds)) {
32412 - log_error_write(srv, __FILE__, __LINE__, "ss",
32413 + log_error_write(srv, __FILE__, __LINE__, "ss",
32414 "pipe failed: ", strerror(errno));
32420 switch (pid = fork()) {
32422 @@ -117,33 +120,28 @@
32428 /* move stdout to from_rrdtool_fd[1] */
32429 close(STDOUT_FILENO);
32430 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
32431 close(from_rrdtool_fds[1]);
32433 close(from_rrdtool_fds[0]);
32436 /* move the stdin to to_rrdtool_fd[0] */
32437 close(STDIN_FILENO);
32438 dup2(to_rrdtool_fds[0], STDIN_FILENO);
32439 close(to_rrdtool_fds[0]);
32441 close(to_rrdtool_fds[1]);
32444 close(STDERR_FILENO);
32446 - if (srv->errorlog_mode == ERRORLOG_FILE) {
32447 - dup2(srv->errorlog_fd, STDERR_FILENO);
32448 - close(srv->errorlog_fd);
32454 args = malloc(sizeof(*args) * argc);
32458 args[i++] = p->conf.path_rrdtool_bin->ptr;
32461 @@ -152,12 +150,12 @@
32462 for (i = 3; i < 256; i++) {
32468 execv(args[0], args);
32471 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
32477 @@ -168,19 +166,19 @@
32483 close(from_rrdtool_fds[1]);
32484 close(to_rrdtool_fds[0]);
32487 /* register PID and wait for them asyncronously */
32488 p->write_fd = to_rrdtool_fds[1];
32489 p->read_fd = from_rrdtool_fds[0];
32490 p->rrdtool_pid = pid;
32501 @@ -189,19 +187,19 @@
32503 static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
32507 /* check if DB already exists */
32508 if (0 == stat(s->path_rrd->ptr, &st)) {
32509 /* check if it is plain file */
32510 if (!S_ISREG(st.st_mode)) {
32511 - log_error_write(srv, __FILE__, __LINE__, "sb",
32512 + log_error_write(srv, __FILE__, __LINE__, "sb",
32513 "not a regular file:", s->path_rrd);
32514 return HANDLER_ERROR;
32518 /* create a new one */
32521 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
32522 buffer_append_string_buffer(p->cmd, s->path_rrd);
32523 buffer_append_string(p->cmd, " --step 60 ");
32524 @@ -220,158 +218,155 @@
32525 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
32526 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
32527 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
32530 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32531 - log_error_write(srv, __FILE__, __LINE__, "ss",
32532 + log_error_write(srv, __FILE__, __LINE__, "ss",
32533 "rrdtool-write: failed", strerror(errno));
32536 return HANDLER_ERROR;
32540 buffer_prepare_copy(p->resp, 4096);
32541 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32542 - log_error_write(srv, __FILE__, __LINE__, "ss",
32543 + log_error_write(srv, __FILE__, __LINE__, "ss",
32544 "rrdtool-read: failed", strerror(errno));
32547 return HANDLER_ERROR;
32554 if (p->resp->ptr[0] != 'O' ||
32555 p->resp->ptr[1] != 'K') {
32556 - log_error_write(srv, __FILE__, __LINE__, "sbb",
32557 + log_error_write(srv, __FILE__, __LINE__, "sbb",
32558 "rrdtool-response:", p->cmd, p->resp);
32561 return HANDLER_ERROR;
32566 return HANDLER_GO_ON;
32569 -#define PATCH(x) \
32570 - p->conf.x = s->x;
32571 static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
32573 plugin_config *s = p->config_storage[0];
32575 - PATCH(path_rrdtool_bin);
32579 + PATCH_OPTION(path_rrdtool_bin);
32580 + PATCH_OPTION(path_rrd);
32582 p->conf.bytes_written_ptr = &(s->bytes_written);
32583 p->conf.bytes_read_ptr = &(s->bytes_read);
32584 p->conf.requests_ptr = &(s->requests);
32587 /* skip the first, the global context */
32588 for (i = 1; i < srv->config_context->used; i++) {
32589 data_config *dc = (data_config *)srv->config_context->data[i];
32590 s = p->config_storage[i];
32593 /* condition didn't match */
32594 if (!config_check_cond(srv, con, dc)) continue;
32598 for (j = 0; j < dc->value->used; j++) {
32599 data_unset *du = dc->value->data[j];
32602 if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
32604 + PATCH_OPTION(path_rrd);
32605 /* get pointers to double values */
32608 p->conf.bytes_written_ptr = &(s->bytes_written);
32609 p->conf.bytes_read_ptr = &(s->bytes_read);
32610 p->conf.requests_ptr = &(s->requests);
32620 SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
32621 plugin_data *p = p_d;
32624 - config_values_t cv[] = {
32626 + config_values_t cv[] = {
32627 { "rrdtool.binary", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
32628 { "rrdtool.db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
32629 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32633 if (!p) return HANDLER_ERROR;
32636 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32639 for (i = 0; i < srv->config_context->used; i++) {
32643 s = calloc(1, sizeof(plugin_config));
32644 s->path_rrdtool_bin = buffer_init();
32645 s->path_rrd = buffer_init();
32647 s->bytes_written = 0;
32651 cv[0].destination = s->path_rrdtool_bin;
32652 cv[1].destination = s->path_rrd;
32655 p->config_storage[i] = s;
32658 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
32659 return HANDLER_ERROR;
32663 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
32664 /* path_rrdtool_bin is a global option */
32666 - log_error_write(srv, __FILE__, __LINE__, "s",
32668 + log_error_write(srv, __FILE__, __LINE__, "s",
32669 "rrdtool.binary can only be set as a global option.");
32672 return HANDLER_ERROR;
32679 p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
32680 p->rrdtool_running = 0;
32683 /* check for dir */
32686 if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
32687 - log_error_write(srv, __FILE__, __LINE__, "s",
32688 + log_error_write(srv, __FILE__, __LINE__, "s",
32689 "rrdtool.binary has to be set");
32690 return HANDLER_ERROR;
32694 /* open the pipe to rrdtool */
32695 if (mod_rrd_create_pipe(srv, p)) {
32696 return HANDLER_ERROR;
32700 p->rrdtool_running = 1;
32703 return HANDLER_GO_ON;
32706 TRIGGER_FUNC(mod_rrd_trigger) {
32707 plugin_data *p = p_d;
32711 if (!p->rrdtool_running) return HANDLER_GO_ON;
32712 if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
32715 for (i = 0; i < srv->config_context->used; i++) {
32716 plugin_config *s = p->config_storage[i];
32720 if (buffer_is_empty(s->path_rrd)) continue;
32723 /* write the data down every minute */
32726 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
32729 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
32730 buffer_append_string_buffer(p->cmd, s->path_rrd);
32731 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
32732 @@ -381,69 +376,69 @@
32733 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
32734 buffer_append_long(p->cmd, s->requests);
32735 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
32738 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32739 p->rrdtool_running = 0;
32741 - log_error_write(srv, __FILE__, __LINE__, "ss",
32743 + log_error_write(srv, __FILE__, __LINE__, "ss",
32744 "rrdtool-write: failed", strerror(errno));
32747 return HANDLER_ERROR;
32751 buffer_prepare_copy(p->resp, 4096);
32752 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32753 p->rrdtool_running = 0;
32755 - log_error_write(srv, __FILE__, __LINE__, "ss",
32757 + log_error_write(srv, __FILE__, __LINE__, "ss",
32758 "rrdtool-read: failed", strerror(errno));
32761 return HANDLER_ERROR;
32768 if (p->resp->ptr[0] != 'O' ||
32769 p->resp->ptr[1] != 'K') {
32770 p->rrdtool_running = 0;
32772 - log_error_write(srv, __FILE__, __LINE__, "sbb",
32774 + log_error_write(srv, __FILE__, __LINE__, "sbb",
32775 "rrdtool-response:", p->cmd, p->resp);
32778 return HANDLER_ERROR;
32781 s->bytes_written = 0;
32786 return HANDLER_GO_ON;
32789 REQUESTDONE_FUNC(mod_rrd_account) {
32790 plugin_data *p = p_d;
32793 mod_rrd_patch_connection(srv, con, p);
32796 *(p->conf.requests_ptr) += 1;
32797 *(p->conf.bytes_written_ptr) += con->bytes_written;
32798 *(p->conf.bytes_read_ptr) += con->bytes_read;
32801 return HANDLER_GO_ON;
32804 int mod_rrdtool_plugin_init(plugin *p) {
32805 p->version = LIGHTTPD_VERSION_ID;
32806 p->name = buffer_init_string("rrd");
32809 p->init = mod_rrd_init;
32810 p->cleanup = mod_rrd_free;
32811 p->set_defaults= mod_rrd_set_defaults;
32814 p->handle_trigger = mod_rrd_trigger;
32815 p->handle_request_done = mod_rrd_account;
32823 --- ../lighttpd-1.4.11/src/mod_scgi.c 2006-03-04 17:15:26.000000000 +0200
32824 +++ lighttpd-1.4.12/src/mod_scgi.c 2006-07-18 13:03:40.000000000 +0300
32826 #include <sys/types.h>
32827 -#include <unistd.h>
32830 #include <string.h>
32832 #include "connections.h"
32833 #include "response.h"
32834 #include "joblist.h"
32835 +#include "http_resp.h"
32837 #include "plugin.h"
32842 #include "sys-socket.h"
32844 +#include "sys-files.h"
32845 +#include "sys-strings.h"
32846 +#include "sys-process.h"
32848 #ifndef UNIX_PATH_MAX
32849 # define UNIX_PATH_MAX 108
32850 @@ -46,30 +48,29 @@
32851 enum {EOL_UNSET, EOL_N, EOL_RN};
32859 * - add timeout for a connect to a non-scgi process
32860 * (use state_timestamp + state)
32865 typedef struct scgi_proc {
32866 size_t id; /* id will be between 1 and max_procs */
32867 buffer *socket; /* config.socket + "-" + id */
32868 unsigned port; /* config.port + pno */
32870 - pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
32872 + pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
32874 size_t load; /* number of requests waiting on this process */
32876 time_t last_used; /* see idle_timeout */
32877 size_t requests; /* see max_requests */
32878 struct scgi_proc *prev, *next; /* see first */
32881 time_t disable_ts; /* replace by host->something */
32886 enum { PROC_STATE_UNSET, /* init-phase */
32888 PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
32889 PROC_STATE_DIED, /* marked as dead, should be restarted */
32890 PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
32896 @@ -86,20 +87,20 @@
32897 * sorted by lowest load
32899 * whenever a job is done move it up in the list
32900 - * until it is sorted, move it down as soon as the
32901 + * until it is sorted, move it down as soon as the
32904 - scgi_proc *first;
32905 - scgi_proc *unused_procs;
32906 + scgi_proc *first;
32907 + scgi_proc *unused_procs;
32911 * spawn at least min_procs, at max_procs.
32913 - * as soon as the load of the first entry
32914 + * as soon as the load of the first entry
32915 * is max_load_per_proc we spawn a new one
32916 - * and add it to the first entry and give it
32917 + * and add it to the first entry and give it
32923 unsigned short min_procs;
32924 @@ -111,44 +112,44 @@
32927 * kick the process from the list if it was not
32928 - * used for idle_timeout until min_procs is
32929 + * used for idle_timeout until min_procs is
32930 * reached. this helps to get the processlist
32931 * small again we had a small peak load.
32936 unsigned short idle_timeout;
32940 * time after a disabled remote connection is tried to be re-enabled
32948 unsigned short disable_time;
32951 * same scgi processes get a little bit larger
32952 - * than wanted. max_requests_per_proc kills a
32953 + * than wanted. max_requests_per_proc kills a
32954 * process after a number of handled requests.
32957 size_t max_requests_per_proc;
32968 - * if host is one of the local IP adresses the
32969 + * if host is one of the local IP adresses the
32970 * whole connection is local
32972 * if tcp/ip should be used host AND port have
32973 - * to be specified
32977 + * to be specified
32981 unsigned short port;
32984 @@ -161,7 +162,7 @@
32986 buffer *unixsocket;
32988 - /* if socket is local we can start the scgi
32989 + /* if socket is local we can start the scgi
32992 * bin-path is the path to the binary
32993 @@ -169,19 +170,19 @@
32994 * check min_procs and max_procs for the number
32995 * of process to start-up
32997 - buffer *bin_path;
32999 - /* bin-path is set bin-environment is taken to
33000 + buffer *bin_path;
33002 + /* bin-path is set bin-environment is taken to
33003 * create the environement before starting the
33011 array *bin_env_copy;
33015 - * docroot-translation between URL->phys and the
33016 + * docroot-translation between URL->phys and the
33020 @@ -192,7 +193,7 @@
33024 - * check_local tell you if the phys file is stat()ed
33025 + * check_local tell you if the phys file is stat()ed
33026 * or not. FastCGI doesn't care if the service is
33027 * remote. If the web-server side doesn't contain
33028 * the scgi-files we should not stat() for them
33029 @@ -202,33 +203,33 @@
33032 * append PATH_INFO to SCRIPT_FILENAME
33035 * php needs this if cgi.fix_pathinfo is provied
33041 ssize_t load; /* replace by host->load */
33043 size_t max_id; /* corresponds most of the time to
33047 only if a process is killed max_id waits for the process itself
33048 to die and decrements its afterwards */
33049 } scgi_extension_host;
33052 * one extension can have multiple hosts assigned
33053 - * one host can spawn additional processes on the same
33054 + * one host can spawn additional processes on the same
33055 * socket (if we control it)
33057 * ext -> host -> procs
33060 - * if the scgi process is remote that whole goes down
33061 + * if the scgi process is remote that whole goes down
33064 * ext -> host -> procs
33068 * in case of PHP and FCGI_CHILDREN we have again a procs
33069 * but we don't control it directly.
33070 @@ -239,7 +240,7 @@
33071 buffer *key; /* like .php */
33073 scgi_extension_host **hosts;
33079 @@ -253,14 +254,14 @@
33097 @@ -268,52 +269,51 @@
33098 /* generic plugin data, shared between all connections */
33107 - buffer *parse_response;
33112 plugin_config **config_storage;
33115 plugin_config conf; /* this is only used as long as no handler_ctx is setup */
33118 /* connection specific data */
33119 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
33120 - FCGI_STATE_WRITE, FCGI_STATE_READ
33123 + SCGI_STATE_CONNECT,
33124 + SCGI_STATE_PREPARE_WRITE,
33125 + SCGI_STATE_WRITE,
33126 + SCGI_STATE_RESPONSE_HEADER,
33127 + SCGI_STATE_RESPONSE_CONTENT,
33129 } scgi_connection_state_t;
33132 - buffer *response;
33133 - size_t response_len;
33134 - int response_type;
33135 - int response_padding;
33138 scgi_extension_host *host;
33141 scgi_connection_state_t state;
33142 time_t state_timestamp;
33145 int reconnects; /* number of reconnect attempts */
33152 - buffer *response_header;
33155 int delayed; /* flag to mark that the connect() is delayed */
33159 - int fd; /* fd to the scgi process */
33160 - int fde_ndx; /* index into the fd-event buffer */
33161 + iosocket *sock; /* fd to the scgi process */
33167 plugin_config conf;
33170 connection *remote_conn; /* dumb pointer */
33171 plugin_data *plugin_data; /* dumb pointer */
33173 @@ -328,42 +328,30 @@
33175 static handler_ctx * handler_ctx_init() {
33176 handler_ctx * hctx;
33179 hctx = calloc(1, sizeof(*hctx));
33182 - hctx->fde_ndx = -1;
33184 - hctx->response = buffer_init();
33185 - hctx->response_header = buffer_init();
33188 + hctx->sock = iosocket_init();;
33190 hctx->request_id = 0;
33191 - hctx->state = FCGI_STATE_INIT;
33192 + hctx->state = SCGI_STATE_INIT;
33195 - hctx->response_len = 0;
33196 - hctx->response_type = 0;
33197 - hctx->response_padding = 0;
33201 hctx->reconnects = 0;
33203 hctx->wb = chunkqueue_init();
33205 + hctx->rb = chunkqueue_init();
33210 static void handler_ctx_free(handler_ctx *hctx) {
33211 - buffer_free(hctx->response);
33212 - buffer_free(hctx->response_header);
33214 chunkqueue_free(hctx->wb);
33217 - if (hctx->rb->ptr) free(hctx->rb->ptr);
33221 + chunkqueue_free(hctx->rb);
33223 + iosocket_free(hctx->sock);
33228 @@ -372,20 +360,20 @@
33230 f = calloc(1, sizeof(*f));
33231 f->socket = buffer_init();
33241 void scgi_process_free(scgi_proc *f) {
33245 scgi_process_free(f->next);
33248 buffer_free(f->socket);
33254 @@ -400,62 +388,62 @@
33255 f->bin_path = buffer_init();
33256 f->bin_env = array_init();
33257 f->bin_env_copy = array_init();
33263 void scgi_host_free(scgi_extension_host *h) {
33267 buffer_free(h->host);
33268 buffer_free(h->unixsocket);
33269 buffer_free(h->docroot);
33270 buffer_free(h->bin_path);
33271 array_free(h->bin_env);
33272 array_free(h->bin_env_copy);
33275 scgi_process_free(h->first);
33276 scgi_process_free(h->unused_procs);
33284 scgi_exts *scgi_extensions_init() {
33287 f = calloc(1, sizeof(*f));
33293 void scgi_extensions_free(scgi_exts *f) {
33300 for (i = 0; i < f->used; i++) {
33301 scgi_extension *fe;
33308 for (j = 0; j < fe->used; j++) {
33309 scgi_extension_host *h;
33319 buffer_free(fe->key);
33333 @@ -504,99 +492,103 @@
33337 - fe->hosts[fe->used++] = fh;
33338 + fe->hosts[fe->used++] = fh;
33345 INIT_FUNC(mod_scgi_init) {
33349 p = calloc(1, sizeof(*p));
33352 p->scgi_env = buffer_init();
33355 p->path = buffer_init();
33356 - p->parse_response = buffer_init();
33358 + p->resp = http_response_init();
33364 FREE_FUNC(mod_scgi_free) {
33365 plugin_data *p = p_d;
33370 buffer_free(p->scgi_env);
33371 buffer_free(p->path);
33372 - buffer_free(p->parse_response);
33374 + http_response_free(p->resp);
33376 if (p->config_storage) {
33378 for (i = 0; i < srv->config_context->used; i++) {
33379 plugin_config *s = p->config_storage[i];
33388 for (j = 0; j < exts->used; j++) {
33389 scgi_extension *ex;
33392 ex = exts->exts[j];
33395 for (n = 0; n < ex->used; n++) {
33397 scgi_extension_host *host;
33400 host = ex->hosts[n];
33403 for (proc = host->first; proc; proc = proc->next) {
33405 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33407 - if (proc->is_local &&
33410 + if (proc->is_local &&
33411 !buffer_is_empty(proc->socket)) {
33412 unlink(proc->socket->ptr);
33417 for (proc = host->unused_procs; proc; proc = proc->next) {
33419 if (proc->pid != 0) kill(proc->pid, SIGTERM);
33421 - if (proc->is_local &&
33424 + if (proc->is_local &&
33425 !buffer_is_empty(proc->socket)) {
33426 unlink(proc->socket->ptr);
33433 scgi_extensions_free(s->exts);
33438 free(p->config_storage);
33445 return HANDLER_GO_ON;
33448 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
33452 if (!key || !val) return -1;
33455 dst = malloc(key_len + val_len + 3);
33456 memcpy(dst, key, key_len);
33457 dst[key_len] = '=';
33458 /* add the \0 from the value */
33459 memcpy(dst + key_len + 1, val, val_len + 1);
33462 if (env->size == 0) {
33464 env->ptr = malloc(env->size * sizeof(*env->ptr));
33465 @@ -604,13 +596,13 @@
33467 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
33471 env->ptr[env->used++] = dst;
33477 -static int scgi_spawn_connection(server *srv,
33478 +static int scgi_spawn_connection(server *srv,
33480 scgi_extension_host *host,
33482 @@ -622,31 +614,27 @@
33484 struct sockaddr_in scgi_addr_in;
33485 struct sockaddr *scgi_addr;
33496 if (p->conf.debug) {
33497 log_error_write(srv, __FILE__, __LINE__, "sdb",
33498 "new proc, socket:", proc->port, proc->socket);
33502 if (!buffer_is_empty(proc->socket)) {
33503 memset(&scgi_addr, 0, sizeof(scgi_addr));
33506 #ifdef HAVE_SYS_UN_H
33507 scgi_addr_un.sun_family = AF_UNIX;
33508 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
33512 servlen = SUN_LEN(&scgi_addr_un);
33514 - /* stevens says: */
33515 - servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
33518 socket_type = AF_UNIX;
33519 scgi_addr = (struct sockaddr *) &scgi_addr_un;
33521 @@ -656,115 +644,115 @@
33524 scgi_addr_in.sin_family = AF_INET;
33527 if (buffer_is_empty(host->host)) {
33528 scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33530 struct hostent *he;
33533 /* set a usefull default */
33534 scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
33539 if (NULL == (he = gethostbyname(host->host->ptr))) {
33540 - log_error_write(srv, __FILE__, __LINE__,
33541 - "sdb", "gethostbyname failed: ",
33542 + log_error_write(srv, __FILE__, __LINE__,
33543 + "sdb", "gethostbyname failed: ",
33544 h_errno, host->host);
33549 if (he->h_addrtype != AF_INET) {
33550 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
33555 if (he->h_length != sizeof(struct in_addr)) {
33556 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
33561 memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
33565 scgi_addr_in.sin_port = htons(proc->port);
33566 servlen = sizeof(scgi_addr_in);
33569 socket_type = AF_INET;
33570 scgi_addr = (struct sockaddr *) &scgi_addr_in;
33574 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33575 - log_error_write(srv, __FILE__, __LINE__, "ss",
33576 + log_error_write(srv, __FILE__, __LINE__, "ss",
33577 "failed:", strerror(errno));
33582 if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
33583 /* server is not up, spawn in */
33588 if (!buffer_is_empty(proc->socket)) {
33589 unlink(proc->socket->ptr);
33596 /* reopen socket */
33597 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33598 - log_error_write(srv, __FILE__, __LINE__, "ss",
33599 + log_error_write(srv, __FILE__, __LINE__, "ss",
33600 "socket failed:", strerror(errno));
33606 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
33607 - log_error_write(srv, __FILE__, __LINE__, "ss",
33608 + log_error_write(srv, __FILE__, __LINE__, "ss",
33609 "socketsockopt failed:", strerror(errno));
33614 /* create socket */
33615 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
33616 - log_error_write(srv, __FILE__, __LINE__, "sbds",
33617 - "bind failed for:",
33620 + log_error_write(srv, __FILE__, __LINE__, "sbds",
33621 + "bind failed for:",
33629 if (-1 == listen(scgi_fd, 1024)) {
33630 - log_error_write(srv, __FILE__, __LINE__, "ss",
33631 + log_error_write(srv, __FILE__, __LINE__, "ss",
33632 "listen failed:", strerror(errno));
33639 switch ((child = fork())) {
33649 /* create environment */
33655 /* we don't need the client socket */
33656 for (fd = 3; fd < 256; fd++) {
33657 if (fd != 2 && fd != scgi_fd) close(fd);
33661 /* build clean environment */
33662 if (host->bin_env_copy->used) {
33663 for (i = 0; i < host->bin_env_copy->used; i++) {
33664 data_string *ds = (data_string *)host->bin_env_copy->data[i];
33668 if (NULL != (ge = getenv(ds->value->ptr))) {
33669 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
33671 @@ -772,44 +760,44 @@
33673 for (i = 0; environ[i]; i++) {
33677 if (NULL != (eq = strchr(environ[i], '='))) {
33678 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
33684 /* create environment */
33685 for (i = 0; i < host->bin_env->used; i++) {
33686 data_string *ds = (data_string *)host->bin_env->data[i];
33689 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
33693 for (i = 0; i < env.used; i++) {
33694 /* search for PHP_FCGI_CHILDREN */
33695 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
33699 /* not found, add a default */
33700 if (i == env.used) {
33701 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
33705 env.ptr[env.used] = NULL;
33709 buffer_copy_string(b, "exec ");
33710 buffer_append_string_buffer(b, host->bin_path);
33714 execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
33716 - log_error_write(srv, __FILE__, __LINE__, "sbs",
33718 + log_error_write(srv, __FILE__, __LINE__, "sbs",
33719 "execl failed for:", host->bin_path, strerror(errno));
33728 @@ -817,32 +805,32 @@
33735 select(0, NULL, NULL, NULL, &tv);
33738 switch (waitpid(child, &status, WNOHANG)) {
33740 /* child still running after timeout, good */
33743 /* no PID found ? should never happen */
33744 - log_error_write(srv, __FILE__, __LINE__, "ss",
33745 + log_error_write(srv, __FILE__, __LINE__, "ss",
33746 "pid not found:", strerror(errno));
33749 /* the child should not terminate at all */
33750 if (WIFEXITED(status)) {
33751 - log_error_write(srv, __FILE__, __LINE__, "sd",
33752 - "child exited (is this a SCGI binary ?):",
33753 + log_error_write(srv, __FILE__, __LINE__, "sd",
33754 + "child exited (is this a SCGI binary ?):",
33755 WEXITSTATUS(status));
33756 } else if (WIFSIGNALED(status)) {
33757 - log_error_write(srv, __FILE__, __LINE__, "sd",
33758 - "child signaled:",
33759 + log_error_write(srv, __FILE__, __LINE__, "sd",
33760 + "child signaled:",
33763 - log_error_write(srv, __FILE__, __LINE__, "sd",
33764 - "child died somehow:",
33765 + log_error_write(srv, __FILE__, __LINE__, "sd",
33766 + "child died somehow:",
33770 @@ -852,26 +840,26 @@
33772 proc->last_used = srv->cur_ts;
33773 proc->is_local = 1;
33780 proc->is_local = 0;
33784 if (p->conf.debug) {
33785 log_error_write(srv, __FILE__, __LINE__, "sb",
33786 "(debug) socket is already used, won't spawn:",
33792 proc->state = PROC_STATE_RUNNING;
33793 host->active_procs++;
33802 @@ -880,89 +868,89 @@
33803 plugin_data *p = p_d;
33807 - config_values_t cv[] = {
33809 + config_values_t cv[] = {
33810 { "scgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
33811 { "scgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
33812 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33816 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33819 for (i = 0; i < srv->config_context->used; i++) {
33824 s = malloc(sizeof(plugin_config));
33825 s->exts = scgi_extensions_init();
33829 cv[0].destination = s->exts;
33830 cv[1].destination = &(s->debug);
33833 p->config_storage[i] = s;
33834 ca = ((data_config *)srv->config_context->data[i])->value;
33837 if (0 != config_insert_values_global(srv, ca, cv)) {
33838 return HANDLER_ERROR;
33848 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
33850 data_array *da = (data_array *)du;
33853 if (du->type != TYPE_ARRAY) {
33854 - log_error_write(srv, __FILE__, __LINE__, "sss",
33855 + log_error_write(srv, __FILE__, __LINE__, "sss",
33856 "unexpected type for key: ", "scgi.server", "array of strings");
33859 return HANDLER_ERROR;
33864 - * scgi.server = ( "<ext>" => ( ... ),
33868 + * scgi.server = ( "<ext>" => ( ... ),
33869 * "<ext>" => ( ... ) )
33873 for (j = 0; j < da->value->used; j++) {
33875 data_array *da_ext = (data_array *)da->value->data[j];
33878 if (da->value->data[j]->type != TYPE_ARRAY) {
33879 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
33880 - "unexpected type for key: ", "scgi.server",
33881 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
33882 + "unexpected type for key: ", "scgi.server",
33883 "[", da->value->data[j]->key, "](string)");
33886 return HANDLER_ERROR;
33890 - * da_ext->key == name of the extension
33893 + * da_ext->key == name of the extension
33897 - * scgi.server = ( "<ext>" =>
33898 - * ( "<host>" => ( ... ),
33901 + * scgi.server = ( "<ext>" =>
33902 + * ( "<host>" => ( ... ),
33903 * "<host>" => ( ... )
33910 for (n = 0; n < da_ext->value->used; n++) {
33911 data_array *da_host = (data_array *)da_ext->value->data[n];
33914 scgi_extension_host *df;
33916 - config_values_t fcv[] = {
33918 + config_values_t fcv[] = {
33919 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
33920 { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
33921 { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
33922 { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
33925 { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
33926 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
33927 { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
33928 @@ -970,37 +958,37 @@
33929 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
33930 { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
33931 { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
33934 { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
33935 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
33940 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33944 if (da_host->type != TYPE_ARRAY) {
33945 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33946 - "unexpected type for key:",
33948 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33949 + "unexpected type for key:",
33951 "[", da_host->key, "](string)");
33954 return HANDLER_ERROR;
33958 df = scgi_host_init();
33961 df->check_local = 1;
33964 df->max_load_per_proc = 1;
33965 df->idle_timeout = 60;
33966 df->disable_time = 60;
33969 fcv[0].destination = df->host;
33970 fcv[1].destination = df->docroot;
33971 fcv[2].destination = df->unixsocket;
33972 fcv[3].destination = df->bin_path;
33975 fcv[4].destination = &(df->check_local);
33976 fcv[5].destination = &(df->port);
33977 fcv[6].destination = &(df->min_procs);
33978 @@ -1008,47 +996,47 @@
33979 fcv[8].destination = &(df->max_load_per_proc);
33980 fcv[9].destination = &(df->idle_timeout);
33981 fcv[10].destination = &(df->disable_time);
33984 fcv[11].destination = df->bin_env;
33985 fcv[12].destination = df->bin_env_copy;
33990 if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
33991 return HANDLER_ERROR;
33994 - if ((!buffer_is_empty(df->host) || df->port) &&
33996 + if ((!buffer_is_empty(df->host) || df->port) &&
33997 !buffer_is_empty(df->unixsocket)) {
33998 - log_error_write(srv, __FILE__, __LINE__, "s",
33999 + log_error_write(srv, __FILE__, __LINE__, "s",
34000 "either host+port or socket");
34003 return HANDLER_ERROR;
34007 if (!buffer_is_empty(df->unixsocket)) {
34008 /* unix domain socket */
34011 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
34012 - log_error_write(srv, __FILE__, __LINE__, "s",
34013 + log_error_write(srv, __FILE__, __LINE__, "s",
34014 "path of the unixdomain socket is too large");
34015 return HANDLER_ERROR;
34020 - if (buffer_is_empty(df->host) &&
34022 + if (buffer_is_empty(df->host) &&
34023 buffer_is_empty(df->bin_path)) {
34024 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
34025 - "missing key (string):",
34026 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
34027 + "missing key (string):",
34034 return HANDLER_ERROR;
34035 } else if (df->port == 0) {
34036 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
34037 - "missing key (short):",
34038 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
34039 + "missing key (short):",
34043 @@ -1056,14 +1044,14 @@
34044 return HANDLER_ERROR;
34048 - if (!buffer_is_empty(df->bin_path)) {
34050 + if (!buffer_is_empty(df->bin_path)) {
34051 /* a local socket + self spawning */
34055 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
34056 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
34060 log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
34061 "--- scgi spawning local",
34062 @@ -1073,7 +1061,7 @@
34063 "\n\tmin-procs:", df->min_procs,
34064 "\n\tmax-procs:", df->max_procs);
34068 for (pno = 0; pno < df->min_procs; pno++) {
34071 @@ -1088,7 +1076,7 @@
34072 buffer_append_string(proc->socket, "-");
34073 buffer_append_long(proc->socket, pno);
34078 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
34079 "--- scgi spawning",
34080 @@ -1096,53 +1084,53 @@
34081 "\n\tsocket", df->unixsocket,
34082 "\n\tcurrent:", pno, "/", df->min_procs);
34086 if (scgi_spawn_connection(srv, p, df, proc)) {
34087 log_error_write(srv, __FILE__, __LINE__, "s",
34088 "[ERROR]: spawning fcgi failed.");
34089 return HANDLER_ERROR;
34093 proc->next = df->first;
34094 if (df->first) df->first->prev = proc;
34103 fp = scgi_process_init();
34104 fp->id = df->num_procs++;
34106 df->active_procs++;
34107 fp->state = PROC_STATE_RUNNING;
34110 if (buffer_is_empty(df->unixsocket)) {
34111 fp->port = df->port;
34113 buffer_copy_string_buffer(fp->socket, df->unixsocket);
34125 /* if extension already exists, take it */
34126 scgi_extension_insert(s->exts, da_ext->key, df);
34133 return HANDLER_GO_ON;
34136 static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
34137 hctx->state = state;
34138 hctx->state_timestamp = srv->cur_ts;
34144 @@ -1150,35 +1138,35 @@
34145 void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
34150 if (NULL == hctx) return;
34153 p = hctx->plugin_data;
34154 con = hctx->remote_conn;
34157 if (con->mode != p->id) {
34162 - if (hctx->fd != -1) {
34163 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34164 - fdevent_unregister(srv->ev, hctx->fd);
34167 + if (hctx->sock->fd != -1) {
34168 + fdevent_event_del(srv->ev, hctx->sock);
34169 + fdevent_unregister(srv->ev, hctx->sock);
34170 + closesocket(hctx->sock->fd);
34171 + hctx->sock->fd = -1;
34176 if (hctx->host && hctx->proc) {
34177 hctx->host->load--;
34180 if (hctx->got_proc) {
34181 /* after the connect the process gets a load */
34182 hctx->proc->load--;
34185 if (p->conf.debug) {
34186 log_error_write(srv, __FILE__, __LINE__, "sddb",
34191 hctx->proc->pid, hctx->proc->socket);
34194 @@ -1186,87 +1174,87 @@
34195 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
34200 handler_ctx_free(hctx);
34201 - con->plugin_ctx[p->id] = NULL;
34202 + con->plugin_ctx[p->id] = NULL;
34205 static int scgi_reconnect(server *srv, handler_ctx *hctx) {
34206 plugin_data *p = hctx->plugin_data;
34217 * connect was ok, connection was accepted
34218 * but the php accept loop checks after the accept if it should die or not.
34220 - * if yes we can only detect it at a write()
34223 + * if yes we can only detect it at a write()
34225 * next step is resetting this attemp and setup a connection again
34228 * if we have more then 5 reconnects for the same request, die
34235 * we have a connection but the child died by some other reason
34240 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34241 - fdevent_unregister(srv->ev, hctx->fd);
34244 + fdevent_event_del(srv->ev, hctx->sock);
34245 + fdevent_unregister(srv->ev, hctx->sock);
34246 + closesocket(hctx->sock->fd);
34249 - scgi_set_state(srv, hctx, FCGI_STATE_INIT);
34252 + scgi_set_state(srv, hctx, SCGI_STATE_INIT);
34254 hctx->request_id = 0;
34255 hctx->reconnects++;
34258 if (p->conf.debug) {
34259 log_error_write(srv, __FILE__, __LINE__, "sddb",
34264 hctx->proc->pid, hctx->proc->socket);
34268 hctx->proc->load--;
34269 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
34276 static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
34277 plugin_data *p = p_d;
34280 scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
34283 return HANDLER_GO_ON;
34287 static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
34291 if (!key || !val) return -1;
34294 len = key_len + val_len + 2;
34297 buffer_prepare_append(env, len);
34299 - /* include the NUL */
34300 + /* include the NUL */
34301 memcpy(env->ptr + env->used, key, key_len + 1);
34302 env->used += key_len + 1;
34303 memcpy(env->ptr + env->used, val, val_len + 1);
34304 env->used += val_len + 1;
34317 @@ -1280,24 +1268,21 @@
34318 struct sockaddr_un scgi_addr_un;
34323 scgi_extension_host *host = hctx->host;
34324 scgi_proc *proc = hctx->proc;
34325 - int scgi_fd = hctx->fd;
34327 + int scgi_fd = hctx->sock->fd;
34329 memset(&scgi_addr, 0, sizeof(scgi_addr));
34332 if (!buffer_is_empty(proc->socket)) {
34333 #ifdef HAVE_SYS_UN_H
34334 /* use the unix domain socket */
34335 scgi_addr_un.sun_family = AF_UNIX;
34336 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
34339 servlen = SUN_LEN(&scgi_addr_un);
34341 - /* stevens says: */
34342 - servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
34345 scgi_addr = (struct sockaddr *) &scgi_addr_un;
34348 @@ -1305,105 +1290,105 @@
34350 scgi_addr_in.sin_family = AF_INET;
34351 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
34352 - log_error_write(srv, __FILE__, __LINE__, "sbs",
34353 - "converting IP-adress failed for", host->host,
34354 + log_error_write(srv, __FILE__, __LINE__, "sbs",
34355 + "converting IP-adress failed for", host->host,
34356 "\nBe sure to specify an IP address here");
34361 scgi_addr_in.sin_port = htons(proc->port);
34362 servlen = sizeof(scgi_addr_in);
34365 scgi_addr = (struct sockaddr *) &scgi_addr_in;
34369 if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
34370 - if (errno == EINPROGRESS ||
34371 + if (errno == EINPROGRESS ||
34372 errno == EALREADY ||
34374 if (hctx->conf.debug) {
34375 - log_error_write(srv, __FILE__, __LINE__, "sd",
34376 + log_error_write(srv, __FILE__, __LINE__, "sd",
34377 "connect delayed, will continue later:", scgi_fd);
34383 - log_error_write(srv, __FILE__, __LINE__, "sdsddb",
34384 - "connect failed:", scgi_fd,
34385 + log_error_write(srv, __FILE__, __LINE__, "sdsddb",
34386 + "connect failed:", scgi_fd,
34387 strerror(errno), errno,
34388 proc->port, proc->socket);
34390 if (errno == EAGAIN) {
34391 /* this is Linux only */
34393 - log_error_write(srv, __FILE__, __LINE__, "s",
34395 + log_error_write(srv, __FILE__, __LINE__, "s",
34396 "If this happend on Linux: You have been run out of local ports. "
34397 "Check the manual, section Performance how to handle this.");
34405 if (hctx->conf.debug > 1) {
34406 - log_error_write(srv, __FILE__, __LINE__, "sd",
34407 + log_error_write(srv, __FILE__, __LINE__, "sd",
34408 "connect succeeded: ", scgi_fd);
34417 static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
34421 for (i = 0; i < con->request.headers->used; i++) {
34425 ds = (data_string *)con->request.headers->data[i];
34428 if (ds->value->used && ds->key->used) {
34430 buffer_reset(srv->tmp_buf);
34433 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
34434 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
34435 srv->tmp_buf->used--;
34439 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34440 for (j = 0; j < ds->key->used - 1; j++) {
34441 - srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34442 - light_isalpha(ds->key->ptr[j]) ?
34443 + srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34444 + light_isalpha(ds->key->ptr[j]) ?
34445 ds->key->ptr[j] & ~32 : '_';
34447 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34450 scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34455 for (i = 0; i < con->environment->used; i++) {
34459 ds = (data_string *)con->environment->data[i];
34462 if (ds->value->used && ds->key->used) {
34464 buffer_reset(srv->tmp_buf);
34467 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
34468 for (j = 0; j < ds->key->used - 1; j++) {
34469 - srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34470 - isalpha((unsigned char)ds->key->ptr[j]) ?
34471 + srv->tmp_buf->ptr[srv->tmp_buf->used++] =
34472 + isalpha((unsigned char)ds->key->ptr[j]) ?
34473 toupper((unsigned char)ds->key->ptr[j]) : '_';
34475 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
34478 scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
34486 @@ -1415,20 +1400,20 @@
34487 char b2[INET6_ADDRSTRLEN + 1];
34492 plugin_data *p = hctx->plugin_data;
34493 scgi_extension_host *host= hctx->host;
34495 connection *con = hctx->remote_conn;
34496 server_socket *srv_sock = con->srv_socket;
34499 sock_addr our_addr;
34500 socklen_t our_addr_len;
34503 buffer_prepare_copy(p->scgi_env, 1024);
34505 /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
34508 /* request.content_length < SSIZE_MAX, see request.c */
34509 ltostr(buf, con->request.content_length);
34510 scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
34511 @@ -1436,13 +1421,13 @@
34514 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
34517 if (con->server_name->used) {
34518 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
34521 - s = inet_ntop(srv_sock->addr.plain.sa_family,
34522 - srv_sock->addr.plain.sa_family == AF_INET6 ?
34523 + s = inet_ntop(srv_sock->addr.plain.sa_family,
34524 + srv_sock->addr.plain.sa_family == AF_INET6 ?
34525 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
34526 (const void *) &(srv_sock->addr.ipv4.sin_addr),
34528 @@ -1451,47 +1436,47 @@
34530 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
34534 scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
34540 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
34542 ntohs(srv_sock->addr.ipv4.sin_port)
34547 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
34550 /* get the server-side of the connection to the client */
34551 our_addr_len = sizeof(our_addr);
34553 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
34555 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
34556 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
34558 s = inet_ntop_cache_get_ip(srv, &(our_addr));
34560 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
34566 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
34568 ntohs(con->dst_addr.ipv4.sin_port)
34573 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
34576 s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
34577 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
34580 if (!buffer_is_empty(con->authed_user)) {
34581 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
34582 CONST_BUF_LEN(con->authed_user));
34588 * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
34589 @@ -1500,12 +1485,12 @@
34592 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
34595 if (!buffer_is_empty(con->request.pathinfo)) {
34596 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
34599 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
34602 if (!buffer_is_empty(host->docroot)) {
34603 buffer_copy_string_buffer(p->path, host->docroot);
34605 @@ -1526,19 +1511,19 @@
34608 if (!buffer_is_empty(host->docroot)) {
34610 - * rewrite SCRIPT_FILENAME
34613 + * rewrite SCRIPT_FILENAME
34618 buffer_copy_string_buffer(p->path, host->docroot);
34619 buffer_append_string_buffer(p->path, con->uri.path);
34622 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34623 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
34625 buffer_copy_string_buffer(p->path, con->physical.path);
34628 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34629 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
34631 @@ -1551,30 +1536,30 @@
34633 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
34637 s = get_http_method_name(con->request.http_method);
34638 scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
34639 scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
34640 s = get_http_version_name(con->request.http_version);
34641 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
34645 if (srv_sock->is_ssl) {
34646 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
34651 scgi_env_add_request_headers(srv, con, p);
34653 b = chunkqueue_get_append_buffer(hctx->wb);
34656 buffer_append_long(b, p->scgi_env->used);
34657 buffer_append_string_len(b, CONST_STR_LEN(":"));
34658 buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
34659 buffer_append_string_len(b, CONST_STR_LEN(","));
34661 hctx->wb->bytes_in += b->used - 1;
34664 if (con->request.content_length) {
34665 chunkqueue *req_cq = con->request_content_queue;
34667 @@ -1587,7 +1572,7 @@
34669 /* we announce toWrite octects
34670 * now take all the request_content chunk that we need to fill this request
34674 switch (req_c->type) {
34676 @@ -1615,293 +1600,170 @@
34678 req_c->offset += weHave;
34679 req_cq->bytes_out += weHave;
34682 hctx->wb->bytes_in += weHave;
34696 for (i = 0; i < hctx->write_buffer->used; i++) {
34697 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
34698 if ((i+1) % 16 == 0) {
34700 for (j = i-15; j <= i; j++) {
34701 - fprintf(stderr, "%c",
34702 + fprintf(stderr, "%c",
34703 isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
34705 fprintf(stderr, "\n");
34713 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
34720 - buffer_copy_string_buffer(p->parse_response, in);
34722 - for (s = p->parse_response->ptr;
34723 - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
34724 - s = ns + (eol == EOL_RN ? 2 : 1), line++) {
34725 - const char *key, *value;
34732 - 0 == strncmp(s, "HTTP/1.", 7)) {
34733 - /* non-parsed header ... we parse them anyway */
34735 - if ((s[7] == '1' ||
34739 - /* after the space should be a status code for us */
34741 - status = strtol(s+9, NULL, 10);
34743 - if (con->http_status >= 100 &&
34744 - con->http_status < 1000) {
34745 - /* we expected 3 digits and didn't got them */
34746 - con->parsed_response |= HTTP_STATUS;
34747 - con->http_status = status;
34753 - if (NULL == (value = strchr(s, ':'))) {
34754 - /* we expect: "<key>: <value>\r\n" */
34758 - key_len = value - key;
34762 - while (*value == ' ' || *value == '\t') value++;
34764 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34765 - ds = data_response_init();
34767 - buffer_copy_string_len(ds->key, key, key_len);
34768 - buffer_copy_string(ds->value, value);
34770 - array_insert_unique(con->response.headers, (data_unset *)ds);
34772 - switch(key_len) {
34774 - if (0 == strncasecmp(key, "Date", key_len)) {
34775 - con->parsed_response |= HTTP_DATE;
34779 - if (0 == strncasecmp(key, "Status", key_len)) {
34780 - con->http_status = strtol(value, NULL, 10);
34781 - con->parsed_response |= HTTP_STATUS;
34785 - if (0 == strncasecmp(key, "Location", key_len)) {
34786 - con->parsed_response |= HTTP_LOCATION;
34790 - if (0 == strncasecmp(key, "Connection", key_len)) {
34791 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
34792 - con->parsed_response |= HTTP_CONNECTION;
34796 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
34797 - con->response.content_length = strtol(value, NULL, 10);
34798 - con->parsed_response |= HTTP_CONTENT_LENGTH;
34807 - /* CGI/1.1 rev 03 - 7.2.1.2 */
34808 - if ((con->parsed_response & HTTP_LOCATION) &&
34809 - !(con->parsed_response & HTTP_STATUS)) {
34810 - con->http_status = 302;
34817 static int scgi_demux_response(server *srv, handler_ctx *hctx) {
34818 plugin_data *p = hctx->plugin_data;
34819 connection *con = hctx->remote_conn;
34824 - buffer_prepare_copy(hctx->response, 1024);
34825 - if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
34826 - if (errno == EAGAIN || errno == EINTR) {
34827 - /* would block, wait for signal */
34831 - log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
34836 - /* read finished */
34838 - con->file_finished = 1;
34840 - /* send final chunk */
34841 - http_chunk_append_mem(srv, con, NULL, 0);
34842 - joblist_append(srv, con);
34846 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
34847 + case NETWORK_STATUS_SUCCESS:
34848 + /* we got content */
34850 + case NETWORK_STATUS_WAIT_FOR_EVENT:
34851 + /* the ioctl will return WAIT_FOR_EVENT on a read */
34852 + if (0 == con->file_started) return -1;
34853 + case NETWORK_STATUS_CONNECTION_CLOSE:
34854 + /* we are done, get out of here */
34855 + con->file_finished = 1;
34857 + /* close the chunk-queue with a empty chunk */
34865 + /* looks like we got some content
34867 + * split off the header from the incoming stream
34870 + if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
34872 + int have_content_length = 0;
34874 + http_response_reset(p->resp);
34876 + /* the response header is not fully received yet,
34878 + * extract the http-response header from the rb-cq
34880 + switch (http_response_parse_cq(hctx->rb, p->resp)) {
34881 + case PARSE_ERROR:
34882 + /* parsing failed */
34884 + con->http_status = 502; /* Bad Gateway */
34888 - hctx->response->ptr[n] = '\0';
34889 - hctx->response->used = n+1;
34891 - /* split header from body */
34893 - if (con->file_started == 0) {
34895 - int in_header = 0;
34896 - int header_end = 0;
34897 - int cp, eol = EOL_UNSET;
34900 - buffer_append_string_buffer(hctx->response_header, hctx->response);
34902 - /* nph (non-parsed headers) */
34903 - if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
34905 - /* search for the \r\n\r\n or \n\n in the string */
34906 - for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
34907 - if (*c == ':') in_header = 1;
34908 - else if (*c == '\n') {
34909 - if (in_header == 0) {
34910 - /* got a response without a response header */
34917 - if (eol == EOL_UNSET) eol = EOL_N;
34919 - if (*(c+1) == '\n') {
34924 - } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
34925 - if (in_header == 0) {
34926 - /* got a response without a response header */
34933 - if (eol == EOL_UNSET) eol = EOL_RN;
34936 - *(c+2) == '\r' &&
34937 - *(c+3) == '\n') {
34942 - /* skip the \n */
34946 + case PARSE_NEED_MORE:
34948 + case PARSE_SUCCESS:
34949 + con->http_status = p->resp->status;
34951 + chunkqueue_remove_finished_chunks(hctx->rb);
34953 + /* copy the http-headers */
34954 + for (i = 0; i < p->resp->headers->used; i++) {
34955 + const char *ign[] = { "Status", "Connection", NULL };
34959 + data_string *header = (data_string *)p->resp->headers->data[i];
34961 + /* some headers are ignored by default */
34962 + for (j = 0; ign[j]; j++) {
34963 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
34967 - if (header_end) {
34969 - /* no header, but a body */
34971 - if (con->request.http_version == HTTP_VERSION_1_1) {
34972 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34975 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
34976 - joblist_append(srv, con);
34978 - size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
34979 - size_t blen = hctx->response_header->used - hlen - 1;
34981 - /* a small hack: terminate after at the second \r */
34982 - hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
34983 - hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
34985 - /* parse the response header */
34986 - scgi_response_parse(srv, con, p, hctx->response_header, eol);
34988 - /* enable chunked-transfer-encoding */
34989 - if (con->request.http_version == HTTP_VERSION_1_1 &&
34990 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
34991 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34994 - if ((hctx->response->used != hlen) && blen > 0) {
34995 - http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
34996 - joblist_append(srv, con);
34998 + if (ign[j]) continue;
35000 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
35001 + /* CGI/1.1 rev 03 - 7.2.1.2 */
35002 + if (con->http_status == 0) con->http_status = 302;
35003 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
35004 + have_content_length = 1;
35007 - con->file_started = 1;
35008 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
35009 + ds = data_response_init();
35011 + buffer_copy_string_buffer(ds->key, header->key);
35012 + buffer_copy_string_buffer(ds->value, header->value);
35014 + array_insert_unique(con->response.headers, (data_unset *)ds);
35017 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
35018 - joblist_append(srv, con);
35020 + con->file_started = 1;
35022 + if (con->request.http_version == HTTP_VERSION_1_1 &&
35023 + !have_content_length) {
35024 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
35027 + hctx->state = SCGI_STATE_RESPONSE_CONTENT;
35032 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
35037 + /* FIXME: pass the response-header to the other plugins to
35038 + * setup the filter-queue
35040 + * - use next-queue instead of con->write_queue
35043 + assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
35045 + /* FIXME: if we have a content-length or chunked-encoding
35048 + * for now we wait for EOF on the socket */
35050 + /* copy the content to the next cq */
35051 + for (c = hctx->rb->first; c; c = c->next) {
35052 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
35054 + c->offset = c->mem->used - 1;
35057 + chunkqueue_remove_finished_chunks(hctx->rb);
35058 + joblist_append(srv, con);
35064 int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
35070 - /* we have been the smallest of the current list
35071 - * and we want to insert the node sorted as soon
35073 + /* we have been the smallest of the current list
35074 + * and we want to insert the node sorted as soon
35087 /* nothing to sort, only one element */
35088 @@ -1909,9 +1771,9 @@
35090 for (p = proc; p->next && p->next->load < proc->load; p = p->next);
35092 - /* no need to move something
35093 + /* no need to move something
35100 @@ -1930,16 +1792,16 @@
35102 if (proc->prev) proc->prev->next = proc->next;
35103 if (proc->next) proc->next->prev = proc->prev;
35106 /* proc should be right of p */
35109 proc->next = p->next;
35111 if (p->next) p->next->prev = proc;
35114 for(p = host->first; p; p = p->next) {
35115 - log_error_write(srv, __FILE__, __LINE__, "dd",
35116 + log_error_write(srv, __FILE__, __LINE__, "dd",
35120 @@ -1951,21 +1813,21 @@
35122 int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
35128 - /* we have been the smallest of the current list
35129 - * and we want to insert the node sorted as soon
35131 + /* we have been the smallest of the current list
35132 + * and we want to insert the node sorted as soon
35142 * the basic is idea is:
35143 - * - the last active scgi process should be still
35144 + * - the last active scgi process should be still
35145 * in ram and is not swapped out yet
35146 * - processes that are not reused will be killed
35147 * after some time by the trigger-handler
35148 @@ -1975,7 +1837,7 @@
35149 * ice-cold processes are propably unused since more
35150 * than 'unused-timeout', are swaped out and won't be
35151 * reused in the next seconds anyway.
35156 /* nothing to sort, only one element */
35157 @@ -1984,16 +1846,16 @@
35158 for (p = host->first; p != proc && p->load < proc->load; p = p->next);
35161 - /* no need to move something
35162 + /* no need to move something
35171 if (p == proc) return 0;
35174 /* we have to move left. If we are already the first element
35176 if (host->first == proc) return 0;
35177 @@ -2009,9 +1871,9 @@
35180 if (proc->prev == NULL) host->first = proc;
35183 for(p = host->first; p; p = p->next) {
35184 - log_error_write(srv, __FILE__, __LINE__, "dd",
35185 + log_error_write(srv, __FILE__, __LINE__, "dd",
35189 @@ -2023,41 +1885,42 @@
35191 static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
35195 for (proc = host->first; proc; proc = proc->next) {
35196 if (p->conf.debug) {
35197 - log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
35199 - host->host, proc->port,
35200 + log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
35202 + host->host, proc->port,
35211 if (0 == proc->is_local) {
35213 - * external servers might get disabled
35215 - * enable the server again, perhaps it is back again
35217 + * external servers might get disabled
35219 + * enable the server again, perhaps it is back again
35223 if ((proc->state == PROC_STATE_DISABLED) &&
35224 (srv->cur_ts - proc->disable_ts > host->disable_time)) {
35225 proc->state = PROC_STATE_RUNNING;
35226 host->active_procs++;
35228 - log_error_write(srv, __FILE__, __LINE__, "sbdb",
35229 - "fcgi-server re-enabled:",
35230 - host->host, host->port,
35232 + log_error_write(srv, __FILE__, __LINE__, "sbdb",
35233 + "fcgi-server re-enabled:",
35234 + host->host, host->port,
35238 /* the child should not terminate at all */
35242 if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
35244 switch(waitpid(proc->pid, &status, WNOHANG)) {
35246 /* child is still alive */
35247 @@ -2067,33 +1930,34 @@
35249 if (WIFEXITED(status)) {
35251 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
35252 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
35253 "child exited, pid:", proc->pid,
35254 "status:", WEXITSTATUS(status));
35256 } else if (WIFSIGNALED(status)) {
35257 - log_error_write(srv, __FILE__, __LINE__, "sd",
35258 - "child signaled:",
35259 + log_error_write(srv, __FILE__, __LINE__, "sd",
35260 + "child signaled:",
35263 - log_error_write(srv, __FILE__, __LINE__, "sd",
35264 - "child died somehow:",
35265 + log_error_write(srv, __FILE__, __LINE__, "sd",
35266 + "child died somehow:",
35271 proc->state = PROC_STATE_DIED;
35280 * local servers might died, but we restart them
35284 if (proc->state == PROC_STATE_DIED &&
35286 /* restart the child */
35289 if (p->conf.debug) {
35290 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35291 "--- scgi spawning",
35292 @@ -2101,18 +1965,18 @@
35293 "\n\tsocket", host->unixsocket,
35294 "\n\tcurrent:", 1, "/", host->min_procs);
35298 if (scgi_spawn_connection(srv, p, host, proc)) {
35299 log_error_write(srv, __FILE__, __LINE__, "s",
35300 "ERROR: spawning fcgi failed.");
35301 return HANDLER_ERROR;
35305 scgi_proclist_sort_down(srv, host, proc);
35314 @@ -2121,13 +1985,13 @@
35315 plugin_data *p = hctx->plugin_data;
35316 scgi_extension_host *host= hctx->host;
35317 connection *con = hctx->remote_conn;
35322 - /* sanity check */
35323 + /* sanity check */
35325 ((!host->host->used || !host->port) && !host->unixsocket->used)) {
35326 - log_error_write(srv, __FILE__, __LINE__, "sxddd",
35327 + log_error_write(srv, __FILE__, __LINE__, "sxddd",
35328 "write-req: error",
35331 @@ -2135,259 +1999,260 @@
35332 host->unixsocket->used);
35333 return HANDLER_ERROR;
35338 switch(hctx->state) {
35339 - case FCGI_STATE_INIT:
35340 + case SCGI_STATE_INIT:
35341 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
35343 - if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
35345 + if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
35346 if (errno == EMFILE ||
35348 - log_error_write(srv, __FILE__, __LINE__, "sd",
35349 - "wait for fd at connection:", con->fd);
35351 + log_error_write(srv, __FILE__, __LINE__, "sd",
35352 + "wait for fd at connection:", con->sock->fd);
35354 return HANDLER_WAIT_FOR_FD;
35357 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
35359 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
35360 "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
35361 return HANDLER_ERROR;
35363 - hctx->fde_ndx = -1;
35365 + hctx->sock->fde_ndx = -1;
35369 - fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
35371 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
35372 - log_error_write(srv, __FILE__, __LINE__, "ss",
35374 + fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
35376 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
35377 + log_error_write(srv, __FILE__, __LINE__, "ss",
35378 "fcntl failed: ", strerror(errno));
35381 return HANDLER_ERROR;
35386 - case FCGI_STATE_CONNECT:
35387 - if (hctx->state == FCGI_STATE_INIT) {
35388 - for (hctx->proc = hctx->host->first;
35389 - hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
35390 + case SCGI_STATE_CONNECT:
35391 + if (hctx->state == SCGI_STATE_INIT) {
35392 + for (hctx->proc = hctx->host->first;
35393 + hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
35394 hctx->proc = hctx->proc->next);
35397 /* all childs are dead */
35398 if (hctx->proc == NULL) {
35399 - hctx->fde_ndx = -1;
35401 + hctx->sock->fde_ndx = -1;
35403 return HANDLER_ERROR;
35407 if (hctx->proc->is_local) {
35408 hctx->pid = hctx->proc->pid;
35412 switch (scgi_establish_connection(srv, hctx)) {
35414 - scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
35416 + scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
35418 /* connection is in progress, wait for an event and call getsockopt() below */
35420 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35423 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35425 return HANDLER_WAIT_FOR_EVENT;
35427 /* if ECONNREFUSED choose another connection -> FIXME */
35428 - hctx->fde_ndx = -1;
35430 + hctx->sock->fde_ndx = -1;
35432 return HANDLER_ERROR;
35434 /* everything is ok, go on */
35442 socklen_t socket_error_len = sizeof(socket_error);
35445 /* try to finish the connect() */
35446 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35447 - log_error_write(srv, __FILE__, __LINE__, "ss",
35448 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
35449 + log_error_write(srv, __FILE__, __LINE__, "ss",
35450 "getsockopt failed:", strerror(errno));
35453 return HANDLER_ERROR;
35455 if (socket_error != 0) {
35456 if (!hctx->proc->is_local || p->conf.debug) {
35457 /* local procs get restarted */
35460 log_error_write(srv, __FILE__, __LINE__, "ss",
35461 - "establishing connection failed:", strerror(socket_error),
35462 + "establishing connection failed:", strerror(socket_error),
35463 "port:", hctx->proc->port);
35467 return HANDLER_ERROR;
35472 /* ok, we have the connection */
35475 hctx->proc->load++;
35476 hctx->proc->last_used = srv->cur_ts;
35477 hctx->got_proc = 1;
35480 if (p->conf.debug) {
35481 log_error_write(srv, __FILE__, __LINE__, "sddbdd",
35485 - hctx->proc->socket,
35489 + hctx->proc->socket,
35494 /* move the proc-list entry down the list */
35495 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
35497 - scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
35499 + scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
35501 - case FCGI_STATE_PREPARE_WRITE:
35502 + case SCGI_STATE_PREPARE_WRITE:
35503 scgi_create_env(srv, hctx);
35505 - scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
35508 + scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
35511 - case FCGI_STATE_WRITE:
35512 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
35513 + case SCGI_STATE_WRITE:
35514 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
35516 chunkqueue_remove_finished_chunks(hctx->wb);
35520 if (errno == ENOTCONN) {
35521 - /* the connection got dropped after accept()
35523 - * this is most of the time a PHP which dies
35524 + /* the connection got dropped after accept()
35526 + * this is most of the time a PHP which dies
35527 * after PHP_FCGI_MAX_REQUESTS
35532 if (hctx->wb->bytes_out == 0 &&
35533 hctx->reconnects < 5) {
35534 - usleep(10000); /* take away the load of the webserver
35535 - * to let the php a chance to restart
35537 + usleep(10000); /* take away the load of the webserver
35538 + * to let the php a chance to restart
35542 scgi_reconnect(srv, hctx);
35545 return HANDLER_WAIT_FOR_FD;
35549 /* not reconnected ... why
35552 * far@#lighttpd report this for FreeBSD
35557 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35559 + log_error_write(srv, __FILE__, __LINE__, "ssosd",
35560 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
35561 "write-offset:", hctx->wb->bytes_out,
35562 "reconnect attempts:", hctx->reconnects);
35565 return HANDLER_ERROR;
35569 if ((errno != EAGAIN) &&
35570 (errno != EINTR)) {
35572 - log_error_write(srv, __FILE__, __LINE__, "ssd",
35574 + log_error_write(srv, __FILE__, __LINE__, "ssd",
35575 "write failed:", strerror(errno), errno);
35578 return HANDLER_ERROR;
35580 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35582 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35584 return HANDLER_WAIT_FOR_EVENT;
35589 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
35590 /* we don't need the out event anymore */
35591 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
35592 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
35593 - scgi_set_state(srv, hctx, FCGI_STATE_READ);
35594 + fdevent_event_del(srv->ev, hctx->sock);
35595 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35596 + scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
35598 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35600 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35602 return HANDLER_WAIT_FOR_EVENT;
35607 - case FCGI_STATE_READ:
35608 + case SCGI_STATE_RESPONSE_HEADER:
35609 /* waiting for a response */
35612 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
35613 return HANDLER_ERROR;
35617 return HANDLER_WAIT_FOR_EVENT;
35620 SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
35621 plugin_data *p = p_d;
35624 handler_ctx *hctx = con->plugin_ctx[p->id];
35626 scgi_extension_host *host;
35629 if (NULL == hctx) return HANDLER_GO_ON;
35633 if (con->mode != p->id) return HANDLER_GO_ON;
35636 /* ok, create the request */
35637 switch(scgi_write_request(srv, hctx)) {
35638 case HANDLER_ERROR:
35645 0 == proc->is_local &&
35646 proc->state != PROC_STATE_DISABLED) {
35647 /* only disable remote servers as we don't manage them*/
35649 - log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
35651 + log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
35657 /* disable this server */
35658 proc->disable_ts = srv->cur_ts;
35659 proc->state = PROC_STATE_DISABLED;
35660 host->active_procs--;
35663 - if (hctx->state == FCGI_STATE_INIT ||
35664 - hctx->state == FCGI_STATE_CONNECT) {
35665 - /* connect() or getsockopt() failed,
35666 - * restart the request-handling
35668 + if (hctx->state == SCGI_STATE_INIT ||
35669 + hctx->state == SCGI_STATE_CONNECT) {
35670 + /* connect() or getsockopt() failed,
35671 + * restart the request-handling
35673 if (proc && proc->is_local) {
35675 if (p->conf.debug) {
35676 - log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
35677 + log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
35685 * several hctx might reference the same proc
35688 * Only one of them should mark the proc as dead all the other
35689 * ones should just take a new one.
35692 * If a new proc was started with the old struct this might lead
35693 * the mark a perfect proc as dead otherwise
35697 if (proc->state == PROC_STATE_RUNNING &&
35698 hctx->pid == proc->pid) {
35699 @@ -2395,25 +2260,25 @@
35702 scgi_restart_dead_procs(srv, p, host);
35705 scgi_connection_cleanup(srv, hctx);
35708 buffer_reset(con->physical.path);
35709 con->mode = DIRECT;
35710 joblist_append(srv, con);
35712 - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35713 - * and hope that the childs will be restarted
35716 + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35717 + * and hope that the childs will be restarted
35720 return HANDLER_WAIT_FOR_FD;
35722 scgi_connection_cleanup(srv, hctx);
35725 buffer_reset(con->physical.path);
35726 con->mode = DIRECT;
35727 con->http_status = 503;
35730 return HANDLER_FINISHED;
35732 case HANDLER_WAIT_FOR_EVENT:
35733 @@ -2433,23 +2298,23 @@
35734 static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
35739 if (NULL == hctx) return HANDLER_GO_ON;
35742 p = hctx->plugin_data;
35743 con = hctx->remote_conn;
35746 if (con->mode != p->id) return HANDLER_GO_ON;
35748 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35749 - "emergency exit: scgi:",
35750 - "connection-fd:", con->fd,
35751 - "fcgi-fd:", hctx->fd);
35756 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35757 + "emergency exit: scgi:",
35758 + "connection-fd:", con->sock->fd,
35759 + "fcgi-fd:", hctx->sock->fd);
35763 scgi_connection_cleanup(srv, hctx);
35766 return HANDLER_FINISHED;
35769 @@ -2459,27 +2324,28 @@
35770 handler_ctx *hctx = ctx;
35771 connection *con = hctx->remote_conn;
35772 plugin_data *p = hctx->plugin_data;
35775 scgi_proc *proc = hctx->proc;
35776 scgi_extension_host *host= hctx->host;
35778 if ((revents & FDEVENT_IN) &&
35779 - hctx->state == FCGI_STATE_READ) {
35780 + (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35781 + hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
35782 switch (scgi_demux_response(srv, hctx)) {
35787 scgi_connection_cleanup(srv, hctx);
35790 joblist_append(srv, con);
35791 return HANDLER_FINISHED;
35793 if (proc->pid && proc->state != PROC_STATE_DIED) {
35797 /* only fetch the zombie if it is not already done */
35800 switch(waitpid(proc->pid, &status, WNOHANG)) {
35802 /* child is still alive */
35803 @@ -2489,19 +2355,19 @@
35805 /* the child should not terminate at all */
35806 if (WIFEXITED(status)) {
35807 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
35808 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
35809 "child exited, pid:", proc->pid,
35810 "status:", WEXITSTATUS(status));
35811 } else if (WIFSIGNALED(status)) {
35812 - log_error_write(srv, __FILE__, __LINE__, "sd",
35813 - "child signaled:",
35814 + log_error_write(srv, __FILE__, __LINE__, "sd",
35815 + "child signaled:",
35818 - log_error_write(srv, __FILE__, __LINE__, "sd",
35819 - "child died somehow:",
35820 + log_error_write(srv, __FILE__, __LINE__, "sd",
35821 + "child died somehow:",
35826 if (p->conf.debug) {
35827 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35828 "--- scgi spawning",
35829 @@ -2509,40 +2375,41 @@
35830 "\n\tsocket", host->unixsocket,
35831 "\n\tcurrent:", 1, "/", host->min_procs);
35835 if (scgi_spawn_connection(srv, p, host, proc)) {
35837 proc->state = PROC_STATE_DIED;
35839 scgi_proclist_sort_down(srv, host, proc);
35848 if (con->file_started == 0) {
35849 /* nothing has been send out yet, try to use another child */
35852 if (hctx->wb->bytes_out == 0 &&
35853 hctx->reconnects < 5) {
35854 scgi_reconnect(srv, hctx);
35856 - log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35858 + log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35859 "response not sent, request not sent, reconnection.",
35860 - "connection-fd:", con->fd,
35861 - "fcgi-fd:", hctx->fd);
35863 + "connection-fd:", con->sock->fd,
35864 + "fcgi-fd:", hctx->sock->fd);
35866 return HANDLER_WAIT_FOR_FD;
35869 - log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35871 + log_error_write(srv, __FILE__, __LINE__, "sosdsd",
35872 "response not sent, request sent:", hctx->wb->bytes_out,
35873 - "connection-fd:", con->fd,
35874 - "fcgi-fd:", hctx->fd);
35876 + "connection-fd:", con->sock->fd,
35877 + "fcgi-fd:", hctx->sock->fd);
35879 scgi_connection_cleanup(srv, hctx);
35882 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
35883 buffer_reset(con->physical.path);
35884 con->http_status = 500;
35885 @@ -2550,76 +2417,77 @@
35887 /* response might have been already started, kill the connection */
35888 scgi_connection_cleanup(srv, hctx);
35890 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35892 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35893 "response already sent out, termination connection",
35894 - "connection-fd:", con->fd,
35895 - "fcgi-fd:", hctx->fd);
35897 + "connection-fd:", con->sock->fd,
35898 + "fcgi-fd:", hctx->sock->fd);
35900 connection_set_state(srv, con, CON_STATE_ERROR);
35908 joblist_append(srv, con);
35909 return HANDLER_FINISHED;
35914 if (revents & FDEVENT_OUT) {
35915 - if (hctx->state == FCGI_STATE_CONNECT ||
35916 - hctx->state == FCGI_STATE_WRITE) {
35917 + if (hctx->state == SCGI_STATE_CONNECT ||
35918 + hctx->state == SCGI_STATE_WRITE) {
35919 /* we are allowed to send something out
35922 * 1. in a unfinished connect() call
35923 * 2. in a unfinished write() call (long POST request)
35925 return mod_scgi_handle_subrequest(srv, con, p);
35927 - log_error_write(srv, __FILE__, __LINE__, "sd",
35928 - "got a FDEVENT_OUT and didn't know why:",
35929 + log_error_write(srv, __FILE__, __LINE__, "sd",
35930 + "got a FDEVENT_OUT and didn't know why:",
35936 /* perhaps this issue is already handled */
35937 if (revents & FDEVENT_HUP) {
35938 - if (hctx->state == FCGI_STATE_CONNECT) {
35939 + if (hctx->state == SCGI_STATE_CONNECT) {
35940 /* getoptsock will catch this one (right ?)
35942 - * if we are in connect we might get a EINPROGRESS
35943 - * in the first call and a FDEVENT_HUP in the
35945 + * if we are in connect we might get a EINPROGRESS
35946 + * in the first call and a FDEVENT_HUP in the
35950 * FIXME: as it is a bit ugly.
35954 return mod_scgi_handle_subrequest(srv, con, p);
35955 - } else if (hctx->state == FCGI_STATE_READ &&
35956 + } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35957 + hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
35958 hctx->proc->port == 0) {
35962 * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
35963 * even if the FCGI_FIN packet is not received yet
35966 - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35967 - "error: unexpected close of scgi connection for",
35968 + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35969 + "error: unexpected close of scgi connection for",
35971 - "(no scgi process on host: ",
35972 + "(no scgi process on host: ",
35981 connection_set_state(srv, con, CON_STATE_ERROR);
35982 scgi_connection_close(srv, hctx);
35983 joblist_append(srv, con);
35985 } else if (revents & FDEVENT_ERR) {
35986 - log_error_write(srv, __FILE__, __LINE__, "s",
35987 + log_error_write(srv, __FILE__, __LINE__, "s",
35988 "fcgi: got a FDEVENT_ERR. Don't know why.");
35989 /* kill all connections to the scgi process */
35991 @@ -2628,42 +2496,39 @@
35992 scgi_connection_close(srv, hctx);
35993 joblist_append(srv, con);
35997 return HANDLER_FINISHED;
35999 -#define PATCH(x) \
36000 - p->conf.x = s->x;
36002 static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
36004 plugin_config *s = p->config_storage[0];
36010 + PATCH_OPTION(exts);
36011 + PATCH_OPTION(debug);
36013 /* skip the first, the global context */
36014 for (i = 1; i < srv->config_context->used; i++) {
36015 data_config *dc = (data_config *)srv->config_context->data[i];
36016 s = p->config_storage[i];
36019 /* condition didn't match */
36020 if (!config_check_cond(srv, con, dc)) continue;
36024 for (j = 0; j < dc->value->used; j++) {
36025 data_unset *du = dc->value->data[j];
36028 if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
36030 + PATCH_OPTION(exts);
36031 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
36033 + PATCH_OPTION(debug);
36044 static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
36045 plugin_data *p = p_d;
36046 @@ -2673,30 +2538,30 @@
36049 scgi_extension *extension = NULL;
36052 /* Possibly, we processed already this request */
36053 if (con->file_started == 1) return HANDLER_GO_ON;
36056 fn = uri_path_handler ? con->uri.path : con->physical.path;
36058 if (buffer_is_empty(fn)) return HANDLER_GO_ON;
36060 s_len = fn->used - 1;
36063 scgi_patch_connection(srv, con, p);
36065 /* check if extension matches */
36066 for (k = 0; k < p->conf.exts->used; k++) {
36070 extension = p->conf.exts->exts[k];
36073 if (extension->key->used == 0) continue;
36076 ct_len = extension->key->used - 1;
36079 if (s_len < ct_len) continue;
36082 /* check extension in the form "/scgi_pattern" */
36083 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
36085 @@ -2710,17 +2575,17 @@
36086 if (k == p->conf.exts->used) {
36087 return HANDLER_GO_ON;
36091 /* get best server */
36092 for (k = 0, ndx = -1; k < extension->used; k++) {
36093 scgi_extension_host *host = extension->hosts[k];
36096 /* we should have at least one proc that can do somthing */
36097 if (host->active_procs == 0) continue;
36099 if (used == -1 || host->load < used) {
36106 @@ -2728,12 +2593,12 @@
36107 /* found a server */
36109 scgi_extension_host *host = extension->hosts[ndx];
36112 - * if check-local is disabled, use the uri.path handler
36116 + * if check-local is disabled, use the uri.path handler
36121 /* init handler-context */
36122 if (uri_path_handler) {
36123 if (host->check_local == 0) {
36124 @@ -2741,7 +2606,7 @@
36127 hctx = handler_ctx_init();
36130 hctx->remote_conn = con;
36131 hctx->plugin_data = p;
36133 @@ -2749,45 +2614,45 @@
36135 hctx->conf.exts = p->conf.exts;
36136 hctx->conf.debug = p->conf.debug;
36139 con->plugin_ctx[p->id] = hctx;
36147 if (con->conf.log_request_handling) {
36148 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
36151 - /* the prefix is the SCRIPT_NAME,
36152 + /* the prefix is the SCRIPT_NAME,
36153 * everthing from start to the next slash
36154 * this is important for check-local = "disable"
36157 * if prefix = /admin.fcgi
36160 * /admin.fcgi/foo/bar
36163 * SCRIPT_NAME = /admin.fcgi
36164 * PATH_INFO = /foo/bar
36167 * if prefix = /fcgi-bin/
36170 * /fcgi-bin/foo/bar
36173 * SCRIPT_NAME = /fcgi-bin/foo
36180 /* the rewrite is only done for /prefix/? matches */
36181 if (extension->key->ptr[0] == '/' &&
36182 con->uri.path->used > extension->key->used &&
36183 NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
36184 - /* rewrite uri.path and pathinfo */
36186 + /* rewrite uri.path and pathinfo */
36188 buffer_copy_string(con->request.pathinfo, pathinfo);
36191 con->uri.path->used -= con->request.pathinfo->used - 1;
36192 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
36194 @@ -2796,21 +2661,21 @@
36197 hctx = handler_ctx_init();
36200 hctx->remote_conn = con;
36201 hctx->plugin_data = p;
36206 hctx->conf.exts = p->conf.exts;
36207 hctx->conf.debug = p->conf.debug;
36210 con->plugin_ctx[p->id] = hctx;
36219 if (con->conf.log_request_handling) {
36220 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
36222 @@ -2821,11 +2686,11 @@
36223 /* no handler found */
36224 buffer_reset(con->physical.path);
36225 con->http_status = 500;
36227 - log_error_write(srv, __FILE__, __LINE__, "sb",
36228 - "no fcgi-handler found for:",
36230 + log_error_write(srv, __FILE__, __LINE__, "sb",
36231 + "no fcgi-handler found for:",
36235 return HANDLER_FINISHED;
36237 return HANDLER_GO_ON;
36238 @@ -2844,21 +2709,22 @@
36239 JOBLIST_FUNC(mod_scgi_handle_joblist) {
36240 plugin_data *p = p_d;
36241 handler_ctx *hctx = con->plugin_ctx[p->id];
36244 if (hctx == NULL) return HANDLER_GO_ON;
36246 - if (hctx->fd != -1) {
36247 + if (hctx->sock->fd != -1) {
36248 switch (hctx->state) {
36249 - case FCGI_STATE_READ:
36250 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
36252 + case SCGI_STATE_RESPONSE_HEADER:
36253 + case SCGI_STATE_RESPONSE_CONTENT:
36254 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
36257 - case FCGI_STATE_CONNECT:
36258 - case FCGI_STATE_WRITE:
36259 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
36261 + case SCGI_STATE_CONNECT:
36262 + case SCGI_STATE_WRITE:
36263 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
36266 - case FCGI_STATE_INIT:
36267 + case SCGI_STATE_INIT:
36271 @@ -2873,21 +2739,21 @@
36273 static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
36274 plugin_data *p = p_d;
36277 return scgi_connection_close(srv, con->plugin_ctx[p->id]);
36280 TRIGGER_FUNC(mod_scgi_handle_trigger) {
36281 plugin_data *p = p_d;
36287 /* perhaps we should kill a connect attempt after 10-15 seconds
36290 * currently we wait for the TCP timeout which is on Linux 180 seconds
36299 /* check all childs if they are still up */
36300 @@ -2904,47 +2770,47 @@
36301 scgi_extension *ex;
36303 ex = exts->exts[j];
36306 for (n = 0; n < ex->used; n++) {
36310 unsigned long sum_load = 0;
36311 scgi_extension_host *host;
36314 host = ex->hosts[n];
36317 scgi_restart_dead_procs(srv, p, host);
36320 for (proc = host->first; proc; proc = proc->next) {
36321 sum_load += proc->load;
36325 if (host->num_procs &&
36326 host->num_procs < host->max_procs &&
36327 (sum_load / host->num_procs) > host->max_load_per_proc) {
36328 /* overload, spawn new child */
36329 scgi_proc *fp = NULL;
36332 if (p->conf.debug) {
36333 - log_error_write(srv, __FILE__, __LINE__, "s",
36334 + log_error_write(srv, __FILE__, __LINE__, "s",
36335 "overload detected, spawning a new child");
36339 for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
36343 if (fp == host->unused_procs) host->unused_procs = fp->next;
36346 if (fp->next) fp->next->prev = NULL;
36351 fp = scgi_process_init();
36352 fp->id = host->max_id++;
36359 if (buffer_is_empty(host->unixsocket)) {
36360 fp->port = host->port + fp->id;
36362 @@ -2952,13 +2818,13 @@
36363 buffer_append_string(fp->socket, "-");
36364 buffer_append_long(fp->socket, fp->id);
36368 if (scgi_spawn_connection(srv, p, host, fp)) {
36369 log_error_write(srv, __FILE__, __LINE__, "s",
36370 "ERROR: spawning fcgi failed.");
36371 return HANDLER_ERROR;
36376 fp->next = host->first;
36378 @@ -2966,56 +2832,57 @@
36384 for (proc = host->first; proc; proc = proc->next) {
36385 if (proc->load != 0) break;
36386 if (host->num_procs <= host->min_procs) break;
36387 if (proc->pid == 0) continue;
36390 if (srv->cur_ts - proc->last_used > host->idle_timeout) {
36391 /* a proc is idling for a long time now,
36395 if (p->conf.debug) {
36396 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36397 - "idle-timeout reached, terminating child:",
36398 - "socket:", proc->socket,
36399 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36400 + "idle-timeout reached, terminating child:",
36401 + "socket:", proc->socket,
36408 if (proc->next) proc->next->prev = proc->prev;
36409 if (proc->prev) proc->prev->next = proc->next;
36412 if (proc->prev == NULL) host->first = proc->next;
36416 proc->next = host->unused_procs;
36419 if (host->unused_procs) host->unused_procs->prev = proc;
36420 host->unused_procs = proc;
36423 kill(proc->pid, SIGTERM);
36426 proc->state = PROC_STATE_KILLED;
36428 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36430 - "socket:", proc->socket,
36432 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
36434 + "socket:", proc->socket,
36441 /* proc is now in unused, let the next second handle the next process */
36449 for (proc = host->unused_procs; proc; proc = proc->next) {
36453 if (proc->pid == 0) continue;
36456 switch (waitpid(proc->pid, &status, WNOHANG)) {
36458 /* child still running after timeout, good */
36459 @@ -3023,10 +2890,10 @@
36461 if (errno != EINTR) {
36462 /* no PID found ? should never happen */
36463 - log_error_write(srv, __FILE__, __LINE__, "sddss",
36464 + log_error_write(srv, __FILE__, __LINE__, "sddss",
36465 "pid ", proc->pid, proc->state,
36466 "not found:", strerror(errno));
36470 if (errno == ECHILD) {
36471 /* someone else has cleaned up for us */
36472 @@ -3040,25 +2907,26 @@
36473 /* the child should not terminate at all */
36474 if (WIFEXITED(status)) {
36475 if (proc->state != PROC_STATE_KILLED) {
36476 - log_error_write(srv, __FILE__, __LINE__, "sdb",
36478 + log_error_write(srv, __FILE__, __LINE__, "sdb",
36480 WEXITSTATUS(status), proc->socket);
36482 } else if (WIFSIGNALED(status)) {
36483 if (WTERMSIG(status) != SIGTERM) {
36484 - log_error_write(srv, __FILE__, __LINE__, "sd",
36485 - "child signaled:",
36486 + log_error_write(srv, __FILE__, __LINE__, "sd",
36487 + "child signaled:",
36491 - log_error_write(srv, __FILE__, __LINE__, "sd",
36492 - "child died somehow:",
36493 + log_error_write(srv, __FILE__, __LINE__, "sd",
36494 + "child died somehow:",
36498 proc->state = PROC_STATE_UNSET;
36505 @@ -3082,8 +2950,8 @@
36506 p->handle_subrequest = mod_scgi_handle_subrequest;
36507 p->handle_joblist = mod_scgi_handle_joblist;
36508 p->handle_trigger = mod_scgi_handle_trigger;
36516 --- ../lighttpd-1.4.11/src/mod_secure_download.c 2005-12-14 14:37:29.000000000 +0200
36517 +++ lighttpd-1.4.12/src/mod_secure_download.c 2006-07-16 00:26:03.000000000 +0300
36527 @@ -36,28 +36,28 @@
36530 buffer *uri_prefix;
36533 unsigned short timeout;
36543 plugin_config **config_storage;
36545 - plugin_config conf;
36547 + plugin_config conf;
36550 /* init the plugin data */
36551 INIT_FUNC(mod_secdownload_init) {
36555 p = calloc(1, sizeof(*p));
36558 p->md5 = buffer_init();
36564 @@ -65,27 +65,27 @@
36565 FREE_FUNC(mod_secdownload_free) {
36566 plugin_data *p = p_d;
36570 if (!p) return HANDLER_GO_ON;
36573 if (p->config_storage) {
36575 for (i = 0; i < srv->config_context->used; i++) {
36576 plugin_config *s = p->config_storage[i];
36579 buffer_free(s->secret);
36580 buffer_free(s->doc_root);
36581 buffer_free(s->uri_prefix);
36586 free(p->config_storage);
36590 buffer_free(p->md5);
36596 return HANDLER_GO_ON;
36599 @@ -94,107 +94,103 @@
36600 SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
36601 plugin_data *p = p_d;
36604 - config_values_t cv[] = {
36606 + config_values_t cv[] = {
36607 { "secdownload.secret", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36608 { "secdownload.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
36609 { "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
36610 { "secdownload.timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
36611 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36615 if (!p) return HANDLER_ERROR;
36618 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36621 for (i = 0; i < srv->config_context->used; i++) {
36625 s = calloc(1, sizeof(plugin_config));
36626 s->secret = buffer_init();
36627 s->doc_root = buffer_init();
36628 s->uri_prefix = buffer_init();
36632 cv[0].destination = s->secret;
36633 cv[1].destination = s->doc_root;
36634 cv[2].destination = s->uri_prefix;
36635 cv[3].destination = &(s->timeout);
36638 p->config_storage[i] = s;
36641 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36642 return HANDLER_ERROR;
36647 return HANDLER_GO_ON;
36651 * checks if the supplied string is a MD5 string
36654 * @param str a possible MD5 string
36655 * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
36658 int is_hex_len(const char *str, size_t len) {
36662 if (NULL == str) return 0;
36665 for (i = 0; i < len && *str; i++, str++) {
36666 /* illegal characters */
36667 if (!((*str >= '0' && *str <= '9') ||
36668 (*str >= 'a' && *str <= 'f') ||
36669 - (*str >= 'A' && *str <= 'F'))
36670 + (*str >= 'A' && *str <= 'F'))
36680 -#define PATCH(x) \
36681 - p->conf.x = s->x;
36682 static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
36684 plugin_config *s = p->config_storage[0];
36688 - PATCH(uri_prefix);
36692 + PATCH_OPTION(secret);
36693 + PATCH_OPTION(doc_root);
36694 + PATCH_OPTION(uri_prefix);
36695 + PATCH_OPTION(timeout);
36697 /* skip the first, the global context */
36698 for (i = 1; i < srv->config_context->used; i++) {
36699 data_config *dc = (data_config *)srv->config_context->data[i];
36700 s = p->config_storage[i];
36703 /* condition didn't match */
36704 if (!config_check_cond(srv, con, dc)) continue;
36708 for (j = 0; j < dc->value->used; j++) {
36709 data_unset *du = dc->value->data[j];
36712 if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
36714 + PATCH_OPTION(secret);
36715 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
36717 + PATCH_OPTION(doc_root);
36718 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
36719 - PATCH(uri_prefix);
36720 + PATCH_OPTION(uri_prefix);
36721 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
36723 + PATCH_OPTION(timeout);
36734 URIHANDLER_FUNC(mod_secdownload_uri_handler) {
36735 plugin_data *p = p_d;
36736 @@ -203,88 +199,88 @@
36737 const char *rel_uri, *ts_str, *md5_str;
36742 if (con->uri.path->used == 0) return HANDLER_GO_ON;
36745 mod_secdownload_patch_connection(srv, con, p);
36747 if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
36750 if (buffer_is_empty(p->conf.secret)) {
36751 log_error_write(srv, __FILE__, __LINE__, "s",
36752 "secdownload.secret has to be set");
36753 return HANDLER_ERROR;
36757 if (buffer_is_empty(p->conf.doc_root)) {
36758 log_error_write(srv, __FILE__, __LINE__, "s",
36759 "secdownload.document-root has to be set");
36760 return HANDLER_ERROR;
36766 * /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
36770 if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
36773 md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
36776 if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
36777 if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
36780 ts_str = md5_str + 32 + 1;
36783 if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
36784 if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
36787 for (i = 0; i < 8; i++) {
36788 ts = (ts << 4) + hex2int(*(ts_str + i));
36793 - if (srv->cur_ts - ts > p->conf.timeout ||
36794 + if (srv->cur_ts - ts > p->conf.timeout ||
36795 srv->cur_ts - ts < -p->conf.timeout) {
36796 con->http_status = 408;
36799 return HANDLER_FINISHED;
36803 rel_uri = ts_str + 8;
36810 * <secret><rel-path><timestamp-hex>
36814 buffer_copy_string_buffer(p->md5, p->conf.secret);
36815 buffer_append_string(p->md5, rel_uri);
36816 buffer_append_string_len(p->md5, ts_str, 8);
36820 MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
36821 MD5_Final(HA1, &Md5Ctx);
36824 buffer_copy_string_hex(p->md5, (char *)HA1, 16);
36827 if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
36828 con->http_status = 403;
36830 - log_error_write(srv, __FILE__, __LINE__, "sss",
36832 + log_error_write(srv, __FILE__, __LINE__, "sss",
36834 md5_str, p->md5->ptr);
36837 return HANDLER_FINISHED;
36841 /* starting with the last / we should have relative-path to the docroot
36845 buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
36846 buffer_copy_string(con->physical.rel_path, rel_uri);
36847 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
36848 buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
36851 return HANDLER_GO_ON;
36854 @@ -293,13 +289,13 @@
36855 int mod_secdownload_plugin_init(plugin *p) {
36856 p->version = LIGHTTPD_VERSION_ID;
36857 p->name = buffer_init_string("secdownload");
36860 p->init = mod_secdownload_init;
36861 p->handle_physical = mod_secdownload_uri_handler;
36862 p->set_defaults = mod_secdownload_set_defaults;
36863 p->cleanup = mod_secdownload_free;
36871 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
36872 +++ lighttpd-1.4.12/src/mod_setenv.c 2006-07-16 00:26:04.000000000 +0300
36873 @@ -18,25 +18,25 @@
36875 array *request_header;
36876 array *response_header;
36879 array *environment;
36886 plugin_config **config_storage;
36888 - plugin_config conf;
36890 + plugin_config conf;
36893 static handler_ctx * handler_ctx_init() {
36894 handler_ctx * hctx;
36897 hctx = calloc(1, sizeof(*hctx));
36906 @@ -48,36 +48,36 @@
36907 /* init the plugin data */
36908 INIT_FUNC(mod_setenv_init) {
36912 p = calloc(1, sizeof(*p));
36918 /* detroy the plugin data */
36919 FREE_FUNC(mod_setenv_free) {
36920 plugin_data *p = p_d;
36925 if (!p) return HANDLER_GO_ON;
36928 if (p->config_storage) {
36930 for (i = 0; i < srv->config_context->used; i++) {
36931 plugin_config *s = p->config_storage[i];
36934 array_free(s->request_header);
36935 array_free(s->response_header);
36936 array_free(s->environment);
36941 free(p->config_storage);
36948 return HANDLER_GO_ON;
36951 @@ -86,86 +86,83 @@
36952 SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
36953 plugin_data *p = p_d;
36956 - config_values_t cv[] = {
36958 + config_values_t cv[] = {
36959 { "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36960 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
36961 { "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
36962 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36966 if (!p) return HANDLER_ERROR;
36969 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36972 for (i = 0; i < srv->config_context->used; i++) {
36976 s = calloc(1, sizeof(plugin_config));
36977 s->request_header = array_init();
36978 s->response_header = array_init();
36979 s->environment = array_init();
36982 cv[0].destination = s->request_header;
36983 cv[1].destination = s->response_header;
36984 cv[2].destination = s->environment;
36987 p->config_storage[i] = s;
36990 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36991 return HANDLER_ERROR;
36996 return HANDLER_GO_ON;
36999 -#define PATCH(x) \
37000 - p->conf.x = s->x;
37001 static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
37003 plugin_config *s = p->config_storage[0];
37005 - PATCH(request_header);
37006 - PATCH(response_header);
37007 - PATCH(environment);
37010 + PATCH_OPTION(request_header);
37011 + PATCH_OPTION(response_header);
37012 + PATCH_OPTION(environment);
37014 /* skip the first, the global context */
37015 for (i = 1; i < srv->config_context->used; i++) {
37016 data_config *dc = (data_config *)srv->config_context->data[i];
37017 s = p->config_storage[i];
37020 /* condition didn't match */
37021 if (!config_check_cond(srv, con, dc)) continue;
37025 for (j = 0; j < dc->value->used; j++) {
37026 data_unset *du = dc->value->data[j];
37029 if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
37030 - PATCH(request_header);
37031 + PATCH_OPTION(request_header);
37032 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
37033 - PATCH(response_header);
37034 + PATCH_OPTION(response_header);
37035 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
37036 - PATCH(environment);
37037 + PATCH_OPTION(environment);
37047 URIHANDLER_FUNC(mod_setenv_uri_handler) {
37048 plugin_data *p = p_d;
37053 if (con->plugin_ctx[p->id]) {
37054 hctx = con->plugin_ctx[p->id];
37056 hctx = handler_ctx_init();
37059 con->plugin_ctx[p->id] = hctx;
37062 @@ -180,52 +177,52 @@
37063 for (k = 0; k < p->conf.request_header->used; k++) {
37064 data_string *ds = (data_string *)p->conf.request_header->data[k];
37065 data_string *ds_dst;
37068 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
37069 ds_dst = data_string_init();
37073 buffer_copy_string_buffer(ds_dst->key, ds->key);
37074 buffer_copy_string_buffer(ds_dst->value, ds->value);
37077 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
37081 for (k = 0; k < p->conf.environment->used; k++) {
37082 data_string *ds = (data_string *)p->conf.environment->data[k];
37083 data_string *ds_dst;
37086 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
37087 ds_dst = data_string_init();
37091 buffer_copy_string_buffer(ds_dst->key, ds->key);
37092 buffer_copy_string_buffer(ds_dst->value, ds->value);
37095 array_insert_unique(con->environment, (data_unset *)ds_dst);
37099 for (k = 0; k < p->conf.response_header->used; k++) {
37100 data_string *ds = (data_string *)p->conf.response_header->data[k];
37103 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
37108 return HANDLER_GO_ON;
37111 REQUESTDONE_FUNC(mod_setenv_reset) {
37112 plugin_data *p = p_d;
37118 if (con->plugin_ctx[p->id]) {
37119 handler_ctx_free(con->plugin_ctx[p->id]);
37120 con->plugin_ctx[p->id] = NULL;
37123 - return HANDLER_GO_ON;
37124 + return HANDLER_GO_ON;
37127 /* this function is called at dlopen() time and inits the callbacks */
37128 @@ -233,15 +230,15 @@
37129 int mod_setenv_plugin_init(plugin *p) {
37130 p->version = LIGHTTPD_VERSION_ID;
37131 p->name = buffer_init_string("setenv");
37134 p->init = mod_setenv_init;
37135 p->handle_uri_clean = mod_setenv_uri_handler;
37136 p->set_defaults = mod_setenv_set_defaults;
37137 p->cleanup = mod_setenv_free;
37140 p->handle_request_done = mod_setenv_reset;
37147 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c 2005-11-18 15:16:13.000000000 +0200
37148 +++ lighttpd-1.4.12/src/mod_simple_vhost.c 2006-07-16 00:26:04.000000000 +0300
37151 #include "plugin.h"
37153 +#include "sys-files.h"
37155 #ifdef HAVE_CONFIG_H
37156 #include "config.h"
37159 buffer *server_root;
37160 buffer *default_host;
37161 buffer *document_root;
37164 buffer *docroot_cache_key;
37165 buffer *docroot_cache_value;
37166 buffer *docroot_cache_servername;
37167 @@ -28,138 +30,138 @@
37176 plugin_config **config_storage;
37177 - plugin_config conf;
37178 + plugin_config conf;
37181 INIT_FUNC(mod_simple_vhost_init) {
37185 p = calloc(1, sizeof(*p));
37188 p->doc_root = buffer_init();
37194 FREE_FUNC(mod_simple_vhost_free) {
37195 plugin_data *p = p_d;
37200 if (!p) return HANDLER_GO_ON;
37203 if (p->config_storage) {
37205 for (i = 0; i < srv->config_context->used; i++) {
37206 plugin_config *s = p->config_storage[i];
37209 buffer_free(s->document_root);
37210 buffer_free(s->default_host);
37211 buffer_free(s->server_root);
37214 buffer_free(s->docroot_cache_key);
37215 buffer_free(s->docroot_cache_value);
37216 buffer_free(s->docroot_cache_servername);
37223 free(p->config_storage);
37227 buffer_free(p->doc_root);
37233 return HANDLER_GO_ON;
37236 SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
37237 plugin_data *p = p_d;
37240 - config_values_t cv[] = {
37242 + config_values_t cv[] = {
37243 { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37244 { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37245 { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
37246 { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
37247 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37251 if (!p) return HANDLER_ERROR;
37254 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37257 for (i = 0; i < srv->config_context->used; i++) {
37261 s = calloc(1, sizeof(plugin_config));
37264 s->server_root = buffer_init();
37265 s->default_host = buffer_init();
37266 s->document_root = buffer_init();
37269 s->docroot_cache_key = buffer_init();
37270 s->docroot_cache_value = buffer_init();
37271 s->docroot_cache_servername = buffer_init();
37276 cv[0].destination = s->server_root;
37277 cv[1].destination = s->default_host;
37278 cv[2].destination = s->document_root;
37279 cv[3].destination = &(s->debug);
37284 p->config_storage[i] = s;
37287 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37288 return HANDLER_ERROR;
37293 return HANDLER_GO_ON;
37296 static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
37297 stat_cache_entry *sce = NULL;
37300 buffer_prepare_copy(out, 128);
37302 if (p->conf.server_root->used) {
37303 buffer_copy_string_buffer(out, p->conf.server_root);
37307 /* a hostname has to start with a alpha-numerical character
37308 * and must not contain a slash "/"
37312 - BUFFER_APPEND_SLASH(out);
37315 + PATHNAME_APPEND_SLASH(out);
37317 if (NULL == (dp = strchr(host->ptr, ':'))) {
37318 buffer_append_string_buffer(out, host);
37320 buffer_append_string_len(out, host->ptr, dp - host->ptr);
37323 - BUFFER_APPEND_SLASH(out);
37325 + PATHNAME_APPEND_SLASH(out);
37327 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
37328 buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
37330 buffer_append_string_buffer(out, p->conf.document_root);
37331 - BUFFER_APPEND_SLASH(out);
37332 + PATHNAME_APPEND_SLASH(out);
37335 buffer_copy_string_buffer(out, con->conf.document_root);
37336 - BUFFER_APPEND_SLASH(out);
37337 + PATHNAME_APPEND_SLASH(out);
37341 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
37342 if (p->conf.debug) {
37343 log_error_write(srv, __FILE__, __LINE__, "sb",
37344 @@ -169,57 +171,53 @@
37345 } else if (!S_ISDIR(sce->st.st_mode)) {
37354 -#define PATCH(x) \
37355 - p->conf.x = s->x;
37356 static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
37358 plugin_config *s = p->config_storage[0];
37360 - PATCH(server_root);
37361 - PATCH(default_host);
37362 - PATCH(document_root);
37364 - PATCH(docroot_cache_key);
37365 - PATCH(docroot_cache_value);
37366 - PATCH(docroot_cache_servername);
37370 + PATCH_OPTION(server_root);
37371 + PATCH_OPTION(default_host);
37372 + PATCH_OPTION(document_root);
37374 + PATCH_OPTION(docroot_cache_key);
37375 + PATCH_OPTION(docroot_cache_value);
37376 + PATCH_OPTION(docroot_cache_servername);
37378 + PATCH_OPTION(debug);
37380 /* skip the first, the global context */
37381 for (i = 1; i < srv->config_context->used; i++) {
37382 data_config *dc = (data_config *)srv->config_context->data[i];
37383 s = p->config_storage[i];
37386 /* condition didn't match */
37387 if (!config_check_cond(srv, con, dc)) continue;
37391 for (j = 0; j < dc->value->used; j++) {
37392 data_unset *du = dc->value->data[j];
37395 if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
37396 - PATCH(server_root);
37397 - PATCH(docroot_cache_key);
37398 - PATCH(docroot_cache_value);
37399 - PATCH(docroot_cache_servername);
37400 + PATCH_OPTION(server_root);
37401 + PATCH_OPTION(docroot_cache_key);
37402 + PATCH_OPTION(docroot_cache_value);
37403 + PATCH_OPTION(docroot_cache_servername);
37404 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
37405 - PATCH(default_host);
37406 + PATCH_OPTION(default_host);
37407 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
37408 - PATCH(document_root);
37409 + PATCH_OPTION(document_root);
37410 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
37412 + PATCH_OPTION(debug);
37422 static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
37423 plugin_data *p = p_data;
37424 @@ -227,12 +225,12 @@
37426 * cache the last successfull translation from hostname (authority) to docroot
37427 * - this saves us a stat() call
37433 mod_simple_vhost_patch_connection(srv, con, p);
37435 - if (p->conf.docroot_cache_key->used &&
37437 + if (p->conf.docroot_cache_key->used &&
37438 con->uri.authority->used &&
37439 buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
37441 @@ -243,8 +241,8 @@
37442 if ((con->uri.authority->used == 0) ||
37443 build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
37444 /* not found, fallback the default-host */
37445 - if (build_doc_root(srv, con, p,
37447 + if (build_doc_root(srv, con, p,
37449 p->conf.default_host)) {
37450 return HANDLER_GO_ON;
37452 @@ -253,15 +251,15 @@
37454 buffer_copy_string_buffer(con->server_name, con->uri.authority);
37458 /* copy to cache */
37459 buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority);
37460 buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root);
37461 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
37464 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
37468 return HANDLER_GO_ON;
37471 @@ -269,13 +267,13 @@
37472 int mod_simple_vhost_plugin_init(plugin *p) {
37473 p->version = LIGHTTPD_VERSION_ID;
37474 p->name = buffer_init_string("simple_vhost");
37477 p->init = mod_simple_vhost_init;
37478 p->set_defaults = mod_simple_vhost_set_defaults;
37479 p->handle_docroot = mod_simple_vhost_docroot;
37480 p->cleanup = mod_simple_vhost_free;
37488 --- ../lighttpd-1.4.11/src/mod_skeleton.c 2005-10-02 18:30:51.000000000 +0300
37489 +++ lighttpd-1.4.12/src/mod_skeleton.c 2006-07-16 00:26:03.000000000 +0300
37490 @@ -14,13 +14,13 @@
37493 * this is a skeleton for a lighttpd plugin
37496 * just replaces every occurance of 'skeleton' by your plugin name
37502 * :%s/skeleton/myhandler/
37508 @@ -33,12 +33,12 @@
37517 plugin_config **config_storage;
37519 - plugin_config conf;
37521 + plugin_config conf;
37525 @@ -47,36 +47,36 @@
37527 static handler_ctx * handler_ctx_init() {
37528 handler_ctx * hctx;
37531 hctx = calloc(1, sizeof(*hctx));
37537 static void handler_ctx_free(handler_ctx *hctx) {
37543 /* init the plugin data */
37544 INIT_FUNC(mod_skeleton_init) {
37548 p = calloc(1, sizeof(*p));
37551 p->match_buf = buffer_init();
37557 /* detroy the plugin data */
37558 FREE_FUNC(mod_skeleton_free) {
37559 plugin_data *p = p_d;
37564 if (!p) return HANDLER_GO_ON;
37567 if (p->config_storage) {
37570 @@ -84,18 +84,18 @@
37571 plugin_config *s = p->config_storage[i];
37576 array_free(s->match);
37581 free(p->config_storage);
37585 buffer_free(p->match_buf);
37591 return HANDLER_GO_ON;
37594 @@ -104,91 +104,88 @@
37595 SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
37596 plugin_data *p = p_d;
37599 - config_values_t cv[] = {
37601 + config_values_t cv[] = {
37602 { "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
37603 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37607 if (!p) return HANDLER_ERROR;
37610 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37613 for (i = 0; i < srv->config_context->used; i++) {
37617 s = calloc(1, sizeof(plugin_config));
37618 s->match = array_init();
37621 cv[0].destination = s->match;
37624 p->config_storage[i] = s;
37627 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37628 return HANDLER_ERROR;
37633 return HANDLER_GO_ON;
37636 -#define PATCH(x) \
37637 - p->conf.x = s->x;
37638 static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
37640 plugin_config *s = p->config_storage[0];
37645 + PATCH_OPTION(match);
37647 /* skip the first, the global context */
37648 for (i = 1; i < srv->config_context->used; i++) {
37649 data_config *dc = (data_config *)srv->config_context->data[i];
37650 s = p->config_storage[i];
37653 /* condition didn't match */
37654 if (!config_check_cond(srv, con, dc)) continue;
37658 for (j = 0; j < dc->value->used; j++) {
37659 data_unset *du = dc->value->data[j];
37662 if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
37664 + PATCH_OPTION(match);
37674 URIHANDLER_FUNC(mod_skeleton_uri_handler) {
37675 plugin_data *p = p_d;
37682 if (con->uri.path->used == 0) return HANDLER_GO_ON;
37685 mod_skeleton_patch_connection(srv, con, p);
37687 s_len = con->uri.path->used - 1;
37690 for (k = 0; k < p->conf.match->used; k++) {
37691 data_string *ds = (data_string *)p->conf.match->data[k];
37692 int ct_len = ds->value->used - 1;
37695 if (ct_len > s_len) continue;
37696 if (ds->value->used == 0) continue;
37699 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
37700 con->http_status = 403;
37703 return HANDLER_FINISHED;
37709 return HANDLER_GO_ON;
37711 @@ -198,13 +195,13 @@
37712 int mod_skeleton_plugin_init(plugin *p) {
37713 p->version = LIGHTTPD_VERSION_ID;
37714 p->name = buffer_init_string("skeleton");
37717 p->init = mod_skeleton_init;
37718 p->handle_uri_clean = mod_skeleton_uri_handler;
37719 p->set_defaults = mod_skeleton_set_defaults;
37720 p->cleanup = mod_skeleton_free;
37728 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
37729 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.c 2006-07-20 00:57:20.000000000 +0300
37731 +#include <stdio.h>
37732 +#include <errno.h>
37733 +#include <fcntl.h>
37734 +#include <string.h>
37736 +#ifdef HAVE_CONFIG_H
37737 +#include "config.h"
37740 +#include "plugin.h"
37743 +#include "stat_cache.h"
37745 +#include "mod_sql_vhost_core.h"
37747 +#define plugin_data mod_sql_vhost_core_plugin_data
37748 +#define plugin_config mod_sql_vhost_core_plugin_config
37750 +/* init the plugin data */
37751 +INIT_FUNC(mod_sql_vhost_core_init) {
37754 + p = calloc(1, sizeof(*p));
37756 + p->docroot = buffer_init();
37757 + p->host = buffer_init();
37762 +/* cleanup the plugin data */
37763 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
37764 + plugin_data *p = p_d;
37768 + if (!p) return HANDLER_GO_ON;
37770 + if (p->config_storage) {
37772 + for (i = 0; i < srv->config_context->used; i++) {
37773 + plugin_config *s = p->config_storage[i];
37775 + if (!s) continue;
37777 + buffer_free(s->db);
37778 + buffer_free(s->user);
37779 + buffer_free(s->pass);
37780 + buffer_free(s->sock);
37781 + buffer_free(s->backend);
37782 + buffer_free(s->hostname);
37783 + buffer_free(s->select_vhost);
37787 + free(p->config_storage);
37789 + buffer_free(p->docroot);
37790 + buffer_free(p->host);
37794 + return HANDLER_GO_ON;
37797 +/* set configuration values */
37798 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
37799 + plugin_data *p = p_d;
37803 + config_values_t cv[] = {
37804 + { "sql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
37805 + { "sql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
37806 + { "sql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
37807 + { "sql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
37808 + { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
37809 + { "sql-vhost.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
37810 + { "sql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
37811 + { "sql-vhost.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
37813 + /* backward compat */
37814 + { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
37815 + { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
37816 + { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
37817 + { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
37818 + { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
37819 + { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
37820 + { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
37822 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37825 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37827 + for (i = 0; i < srv->config_context->used; i++) {
37828 + plugin_config *s;
37830 + s = calloc(1, sizeof(plugin_config));
37831 + s->db = buffer_init();
37832 + s->user = buffer_init();
37833 + s->pass = buffer_init();
37834 + s->sock = buffer_init();
37835 + s->hostname = buffer_init();
37836 + s->backend = buffer_init();
37837 + s->port = 0; /* default port for mysql */
37838 + s->select_vhost = buffer_init();
37839 + s->backend_data = NULL;
37841 + cv[0].destination = s->db;
37842 + cv[1].destination = s->user;
37843 + cv[2].destination = s->pass;
37844 + cv[3].destination = s->sock;
37845 + cv[4].destination = s->select_vhost;
37846 + cv[5].destination = s->hostname;
37847 + cv[6].destination = &(s->port);
37848 + cv[7].destination = s->backend;
37850 + /* backend compat */
37851 + cv[8].destination = cv[0].destination;
37852 + cv[9].destination = cv[1].destination;
37853 + cv[10].destination = cv[2].destination;
37854 + cv[11].destination = cv[3].destination;
37855 + cv[12].destination = cv[4].destination;
37856 + cv[13].destination = cv[5].destination;
37857 + cv[14].destination = cv[6].destination;
37859 + p->config_storage[i] = s;
37861 + if (config_insert_values_global(srv,
37862 + ((data_config *)srv->config_context->data[i])->value,
37863 + cv)) return HANDLER_ERROR;
37865 + /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
37868 + return HANDLER_GO_ON;
37871 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
37873 + plugin_config *s = p->config_storage[0];
37875 + PATCH_OPTION(backend_data);
37876 + PATCH_OPTION(get_vhost);
37878 + /* skip the first, the global context */
37879 + for (i = 1; i < srv->config_context->used; i++) {
37880 + data_config *dc = (data_config *)srv->config_context->data[i];
37881 + s = p->config_storage[i];
37883 + /* condition didn't match */
37884 + if (!config_check_cond(srv, con, dc)) continue;
37886 + if (s->backend_data) {
37887 + PATCH_OPTION(backend_data);
37888 + PATCH_OPTION(get_vhost);
37895 +/* handle document root request */
37896 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
37897 + plugin_data *p = p_d;
37898 + stat_cache_entry *sce;
37900 + /* no host specified? */
37901 + if (!con->uri.authority->used) return HANDLER_GO_ON;
37903 + mod_sql_vhost_core_patch_connection(srv, con, p);
37905 + /* do we have backend ? */
37906 + if (!p->conf.get_vhost) return HANDLER_GO_ON;
37908 + /* ask the backend for the data */
37909 + if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
37910 + return HANDLER_GO_ON;
37913 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
37914 + log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
37915 + return HANDLER_GO_ON;
37917 + if (!S_ISDIR(sce->st.st_mode)) {
37918 + log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
37919 + return HANDLER_GO_ON;
37922 + buffer_copy_string_buffer(con->server_name, p->host);
37923 + buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
37925 + return HANDLER_GO_ON;
37928 +/* this function is called at dlopen() time and inits the callbacks */
37929 +int mod_sql_vhost_core_plugin_init(plugin *p) {
37930 + p->version = LIGHTTPD_VERSION_ID;
37931 + p->name = buffer_init_string("mod_sql_vhost_core");
37933 + p->init = mod_sql_vhost_core_init;
37934 + p->cleanup = mod_sql_vhost_core_cleanup;
37936 + p->set_defaults = mod_sql_vhost_core_set_defaults;
37937 + p->handle_docroot = mod_sql_vhost_core_handle_docroot;
37942 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
37943 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.h 2006-07-16 00:26:04.000000000 +0300
37945 +#ifndef _MOD_SQL_VHOST_CORE_H_
37946 +#define _MOD_SQL_VHOST_CORE_H_
37948 +#include "buffer.h"
37949 +#include "plugin.h"
37951 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
37952 + (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
37954 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
37956 +#define SQLVHOST_BACKEND_GETVHOST(name) \
37957 + SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
37959 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
37960 + SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
37968 + buffer *hostname;
37969 + unsigned short port;
37972 + void *backend_data;
37974 + buffer *select_vhost;
37976 + SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
37977 +} mod_sql_vhost_core_plugin_config;
37979 +/* global plugin data */
37986 + mod_sql_vhost_core_plugin_config **config_storage;
37988 + mod_sql_vhost_core_plugin_config conf;
37989 +} mod_sql_vhost_core_plugin_data;
37994 --- ../lighttpd-1.4.11/src/mod_ssi.c 2006-03-04 17:09:48.000000000 +0200
37995 +++ lighttpd-1.4.12/src/mod_ssi.c 2006-07-16 00:26:04.000000000 +0300
37997 #include <string.h>
38000 -#include <unistd.h>
38005 #include "inet_ntop_cache.h"
38007 #include "sys-socket.h"
38008 +#include "sys-strings.h"
38009 +#include "sys-files.h"
38013 @@ -39,15 +40,15 @@
38014 /* init the plugin data */
38015 INIT_FUNC(mod_ssi_init) {
38019 p = calloc(1, sizeof(*p));
38022 p->timefmt = buffer_init();
38023 p->stat_fn = buffer_init();
38026 p->ssi_vars = array_init();
38027 p->ssi_cgi_env = array_init();
38033 @@ -55,21 +56,21 @@
38034 FREE_FUNC(mod_ssi_free) {
38035 plugin_data *p = p_d;
38039 if (!p) return HANDLER_GO_ON;
38042 if (p->config_storage) {
38044 for (i = 0; i < srv->config_context->used; i++) {
38045 plugin_config *s = p->config_storage[i];
38048 array_free(s->ssi_extension);
38053 free(p->config_storage);
38057 array_free(p->ssi_vars);
38058 array_free(p->ssi_cgi_env);
38062 buffer_free(p->timefmt);
38063 buffer_free(p->stat_fn);
38069 return HANDLER_GO_ON;
38072 @@ -92,36 +93,36 @@
38073 const char *errptr;
38077 - config_values_t cv[] = {
38079 + config_values_t cv[] = {
38080 { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
38081 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
38085 if (!p) return HANDLER_ERROR;
38088 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
38091 for (i = 0; i < srv->config_context->used; i++) {
38095 s = calloc(1, sizeof(plugin_config));
38096 s->ssi_extension = array_init();
38099 cv[0].destination = s->ssi_extension;
38102 p->config_storage[i] = s;
38105 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
38106 return HANDLER_ERROR;
38112 /* allow 2 params */
38113 if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
38114 log_error_write(srv, __FILE__, __LINE__, "sds",
38118 return HANDLER_ERROR;
38120 @@ -130,52 +131,52 @@
38121 "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
38122 return HANDLER_ERROR;
38126 return HANDLER_GO_ON;
38129 int ssi_env_add(array *env, const char *key, const char *val) {
38133 if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
38134 ds = data_string_init();
38136 buffer_copy_string(ds->key, key);
38137 buffer_copy_string(ds->value, val);
38140 array_insert_unique(env, (data_unset *)ds);
38148 * the next two functions are take from fcgi.c
38153 static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
38157 for (i = 0; i < con->request.headers->used; i++) {
38161 ds = (data_string *)con->request.headers->data[i];
38164 if (ds->value->used && ds->key->used) {
38166 buffer_reset(srv->tmp_buf);
38169 /* don't forward the Authorization: Header */
38170 if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
38175 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
38176 buffer_copy_string(srv->tmp_buf, "HTTP_");
38177 srv->tmp_buf->used--;
38181 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
38182 for (j = 0; j < ds->key->used - 1; j++) {
38184 @@ -189,33 +190,33 @@
38185 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
38187 srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
38190 ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
38198 static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
38202 server_socket *srv_sock = con->srv_socket;
38206 char b2[INET6_ADDRSTRLEN + 1];
38209 #define CONST_STRING(x) \
38213 array_reset(p->ssi_cgi_env);
38216 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
38217 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
38219 - inet_ntop(srv_sock->addr.plain.sa_family,
38220 - srv_sock->addr.plain.sa_family == AF_INET6 ?
38221 + inet_ntop(srv_sock->addr.plain.sa_family,
38222 + srv_sock->addr.plain.sa_family == AF_INET6 ?
38223 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
38224 (const void *) &(srv_sock->addr.ipv4.sin_addr),
38226 @@ -224,28 +225,28 @@
38229 ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
38235 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
38237 ntohs(srv_sock->addr.ipv4.sin_port)
38242 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
38245 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
38246 inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
38249 if (con->authed_user->used) {
38250 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
38251 con->authed_user->ptr);
38255 if (con->request.content_length > 0) {
38256 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
38259 /* request.content_length < SSIZE_MAX, see request.c */
38260 ltostr(buf, con->request.content_length);
38261 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
38262 @@ -271,30 +272,30 @@
38263 if (con->request.pathinfo->used) {
38264 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
38268 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
38269 ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
38272 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
38273 ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
38274 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
38275 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
38276 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
38279 ssi_env_add_request_headers(srv, con, p);
38285 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
38286 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
38287 const char **l, size_t n) {
38288 size_t i, ssicmd = 0;
38296 - enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
38297 + enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
38298 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
38299 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
38301 @@ -310,27 +311,27 @@
38302 { "endif", SSI_ENDIF },
38303 { "else", SSI_ELSE },
38304 { "exec", SSI_EXEC },
38307 { NULL, SSI_UNSET }
38311 for (i = 0; ssicmds[i].var; i++) {
38312 if (0 == strcmp(l[1], ssicmds[i].var)) {
38313 ssicmd = ssicmds[i].type;
38322 int var = 0, enc = 0;
38323 const char *var_val = NULL;
38324 stat_cache_entry *sce = NULL;
38330 - enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
38331 + enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
38332 SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
38334 { "DATE_GMT", SSI_ECHO_DATE_GMT },
38335 @@ -339,27 +340,27 @@
38336 { "DOCUMENT_URI", SSI_ECHO_DOCUMENT_URI },
38337 { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
38338 { "USER_NAME", SSI_ECHO_USER_NAME },
38341 { NULL, SSI_ECHO_UNSET }
38348 enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
38350 { "url", SSI_ENC_URL },
38351 { "none", SSI_ENC_NONE },
38352 { "entity", SSI_ENC_ENTITY },
38355 { NULL, SSI_ENC_UNSET }
38359 for (i = 2; i < n; i += 2) {
38360 if (0 == strcmp(l[i], "var")) {
38367 for (j = 0; echovars[j].var; j++) {
38368 if (0 == strcmp(l[i+1], echovars[j].var)) {
38369 var = echovars[j].type;
38370 @@ -368,7 +369,7 @@
38372 } else if (0 == strcmp(l[i], "encoding")) {
38376 for (j = 0; encvars[j].var; j++) {
38377 if (0 == strcmp(l[i+1], encvars[j].var)) {
38378 enc = encvars[j].type;
38379 @@ -377,26 +378,26 @@
38382 log_error_write(srv, __FILE__, __LINE__, "sss",
38383 - "ssi: unknow attribute for ",
38384 + "ssi: unknow attribute for ",
38390 if (p->if_is_false) break;
38394 log_error_write(srv, __FILE__, __LINE__, "sss",
38397 l[1], "var is missing");
38401 stat_cache_get_entry(srv, con, con->physical.path, &sce);
38405 case SSI_ECHO_USER_NAME: {
38409 b = chunkqueue_get_append_buffer(con->write_queue);
38411 if (NULL == (pw = getpwuid(sce->st.st_uid))) {
38412 @@ -411,7 +412,7 @@
38414 case SSI_ECHO_LAST_MODIFIED: {
38415 time_t t = sce->st.st_mtime;
38418 b = chunkqueue_get_append_buffer(con->write_queue);
38419 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38420 buffer_copy_string(b, "(none)");
38421 @@ -422,7 +423,7 @@
38423 case SSI_ECHO_DATE_LOCAL: {
38424 time_t t = time(NULL);
38427 b = chunkqueue_get_append_buffer(con->write_queue);
38428 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
38429 buffer_copy_string(b, "(none)");
38430 @@ -433,7 +434,7 @@
38432 case SSI_ECHO_DATE_GMT: {
38433 time_t t = time(NULL);
38436 b = chunkqueue_get_append_buffer(con->write_queue);
38437 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
38438 buffer_copy_string(b, "(none)");
38439 @@ -444,7 +445,7 @@
38441 case SSI_ECHO_DOCUMENT_NAME: {
38445 b = chunkqueue_get_append_buffer(con->write_queue);
38446 if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38447 buffer_copy_string_buffer(b, con->physical.path);
38448 @@ -461,15 +462,15 @@
38451 /* check if it is a cgi-var */
38454 b = chunkqueue_get_append_buffer(con->write_queue);
38457 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
38458 buffer_copy_string_buffer(b, ds->value);
38460 buffer_copy_string(b, "(none)");
38467 @@ -481,7 +482,7 @@
38468 const char * file_path = NULL, *virt_path = NULL;
38473 for (i = 2; i < n; i += 2) {
38474 if (0 == strcmp(l[i], "file")) {
38475 file_path = l[i+1];
38476 @@ -489,28 +490,28 @@
38477 virt_path = l[i+1];
38479 log_error_write(srv, __FILE__, __LINE__, "sss",
38480 - "ssi: unknow attribute for ",
38481 + "ssi: unknow attribute for ",
38487 if (!file_path && !virt_path) {
38488 log_error_write(srv, __FILE__, __LINE__, "sss",
38491 l[1], "file or virtual are missing");
38496 if (file_path && virt_path) {
38497 log_error_write(srv, __FILE__, __LINE__, "sss",
38500 l[1], "only one of file and virtual is allowed here");
38507 if (p->if_is_false) break;
38511 /* current doc-root */
38512 if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
38513 @@ -519,46 +520,46 @@
38514 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
38517 - buffer_copy_string(srv->tmp_buf, file_path);
38518 + buffer_copy_string(srv->tmp_buf, file_path);
38519 buffer_urldecode_path(srv->tmp_buf);
38520 - buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
38521 - buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38522 + buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
38523 + buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38528 if (virt_path[0] == '/') {
38529 buffer_copy_string(p->stat_fn, virt_path);
38531 /* there is always a / */
38532 sl = strrchr(con->uri.path->ptr, '/');
38535 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
38536 buffer_append_string(p->stat_fn, virt_path);
38540 buffer_urldecode_path(p->stat_fn);
38541 buffer_path_simplify(srv->tmp_buf, p->stat_fn);
38544 /* we have an uri */
38547 buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
38548 buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
38552 if (0 == stat(p->stat_fn->ptr, &st)) {
38553 time_t t = st.st_mtime;
38558 b = chunkqueue_get_append_buffer(con->write_queue);
38561 const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
38564 off_t s = st.st_size;
38567 for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
38570 buffer_copy_off_t(b, s);
38571 buffer_append_string(b, abr[j]);
38573 @@ -579,7 +580,7 @@
38576 log_error_write(srv, __FILE__, __LINE__, "sbs",
38577 - "ssi: stating failed ",
38578 + "ssi: stating failed ",
38579 p->stat_fn, strerror(errno));
38582 @@ -593,33 +594,33 @@
38585 log_error_write(srv, __FILE__, __LINE__, "sss",
38586 - "ssi: unknow attribute for ",
38587 + "ssi: unknow attribute for ",
38593 if (p->if_is_false) break;
38600 if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
38601 ds = data_string_init();
38603 buffer_copy_string(ds->key, key);
38604 buffer_copy_string(ds->value, val);
38607 array_insert_unique(p->ssi_vars, (data_unset *)ds);
38609 log_error_write(srv, __FILE__, __LINE__, "sss",
38610 - "ssi: var and value have to be set in",
38611 + "ssi: var and value have to be set in",
38618 if (p->if_is_false) break;
38621 for (i = 2; i < n; i += 2) {
38622 if (0 == strcmp(l[i], "timefmt")) {
38623 buffer_copy_string(p->timefmt, l[i+1]);
38624 @@ -632,63 +633,65 @@
38625 log_error_write(srv, __FILE__, __LINE__, "sssss",
38626 "ssi: unknow value for attribute '",
38633 log_error_write(srv, __FILE__, __LINE__, "sss",
38634 - "ssi: unknow attribute for ",
38635 + "ssi: unknow attribute for ",
38641 if (p->if_is_false) break;
38644 b = chunkqueue_get_append_buffer(con->write_queue);
38645 buffer_copy_string(b, "<pre>");
38646 for (i = 0; i < p->ssi_vars->used; i++) {
38647 data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
38650 buffer_append_string_buffer(b, ds->key);
38651 buffer_append_string(b, ": ");
38652 buffer_append_string_buffer(b, ds->value);
38653 buffer_append_string(b, "<br />");
38657 buffer_append_string(b, "</pre>");
38664 const char *cmd = NULL;
38666 int from_exec_fds[2];
38669 for (i = 2; i < n; i += 2) {
38670 if (0 == strcmp(l[i], "cmd")) {
38673 log_error_write(srv, __FILE__, __LINE__, "sss",
38674 - "ssi: unknow attribute for ",
38675 + "ssi: unknow attribute for ",
38681 if (p->if_is_false) break;
38684 /* create a return pipe and send output to the html-page
38686 - * as exec is assumed evil it is implemented synchronously
38688 + * as exec is assumed evil it is implemented synchronously
38695 if (pipe(from_exec_fds)) {
38696 - log_error_write(srv, __FILE__, __LINE__, "ss",
38697 + log_error_write(srv, __FILE__, __LINE__, "ss",
38698 "pipe failed: ", strerror(errno));
38704 switch (pid = fork()) {
38706 @@ -698,14 +701,14 @@
38707 close(from_exec_fds[1]);
38709 close(from_exec_fds[0]);
38713 close(STDIN_FILENO);
38716 execl("/bin/sh", "sh", "-c", cmd, NULL);
38719 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
38725 @@ -718,9 +721,9 @@
38731 close(from_exec_fds[1]);
38734 /* wait for the client to end */
38735 if (-1 == waitpid(pid, &status, 0)) {
38736 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
38737 @@ -730,7 +733,7 @@
38740 if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
38741 - log_error_write(srv, __FILE__, __LINE__, "s",
38742 + log_error_write(srv, __FILE__, __LINE__, "s",
38743 "unexpected end-of-file (perhaps the ssi-exec process died)");
38746 @@ -738,10 +741,10 @@
38748 b = chunkqueue_get_append_buffer(con->write_queue);
38750 - buffer_prepare_copy(b, toread + 1);
38751 + buffer_prepare_copy(b, toread + 1);
38753 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
38754 - /* read failed */
38755 + /* read failed */
38759 @@ -755,59 +758,58 @@
38760 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
38762 close(from_exec_fds[0]);
38777 const char *expr = NULL;
38780 for (i = 2; i < n; i += 2) {
38781 if (0 == strcmp(l[i], "expr")) {
38784 log_error_write(srv, __FILE__, __LINE__, "sss",
38785 - "ssi: unknow attribute for ",
38786 + "ssi: unknow attribute for ",
38793 log_error_write(srv, __FILE__, __LINE__, "sss",
38796 l[1], "expr missing");
38801 if ((!p->if_is_false) &&
38802 - ((p->if_is_false_level == 0) ||
38803 + ((p->if_is_false_level == 0) ||
38804 (p->if_level < p->if_is_false_level))) {
38805 switch (ssi_eval_expr(srv, con, p, expr)) {
38808 - p->if_is_false = 1;
38810 + p->if_is_false = 1;
38811 p->if_is_false_level = p->if_level;
38814 - p->if_is_false = 0;
38816 + p->if_is_false = 0;
38831 if (p->if_is_false) {
38832 if ((p->if_level == p->if_is_false_level) &&
38833 (p->if_is_false_endif == 0)) {
38834 @@ -815,11 +817,11 @@
38837 p->if_is_false = 1;
38840 p->if_is_false_level = p->if_level;
38847 const char *expr = NULL;
38848 @@ -828,52 +830,52 @@
38851 log_error_write(srv, __FILE__, __LINE__, "sss",
38852 - "ssi: unknow attribute for ",
38853 + "ssi: unknow attribute for ",
38860 log_error_write(srv, __FILE__, __LINE__, "sss",
38863 l[1], "expr missing");
38871 if (p->if_level == p->if_is_false_level) {
38872 if ((p->if_is_false) &&
38873 (p->if_is_false_endif == 0)) {
38874 switch (ssi_eval_expr(srv, con, p, expr)) {
38877 - p->if_is_false = 1;
38879 + p->if_is_false = 1;
38880 p->if_is_false_level = p->if_level;
38883 - p->if_is_false = 0;
38885 + p->if_is_false = 0;
38889 - p->if_is_false = 1;
38890 + p->if_is_false = 1;
38891 p->if_is_false_level = p->if_level;
38892 p->if_is_false_endif = 1;
38906 if (p->if_level == p->if_is_false_level) {
38907 p->if_is_false = 0;
38908 p->if_is_false_endif = 0;
38914 log_error_write(srv, __FILE__, __LINE__, "ss",
38915 @@ -881,41 +883,41 @@
38926 static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
38937 /* get a stream to the file */
38940 array_reset(p->ssi_vars);
38941 array_reset(p->ssi_cgi_env);
38942 buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
38944 build_ssi_cgi_vars(srv, con, p);
38945 p->if_is_false = 0;
38948 if (-1 == stream_open(&s, con->physical.path)) {
38949 log_error_write(srv, __FILE__, __LINE__, "sb",
38950 "stream-open: ", con->physical.path);
38958 - * <!--#element attribute=value attribute=value ... -->
38960 + * <!--#element attribute=value attribute=value ... -->
38963 - * errmsg -- missing
38964 + * errmsg -- missing
38968 @@ -937,13 +939,13 @@
38985 @@ -951,118 +953,115 @@
38997 - * The current date in Greenwich Mean Time.
38999 - * The current date in the local time zone.
39001 - * The filename (excluding directories) of the document requested by the user.
39003 - * 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.
39005 - * The last modification date of the document requested by the user.
39008 + * The current date in Greenwich Mean Time.
39010 + * The current date in the local time zone.
39012 + * The filename (excluding directories) of the document requested by the user.
39014 + * 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.
39016 + * The last modification date of the document requested by the user.
39018 * Contains the owner of the file which included it.
39022 -#ifdef HAVE_PCRE_H
39023 +#ifdef HAVE_PCRE_H
39024 for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
39026 /* take everything from last offset to current match pos */
39029 if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
39032 pcre_get_substring_list(s.start, ovec, n, &l);
39033 process_ssi_stmt(srv, con, p, l, n);
39034 pcre_free_substring_list(l);
39039 case PCRE_ERROR_NOMATCH:
39040 /* copy everything/the rest */
39041 chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
39046 log_error_write(srv, __FILE__, __LINE__, "sd",
39047 "execution error while matching: ", n);
39059 con->file_started = 1;
39060 con->file_finished = 1;
39063 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
39066 /* reset physical.path */
39067 buffer_reset(con->physical.path);
39073 -#define PATCH(x) \
39074 - p->conf.x = s->x;
39075 static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
39077 plugin_config *s = p->config_storage[0];
39079 - PATCH(ssi_extension);
39082 + PATCH_OPTION(ssi_extension);
39084 /* skip the first, the global context */
39085 for (i = 1; i < srv->config_context->used; i++) {
39086 data_config *dc = (data_config *)srv->config_context->data[i];
39087 s = p->config_storage[i];
39090 /* condition didn't match */
39091 if (!config_check_cond(srv, con, dc)) continue;
39095 for (j = 0; j < dc->value->used; j++) {
39096 data_unset *du = dc->value->data[j];
39099 if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
39100 - PATCH(ssi_extension);
39101 + PATCH_OPTION(ssi_extension);
39111 URIHANDLER_FUNC(mod_ssi_physical_path) {
39112 plugin_data *p = p_d;
39116 if (con->physical.path->used == 0) return HANDLER_GO_ON;
39119 mod_ssi_patch_connection(srv, con, p);
39122 for (k = 0; k < p->conf.ssi_extension->used; k++) {
39123 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
39126 if (ds->value->used == 0) continue;
39129 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
39130 /* handle ssi-request */
39133 if (mod_ssi_handle_request(srv, con, p)) {
39135 con->http_status = 500;
39139 return HANDLER_FINISHED;
39145 return HANDLER_GO_ON;
39147 @@ -1072,13 +1071,13 @@
39148 int mod_ssi_plugin_init(plugin *p) {
39149 p->version = LIGHTTPD_VERSION_ID;
39150 p->name = buffer_init_string("ssi");
39153 p->init = mod_ssi_init;
39154 p->handle_subrequest_start = mod_ssi_physical_path;
39155 p->set_defaults = mod_ssi_set_defaults;
39156 p->cleanup = mod_ssi_free;
39164 --- ../lighttpd-1.4.11/src/mod_ssi.h 2005-08-11 01:26:39.000000000 +0300
39165 +++ lighttpd-1.4.12/src/mod_ssi.h 2006-07-16 00:26:04.000000000 +0300
39166 @@ -19,23 +19,23 @@
39171 -#ifdef HAVE_PCRE_H
39173 +#ifdef HAVE_PCRE_H
39185 array *ssi_cgi_env;
39188 int if_level, if_is_false_level, if_is_false, if_is_false_endif;
39191 plugin_config **config_storage;
39193 - plugin_config conf;
39195 + plugin_config conf;
39198 int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
39199 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c 2005-08-11 01:26:48.000000000 +0300
39200 +++ lighttpd-1.4.12/src/mod_ssi_expr.c 2006-07-16 00:26:04.000000000 +0300
39213 @@ -21,15 +21,15 @@
39215 ssi_val_t *ssi_val_init() {
39219 s = calloc(1, sizeof(*s));
39225 void ssi_val_free(ssi_val_t *s) {
39226 if (s->str) buffer_free(s->str);
39232 @@ -45,175 +45,175 @@
39233 ssi_tokenizer_t *t, int *token_id, buffer *token) {
39240 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
39241 char c = t->input[t->offset];
39255 buffer_copy_string(token, "(=)");
39260 if (t->input[t->offset + 1] == '=') {
39268 buffer_copy_string(token, "(>=)");
39277 buffer_copy_string(token, "(>)");
39283 if (t->input[t->offset + 1] == '=') {
39291 buffer_copy_string(token, "(<=)");
39300 buffer_copy_string(token, "(<)");
39308 if (t->input[t->offset + 1] == '=') {
39316 buffer_copy_string(token, "(!=)");
39325 buffer_copy_string(token, "(!)");
39331 if (t->input[t->offset + 1] == '&') {
39339 buffer_copy_string(token, "(&&)");
39341 - log_error_write(srv, __FILE__, __LINE__, "sds",
39342 - "pos:", t->line_pos,
39343 + log_error_write(srv, __FILE__, __LINE__, "sds",
39344 + "pos:", t->line_pos,
39345 "missing second &");
39352 if (t->input[t->offset + 1] == '|') {
39360 buffer_copy_string(token, "(||)");
39362 - log_error_write(srv, __FILE__, __LINE__, "sds",
39363 - "pos:", t->line_pos,
39364 + log_error_write(srv, __FILE__, __LINE__, "sds",
39365 + "pos:", t->line_pos,
39366 "missing second |");
39380 /* search for the terminating " */
39381 for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++);
39384 if (t->input[t->offset + i]) {
39388 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39391 t->offset += i + 1;
39392 t->line_pos += i + 1;
39396 - log_error_write(srv, __FILE__, __LINE__, "sds",
39397 - "pos:", t->line_pos,
39399 + log_error_write(srv, __FILE__, __LINE__, "sds",
39400 + "pos:", t->line_pos,
39401 "missing closing quote");
39417 buffer_copy_string(token, "(");
39427 buffer_copy_string(token, ")");
39430 if (t->input[t->offset + 1] == '{') {
39431 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++);
39434 if (t->input[t->offset + i] != '}') {
39435 - log_error_write(srv, __FILE__, __LINE__, "sds",
39436 - "pos:", t->line_pos,
39437 + log_error_write(srv, __FILE__, __LINE__, "sds",
39438 + "pos:", t->line_pos,
39439 "missing closing quote");
39446 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
39448 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_'; i++);
39451 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
39458 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
39459 buffer_copy_string_buffer(token, ds->value);
39460 } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
39461 @@ -221,16 +221,16 @@
39463 buffer_copy_string(token, "");
39473 for (i = 0; isgraph(t->input[t->offset + i]); i++) {
39474 char d = t->input[t->offset + i];
39481 @@ -244,25 +244,25 @@
39490 buffer_copy_string_len(token, t->input + t->offset, i);
39507 } else if (t->offset < t->size) {
39508 - log_error_write(srv, __FILE__, __LINE__, "sds",
39509 - "pos:", t->line_pos,
39510 + log_error_write(srv, __FILE__, __LINE__, "sds",
39511 + "pos:", t->line_pos,
39515 @@ -275,50 +275,50 @@
39523 t.size = strlen(expr);
39536 /* default context */
39539 pParser = ssiexprparserAlloc( malloc );
39540 token = buffer_init();
39541 while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
39542 ssiexprparser(pParser, token_id, token, &context);
39545 token = buffer_init();
39547 ssiexprparser(pParser, 0, token, &context);
39548 ssiexprparserFree(pParser, free );
39551 buffer_free(token);
39555 - log_error_write(srv, __FILE__, __LINE__, "s",
39556 + log_error_write(srv, __FILE__, __LINE__, "s",
39557 "expr parser failed");
39562 if (context.ok == 0) {
39563 - log_error_write(srv, __FILE__, __LINE__, "sds",
39564 - "pos:", t.line_pos,
39565 + log_error_write(srv, __FILE__, __LINE__, "sds",
39566 + "pos:", t.line_pos,
39567 "parser failed somehow near here");
39571 - log_error_write(srv, __FILE__, __LINE__, "ssd",
39572 + log_error_write(srv, __FILE__, __LINE__, "ssd",
39578 return context.val.bo;
39580 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h 2005-08-11 01:26:48.000000000 +0300
39581 +++ lighttpd-1.4.12/src/mod_ssi_expr.h 2006-07-16 00:26:04.000000000 +0300
39585 enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
39602 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
39603 +++ lighttpd-1.4.12/src/mod_ssi_exprparser.c 2006-07-17 22:02:23.000000000 +0300
39604 @@ -18,10 +18,10 @@
39605 /* Next is all token values, in a form suitable for use by makeheaders.
39606 ** This section will be null unless lemon is run with the -m switch.
39610 ** These constants (all generated automatically by the parser generator)
39611 ** specify the various kinds of tokens (terminals) that the parser
39615 ** Each symbol here is a terminal symbol in the grammar.
39618 ** and nonterminals. "int" is used otherwise.
39619 ** YYNOCODE is a number of type YYCODETYPE which corresponds
39620 ** to no legal terminal or nonterminal number. This
39621 -** number is used to fill in empty slots of the hash
39622 +** number is used to fill in empty slots of the hash
39624 ** YYFALLBACK If defined, this indicates that one or more tokens
39625 ** have fall-back values which should be used if the
39627 ** and nonterminal numbers. "unsigned char" is
39628 ** used if there are fewer than 250 rules and
39629 ** states combined. "int" is used otherwise.
39630 -** ssiexprparserTOKENTYPE is the data type used for minor tokens given
39631 +** ssiexprparserTOKENTYPE is the data type used for minor tokens given
39632 ** directly to the parser from the tokenizer.
39633 ** YYMINORTYPE is the data type used for all minor tokens.
39634 ** This is typically a union of many types, one of
39636 /* Next are that tables used to determine what action to take based on the
39637 ** current state and lookahead token. These tables are used to implement
39638 ** functions that take a state number and lookahead value and return an
39639 -** action integer.
39640 +** action integer.
39642 ** Suppose the action integer is N. Then the action is determined as
39644 @@ -116,7 +116,7 @@
39645 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
39646 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
39647 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
39648 -** and that yy_default[S] should be used instead.
39649 +** and that yy_default[S] should be used instead.
39651 ** The formula above is for computing the action when the lookahead is
39652 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
39653 @@ -168,7 +168,7 @@
39655 /* The next table maps tokens into fallback tokens. If a construct
39656 ** like the following:
39659 ** %fallback ID X Y Z.
39661 ** appears in the grammer, then ID becomes a fallback token for X, Y,
39662 @@ -219,10 +219,10 @@
39663 #endif /* NDEBUG */
39668 ** Turn parser tracing on by giving a stream to which to write the trace
39669 ** and a prompt to preface each trace message. Tracing is turned off
39670 -** by making either argument NULL
39671 +** by making either argument NULL
39675 @@ -247,7 +247,7 @@
39677 /* For tracing shifts, the names of all terminals and nonterminals
39678 ** are required. The following table supplies these names */
39679 -static const char *yyTokenName[] = {
39680 +static const char *yyTokenName[] = {
39681 "$", "AND", "OR", "EQ",
39682 "NE", "GT", "GE", "LT",
39683 "LE", "NOT", "LPARAN", "RPARAN",
39684 @@ -295,7 +295,7 @@
39690 ** This function allocates a new parser.
39691 ** The only argument is a pointer to a function which works like
39693 @@ -326,7 +326,7 @@
39694 /* Here is inserted the actions which take place when a
39695 ** terminal or non-terminal is destroyed. This can happen
39696 ** when the symbol is popped from the stack during a
39697 - ** reduce or during error processing or when a parser is
39698 + ** reduce or during error processing or when a parser is
39699 ** being destroyed before it is finished parsing.
39701 ** Note: during a reduce, the only symbols destroyed are those
39702 @@ -379,7 +379,7 @@
39708 ** Deallocate and destroy a parser. Destructors are all called for
39709 ** all stack elements before shutting the parser down.
39711 @@ -415,7 +415,7 @@
39714 int stateno = pParser->yystack[pParser->yyidx].stateno;
39717 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
39718 i = yy_shift_ofst[stateno];
39719 if( i==YY_SHIFT_USE_DFLT ){
39720 @@ -459,7 +459,7 @@
39723 int stateno = pParser->yystack[pParser->yyidx].stateno;
39726 i = yy_reduce_ofst[stateno];
39727 if( i==YY_REDUCE_USE_DFLT ){
39728 return yy_default[stateno];
39729 @@ -559,7 +559,7 @@
39730 ssiexprparserARG_FETCH;
39731 yymsp = &yypParser->yystack[yypParser->yyidx];
39733 - if( yyTraceFILE && yyruleno>=0
39734 + if( yyTraceFILE && yyruleno>=0
39735 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
39736 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
39737 yyRuleName[yyruleno]);
39738 @@ -872,7 +872,7 @@
39739 #ifdef YYERRORSYMBOL
39740 /* A syntax error has occurred.
39741 ** The response to an error depends upon whether or not the
39742 - ** grammar defines an error token "ERROR".
39743 + ** grammar defines an error token "ERROR".
39745 ** This is what we do if the grammar does define ERROR:
39747 --- ../lighttpd-1.4.11/src/mod_staticfile.c 2006-02-15 14:31:14.000000000 +0200
39748 +++ lighttpd-1.4.12/src/mod_staticfile.c 2006-07-16 00:26:03.000000000 +0300
39750 #include "http_chunk.h"
39751 #include "response.h"
39753 +#include "sys-files.h"
39754 +#include "sys-strings.h"
39756 * this is a staticfile for a lighttpd plugin
39762 @@ -29,48 +31,48 @@
39771 plugin_config **config_storage;
39773 - plugin_config conf;
39775 + plugin_config conf;
39778 /* init the plugin data */
39779 INIT_FUNC(mod_staticfile_init) {
39783 p = calloc(1, sizeof(*p));
39786 p->range_buf = buffer_init();
39792 -/* detroy the plugin data */
39793 +/* destroy the plugin data */
39794 FREE_FUNC(mod_staticfile_free) {
39795 plugin_data *p = p_d;
39800 if (!p) return HANDLER_GO_ON;
39803 if (p->config_storage) {
39805 for (i = 0; i < srv->config_context->used; i++) {
39806 plugin_config *s = p->config_storage[i];
39809 array_free(s->exclude_ext);
39814 free(p->config_storage);
39816 buffer_free(p->range_buf);
39822 return HANDLER_GO_ON;
39825 @@ -79,63 +81,60 @@
39826 SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
39827 plugin_data *p = p_d;
39830 - config_values_t cv[] = {
39832 + config_values_t cv[] = {
39833 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
39834 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39838 if (!p) return HANDLER_ERROR;
39841 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39844 for (i = 0; i < srv->config_context->used; i++) {
39848 s = calloc(1, sizeof(plugin_config));
39849 s->exclude_ext = array_init();
39852 cv[0].destination = s->exclude_ext;
39855 p->config_storage[i] = s;
39858 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39859 return HANDLER_ERROR;
39864 return HANDLER_GO_ON;
39867 -#define PATCH(x) \
39868 - p->conf.x = s->x;
39869 static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
39871 plugin_config *s = p->config_storage[0];
39873 - PATCH(exclude_ext);
39876 + PATCH_OPTION(exclude_ext);
39878 /* skip the first, the global context */
39879 for (i = 1; i < srv->config_context->used; i++) {
39880 data_config *dc = (data_config *)srv->config_context->data[i];
39881 s = p->config_storage[i];
39884 /* condition didn't match */
39885 if (!config_check_cond(srv, con, dc)) continue;
39889 for (j = 0; j < dc->value->used; j++) {
39890 data_unset *du = dc->value->data[j];
39893 if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
39894 - PATCH(exclude_ext);
39895 + PATCH_OPTION(exclude_ext);
39905 static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
39907 @@ -146,69 +145,69 @@
39909 stat_cache_entry *sce = NULL;
39910 buffer *content_type = NULL;
39913 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39919 end = sce->st.st_size - 1;
39922 con->response.content_length = 0;
39925 if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
39926 content_type = ds->value;
39930 for (s = con->request.http_range, error = 0;
39931 !error && *s && NULL != (minus = strchr(s, '-')); ) {
39940 le = strtoll(s, &err, 10);
39944 /* RFC 2616 - 14.35.1 */
39947 con->http_status = 416;
39949 } else if (*err == '\0') {
39954 end = sce->st.st_size - 1;
39955 start = sce->st.st_size + le;
39956 } else if (*err == ',') {
39961 end = sce->st.st_size - 1;
39962 start = sce->st.st_size + le;
39968 } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
39972 la = strtoll(s, &err, 10);
39975 if (err == minus) {
39979 if (*(err + 1) == '\0') {
39983 end = sce->st.st_size - 1;
39987 } else if (*(err + 1) == ',') {
39992 end = sce->st.st_size - 1;
39995 @@ -220,64 +219,64 @@
39998 /* <start>-<stop> */
40001 la = strtoll(s, &err, 10);
40004 if (err == minus) {
40005 le = strtoll(minus+1, &err, 10);
40008 /* RFC 2616 - 14.35.1 */
40014 if (*err == '\0') {
40021 } else if (*err == ',') {
40044 if (start < 0) start = 0;
40047 /* RFC 2616 - 14.35.1 */
40048 if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
40051 if (start > sce->st.st_size - 1) {
40055 con->http_status = 416;
40062 /* write boundary-header */
40066 b = chunkqueue_get_append_buffer(con->write_queue);
40069 buffer_copy_string(b, "\r\n--");
40070 buffer_append_string(b, boundary);
40073 /* write Content-Range */
40074 buffer_append_string(b, "\r\nContent-Range: bytes ");
40075 buffer_append_off_t(b, start);
40076 @@ -285,54 +284,54 @@
40077 buffer_append_off_t(b, end);
40078 buffer_append_string(b, "/");
40079 buffer_append_off_t(b, sce->st.st_size);
40082 buffer_append_string(b, "\r\nContent-Type: ");
40083 buffer_append_string_buffer(b, content_type);
40086 /* write END-OF-HEADER */
40087 buffer_append_string(b, "\r\n\r\n");
40090 con->response.content_length += b->used - 1;
40096 chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
40097 con->response.content_length += end - start + 1;
40102 /* something went wrong */
40103 if (error) return -1;
40107 /* add boundary end */
40111 b = chunkqueue_get_append_buffer(con->write_queue);
40114 buffer_copy_string_len(b, "\r\n--", 4);
40115 buffer_append_string(b, boundary);
40116 buffer_append_string_len(b, "--\r\n", 4);
40119 con->response.content_length += b->used - 1;
40122 /* set header-fields */
40125 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
40126 buffer_append_string(p->range_buf, boundary);
40129 /* overwrite content-type */
40130 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
40132 /* add Content-Range-header */
40135 buffer_copy_string(p->range_buf, "bytes ");
40136 buffer_append_off_t(p->range_buf, start);
40137 buffer_append_string(p->range_buf, "-");
40138 buffer_append_off_t(p->range_buf, end);
40139 buffer_append_string(p->range_buf, "/");
40140 buffer_append_off_t(p->range_buf, sce->st.st_size);
40143 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
40146 @@ -347,12 +346,12 @@
40147 stat_cache_entry *sce = NULL;
40152 /* someone else has done a decision for us */
40153 if (con->http_status != 0) return HANDLER_GO_ON;
40154 if (con->uri.path->used == 0) return HANDLER_GO_ON;
40155 if (con->physical.path->used == 0) return HANDLER_GO_ON;
40158 /* someone else has handled this request */
40159 if (con->mode != DIRECT) return HANDLER_GO_ON;
40161 @@ -365,52 +364,52 @@
40163 return HANDLER_GO_ON;
40167 mod_staticfile_patch_connection(srv, con, p);
40170 s_len = con->uri.path->used - 1;
40173 /* ignore certain extensions */
40174 for (k = 0; k < p->conf.exclude_ext->used; k++) {
40175 - ds = (data_string *)p->conf.exclude_ext->data[k];
40177 + ds = (data_string *)p->conf.exclude_ext->data[k];
40179 if (ds->value->used == 0) continue;
40181 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
40182 return HANDLER_GO_ON;
40188 if (con->conf.log_request_handling) {
40189 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
40193 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
40194 con->http_status = 403;
40197 log_error_write(srv, __FILE__, __LINE__, "sbsb",
40198 "not a regular file:", con->uri.path,
40199 "->", con->physical.path);
40202 return HANDLER_FINISHED;
40205 - /* we only handline regular files */
40207 + /* we only handle regular files */
40208 if (!S_ISREG(sce->st.st_mode)) {
40209 con->http_status = 404;
40212 if (con->conf.log_file_not_found) {
40213 log_error_write(srv, __FILE__, __LINE__, "sbsb",
40214 "not a regular file:", con->uri.path,
40219 return HANDLER_FINISHED;
40222 - /* mod_compress might set several data directly, don't overwrite them */
40224 + /* mod_compress might set several parameters directly; don't overwrite them */
40226 /* set response content-type, if not set already */
40228 if (NULL == array_get_element(con->response.headers, "Content-Type")) {
40229 @@ -420,15 +419,15 @@
40230 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
40235 if (NULL == array_get_element(con->response.headers, "ETag")) {
40236 /* generate e-tag */
40237 etag_mutate(con->physical.etag, sce->etag);
40240 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
40242 response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
40245 /* prepare header */
40246 if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
40247 mtime = strftime_cache_get(srv, sce->st.st_mtime);
40248 @@ -444,34 +443,34 @@
40249 /* check if we have a conditional GET */
40251 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
40252 - /* if the value is the same as our ETag, we do a Range-request,
40253 + /* if the value is the same as our ETag, we do a Range-request,
40254 * otherwise a full 200 */
40256 if (!buffer_is_equal(ds->value, con->physical.etag)) {
40257 do_range_request = 0;
40262 if (do_range_request) {
40263 /* content prepared, I'm done */
40264 con->file_finished = 1;
40267 if (0 == http_response_parse_range(srv, con, p)) {
40268 con->http_status = 206;
40270 return HANDLER_FINISHED;
40275 /* if we are still here, prepare body */
40277 - /* we add it here for all requests
40278 - * the HEAD request will drop it afterwards again
40280 + /* we add it here for all requests
40281 + * the HEAD request will drop it afterwards again
40283 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
40286 con->file_finished = 1;
40289 return HANDLER_FINISHED;
40292 @@ -480,13 +479,13 @@
40293 int mod_staticfile_plugin_init(plugin *p) {
40294 p->version = LIGHTTPD_VERSION_ID;
40295 p->name = buffer_init_string("staticfile");
40298 p->init = mod_staticfile_init;
40299 p->handle_subrequest_start = mod_staticfile_subrequest;
40300 p->set_defaults = mod_staticfile_set_defaults;
40301 p->cleanup = mod_staticfile_free;
40309 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
40310 +++ lighttpd-1.4.12/src/mod_status.c 2006-07-19 20:02:55.000000000 +0300
40313 #include <stdlib.h>
40314 #include <string.h>
40315 -#include <unistd.h>
40320 #include "response.h"
40321 #include "connections.h"
40323 +#include "status_counter.h"
40325 #include "plugin.h"
40327 @@ -29,114 +29,114 @@
40333 double traffic_out;
40337 double mod_5s_traffic_out[5];
40338 double mod_5s_requests[5];
40342 double rel_traffic_out;
40343 double rel_requests;
40346 double abs_traffic_out;
40347 double abs_requests;
40350 double bytes_written;
40353 buffer *module_list;
40356 plugin_config **config_storage;
40358 - plugin_config conf;
40360 + plugin_config conf;
40363 INIT_FUNC(mod_status_init) {
40368 p = calloc(1, sizeof(*p));
40371 p->traffic_out = p->requests = 0;
40372 p->rel_traffic_out = p->rel_requests = 0;
40373 p->abs_traffic_out = p->abs_requests = 0;
40374 p->bytes_written = 0;
40375 p->module_list = buffer_init();
40378 for (i = 0; i < 5; i++) {
40379 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
40386 FREE_FUNC(mod_status_free) {
40387 plugin_data *p = p_d;
40392 if (!p) return HANDLER_GO_ON;
40395 buffer_free(p->module_list);
40398 if (p->config_storage) {
40400 for (i = 0; i < srv->config_context->used; i++) {
40401 plugin_config *s = p->config_storage[i];
40404 buffer_free(s->status_url);
40405 buffer_free(s->statistics_url);
40406 buffer_free(s->config_url);
40411 free(p->config_storage);
40420 return HANDLER_GO_ON;
40423 SETDEFAULTS_FUNC(mod_status_set_defaults) {
40424 plugin_data *p = p_d;
40427 - config_values_t cv[] = {
40429 + config_values_t cv[] = {
40430 { "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40431 { "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40432 { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
40433 { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
40434 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
40438 if (!p) return HANDLER_ERROR;
40441 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
40444 for (i = 0; i < srv->config_context->used; i++) {
40448 s = calloc(1, sizeof(plugin_config));
40449 s->config_url = buffer_init();
40450 s->status_url = buffer_init();
40452 s->statistics_url = buffer_init();
40455 cv[0].destination = s->status_url;
40456 cv[1].destination = s->config_url;
40457 cv[2].destination = &(s->sort);
40458 cv[3].destination = s->statistics_url;
40461 p->config_storage[i] = s;
40464 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
40465 return HANDLER_ERROR;
40470 return HANDLER_GO_ON;
40473 @@ -151,7 +151,7 @@
40474 buffer_append_string(b, value);
40475 BUFFER_APPEND_STRING_CONST(b, "</td>\n");
40476 BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
40482 @@ -161,13 +161,13 @@
40483 buffer_append_string(b, key);
40484 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40485 BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
40491 static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
40492 plugin_data *p = p_d;
40495 if (p->conf.sort) {
40496 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
40497 buffer_append_string(b, key);
40498 @@ -177,13 +177,13 @@
40499 buffer_append_string(b, key);
40500 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
40507 static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
40511 if (*avg > size) { *avg /= size; *multiplier = 'k'; }
40512 if (*avg > size) { *avg /= size; *multiplier = 'M'; }
40513 if (*avg > size) { *avg /= size; *multiplier = 'G'; }
40514 @@ -202,21 +202,21 @@
40517 char multiplier = '\0';
40523 int days, hours, mins, seconds;
40526 b = chunkqueue_get_append_buffer(con->write_queue);
40528 - BUFFER_COPY_STRING_CONST(b,
40529 + BUFFER_COPY_STRING_CONST(b,
40530 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40531 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40532 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40533 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
40535 " <title>Status</title>\n");
40538 BUFFER_APPEND_STRING_CONST(b,
40539 " <style type=\"text/css\">\n"
40540 " table.status { border: black solid thin; }\n"
40541 @@ -226,14 +226,14 @@
40542 " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
40543 " span.sortarrow { color: white; text-decoration: none; }\n"
40547 if (p->conf.sort) {
40548 BUFFER_APPEND_STRING_CONST(b,
40549 "<script type=\"text/javascript\">\n"
40551 "var sort_column;\n"
40552 "var prev_span = null;\n");
40555 BUFFER_APPEND_STRING_CONST(b,
40556 "function get_inner_text(el) {\n"
40557 " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
40558 @@ -251,7 +251,7 @@
40564 BUFFER_APPEND_STRING_CONST(b,
40565 "function sortfn(a,b) {\n"
40566 " var at = get_inner_text(a.cells[sort_column]);\n"
40567 @@ -266,7 +266,7 @@
40568 " else return 1;\n"
40573 BUFFER_APPEND_STRING_CONST(b,
40574 "function resort(lnk) {\n"
40575 " var span = lnk.childNodes[1];\n"
40576 @@ -276,7 +276,7 @@
40577 " rows[j-1] = table.rows[j];\n"
40578 " sort_column = lnk.parentNode.cellIndex;\n"
40579 " rows.sort(sortfn);\n");
40582 BUFFER_APPEND_STRING_CONST(b,
40583 " if (prev_span != null) prev_span.innerHTML = '';\n"
40584 " if (span.getAttribute('sortdir')=='down') {\n"
40585 @@ -294,175 +294,175 @@
40590 - BUFFER_APPEND_STRING_CONST(b,
40592 + BUFFER_APPEND_STRING_CONST(b,
40601 /* connection listing */
40602 BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
40604 - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
40605 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
40607 + BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
40608 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
40609 buffer_append_string_buffer(b, con->uri.authority);
40610 - BUFFER_APPEND_STRING_CONST(b, " (");
40611 + BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
40612 buffer_append_string_buffer(b, con->server_name);
40613 - BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
40614 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
40616 + BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
40617 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
40619 ts = srv->cur_ts - srv->startup_ts;
40622 days = ts / (60 * 60 * 24);
40623 ts %= (60 * 60 * 24);
40626 hours = ts / (60 * 60);
40638 buffer_append_long(b, days);
40639 BUFFER_APPEND_STRING_CONST(b, " days ");
40644 buffer_append_long(b, hours);
40645 BUFFER_APPEND_STRING_CONST(b, " hours ");
40650 buffer_append_long(b, mins);
40651 BUFFER_APPEND_STRING_CONST(b, " min ");
40655 buffer_append_long(b, seconds);
40656 BUFFER_APPEND_STRING_CONST(b, " s");
40659 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40660 BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
40663 ts = srv->startup_ts;
40665 - strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
40667 + strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
40668 buffer_append_string(b, buf);
40669 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40674 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
40676 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40678 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
40679 avg = p->abs_requests;
40681 mod_status_get_multiplier(&avg, &multiplier, 1000);
40684 buffer_append_long(b, avg);
40685 - BUFFER_APPEND_STRING_CONST(b, " ");
40686 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
40687 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40688 - BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
40690 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40691 + BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
40693 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
40694 avg = p->abs_traffic_out;
40696 mod_status_get_multiplier(&avg, &multiplier, 1024);
40698 sprintf(buf, "%.2f", avg);
40699 buffer_append_string(b, buf);
40700 - BUFFER_APPEND_STRING_CONST(b, " ");
40701 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_mult\">");
40702 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40703 - BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
40704 + BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
40708 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
40710 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40712 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
40713 avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
40715 mod_status_get_multiplier(&avg, &multiplier, 1000);
40717 buffer_append_long(b, avg);
40718 - BUFFER_APPEND_STRING_CONST(b, " ");
40719 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
40720 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40721 - BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40723 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40724 + BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40726 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
40727 avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
40729 mod_status_get_multiplier(&avg, &multiplier, 1024);
40731 sprintf(buf, "%.2f", avg);
40732 buffer_append_string(b, buf);
40733 - BUFFER_APPEND_STRING_CONST(b, " ");
40734 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
40735 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40736 - BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40737 + BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40743 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
40744 for (j = 0, avg = 0; j < 5; j++) {
40745 avg += p->mod_5s_requests[j];
40751 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40753 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
40755 mod_status_get_multiplier(&avg, &multiplier, 1000);
40757 buffer_append_long(b, avg);
40758 - BUFFER_APPEND_STRING_CONST(b, " ");
40759 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
40760 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40762 - BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40765 + BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40767 for (j = 0, avg = 0; j < 5; j++) {
40768 avg += p->mod_5s_traffic_out[j];
40774 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40776 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
40778 mod_status_get_multiplier(&avg, &multiplier, 1024);
40780 sprintf(buf, "%.2f", avg);
40781 buffer_append_string(b, buf);
40782 - BUFFER_APPEND_STRING_CONST(b, " ");
40783 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
40784 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40785 - BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40787 + BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40789 BUFFER_APPEND_STRING_CONST(b, "</table>\n");
40794 BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
40795 BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
40796 BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
40797 BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n");
40798 BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
40800 - BUFFER_APPEND_STRING_CONST(b, "<b>");
40802 + BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
40803 buffer_append_long(b, srv->conns->used);
40804 - BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
40806 + BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
40808 for (j = 0; j < srv->conns->used; j++) {
40809 connection *c = srv->conns->ptr[j];
40810 const char *state = connection_get_short_state(c->state);
40813 buffer_append_string_len(b, state, 1);
40816 if (((j + 1) % 50) == 0) {
40817 BUFFER_APPEND_STRING_CONST(b, "\n");
40822 BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
40824 - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
40826 + BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
40827 BUFFER_APPEND_STRING_CONST(b, "<tr>");
40828 mod_status_header_append_sort(b, p_d, "Client IP");
40829 mod_status_header_append_sort(b, p_d, "Read");
40830 @@ -473,16 +473,16 @@
40831 mod_status_header_append_sort(b, p_d, "URI");
40832 mod_status_header_append_sort(b, p_d, "File");
40833 BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
40836 for (j = 0; j < srv->conns->used; j++) {
40837 connection *c = srv->conns->ptr[j];
40839 - BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
40842 + BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
40844 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
40846 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40849 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
40851 if (con->request.content_length) {
40852 buffer_append_long(b, c->request_content_queue->bytes_in);
40853 BUFFER_APPEND_STRING_CONST(b, "/");
40854 @@ -490,55 +490,55 @@
40856 BUFFER_APPEND_STRING_CONST(b, "0/0");
40859 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40862 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
40864 buffer_append_off_t(b, chunkqueue_written(c->write_queue));
40865 BUFFER_APPEND_STRING_CONST(b, "/");
40866 buffer_append_off_t(b, chunkqueue_length(c->write_queue));
40868 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40871 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
40873 buffer_append_string(b, connection_get_state(c->state));
40875 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40878 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
40880 buffer_append_long(b, srv->cur_ts - c->request_start);
40882 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40885 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
40887 if (buffer_is_empty(c->server_name)) {
40888 buffer_append_string_buffer(b, c->uri.authority);
40891 buffer_append_string_buffer(b, c->server_name);
40894 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40897 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
40899 if (!buffer_is_empty(c->uri.path)) {
40900 buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
40903 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40906 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
40908 buffer_append_string_buffer(b, c->physical.path);
40911 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40915 - BUFFER_APPEND_STRING_CONST(b,
40918 + BUFFER_APPEND_STRING_CONST(b,
40922 - BUFFER_APPEND_STRING_CONST(b,
40925 + BUFFER_APPEND_STRING_CONST(b,
40931 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40937 @@ -548,7 +548,7 @@
40943 b = chunkqueue_get_append_buffer(con->write_queue);
40945 /* output total number of requests */
40946 @@ -556,19 +556,19 @@
40947 avg = p->abs_requests;
40948 buffer_append_long(b, avg);
40949 BUFFER_APPEND_STRING_CONST(b, "\n");
40952 /* output total traffic out in kbytes */
40953 BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
40954 avg = p->abs_traffic_out / 1024;
40955 buffer_append_long(b, avg);
40956 BUFFER_APPEND_STRING_CONST(b, "\n");
40959 /* output uptime */
40960 BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
40961 ts = srv->cur_ts - srv->startup_ts;
40962 buffer_append_long(b, ts);
40963 BUFFER_APPEND_STRING_CONST(b, "\n");
40966 /* output busy servers */
40967 BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
40968 buffer_append_long(b, srv->conns->used);
40969 @@ -577,7 +577,7 @@
40970 /* set text/plain output */
40972 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40978 @@ -585,16 +585,16 @@
40979 plugin_data *p = p_d;
40980 buffer *b, *m = p->module_list;
40982 - array *st = srv->status;
40983 + array *st = status_counter_get_array();
40985 if (0 == st->used) {
40986 /* we have nothing to send */
40987 con->http_status = 204;
40988 con->file_finished = 1;
40991 return HANDLER_FINISHED;
40995 b = chunkqueue_get_append_buffer(con->write_queue);
40997 for (i = 0; i < st->used; i++) {
40998 @@ -605,27 +605,27 @@
40999 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
41000 buffer_append_string(b, "\n");
41004 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
41007 con->http_status = 200;
41008 con->file_finished = 1;
41011 return HANDLER_FINISHED;
41015 static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
41018 if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
41019 mod_status_handle_server_status_text(srv, con, p_d);
41021 mod_status_handle_server_status_html(srv, con, p_d);
41025 con->http_status = 200;
41026 con->file_finished = 1;
41029 return HANDLER_FINISHED;
41032 @@ -634,9 +634,9 @@
41033 plugin_data *p = p_d;
41034 buffer *b, *m = p->module_list;
41037 - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
41040 + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
41042 /* - poll is most reliable
41043 * - select works everywhere
41044 * - linux-* are experimental
41045 @@ -661,10 +661,10 @@
41047 { FDEVENT_HANDLER_UNSET, NULL }
41051 b = chunkqueue_get_append_buffer(con->write_queue);
41053 - BUFFER_COPY_STRING_CONST(b,
41055 + BUFFER_COPY_STRING_CONST(b,
41056 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
41057 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
41058 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
41059 @@ -675,7 +675,7 @@
41061 " <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
41062 " <table border=\"1\">\n");
41065 mod_status_header_append(b, "Server-Features");
41067 mod_status_row_append(b, "RegEx Conditionals", "enabled");
41068 @@ -683,21 +683,21 @@
41069 mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
41071 mod_status_header_append(b, "Network Engine");
41074 for (i = 0; event_handlers[i].name; i++) {
41075 if (event_handlers[i].et == srv->event_handler) {
41076 mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
41082 mod_status_header_append(b, "Config-File-Settings");
41085 for (i = 0; i < srv->plugins.used; i++) {
41086 plugin **ps = srv->plugins.ptr;
41089 plugin *pl = ps[i];
41093 buffer_copy_string_buffer(m, pl->name);
41095 @@ -705,137 +705,135 @@
41096 buffer_append_string_buffer(m, pl->name);
41101 mod_status_row_append(b, "Loaded Modules", m->ptr);
41104 BUFFER_APPEND_STRING_CONST(b, " </table>\n");
41106 - BUFFER_APPEND_STRING_CONST(b,
41108 + BUFFER_APPEND_STRING_CONST(b,
41114 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
41117 con->http_status = 200;
41118 con->file_finished = 1;
41121 return HANDLER_FINISHED;
41124 -#define PATCH(x) \
41125 - p->conf.x = s->x;
41126 static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
41128 plugin_config *s = p->config_storage[0];
41130 - PATCH(status_url);
41131 - PATCH(config_url);
41133 - PATCH(statistics_url);
41136 + PATCH_OPTION(status_url);
41137 + PATCH_OPTION(config_url);
41138 + PATCH_OPTION(sort);
41139 + PATCH_OPTION(statistics_url);
41141 /* skip the first, the global context */
41142 for (i = 1; i < srv->config_context->used; i++) {
41143 data_config *dc = (data_config *)srv->config_context->data[i];
41144 s = p->config_storage[i];
41147 /* condition didn't match */
41148 if (!config_check_cond(srv, con, dc)) continue;
41152 for (j = 0; j < dc->value->used; j++) {
41153 data_unset *du = dc->value->data[j];
41156 if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
41157 - PATCH(status_url);
41158 + PATCH_OPTION(status_url);
41159 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
41160 - PATCH(config_url);
41161 + PATCH_OPTION(config_url);
41162 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
41164 + PATCH_OPTION(sort);
41165 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
41166 - PATCH(statistics_url);
41168 + PATCH_OPTION(statistics_url);
41177 static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
41178 plugin_data *p = p_d;
41181 mod_status_patch_connection(srv, con, p);
41183 - if (!buffer_is_empty(p->conf.status_url) &&
41185 + if (!buffer_is_empty(p->conf.status_url) &&
41186 buffer_is_equal(p->conf.status_url, con->uri.path)) {
41187 return mod_status_handle_server_status(srv, con, p_d);
41188 - } else if (!buffer_is_empty(p->conf.config_url) &&
41189 + } else if (!buffer_is_empty(p->conf.config_url) &&
41190 buffer_is_equal(p->conf.config_url, con->uri.path)) {
41191 return mod_status_handle_server_config(srv, con, p_d);
41192 - } else if (!buffer_is_empty(p->conf.statistics_url) &&
41193 + } else if (!buffer_is_empty(p->conf.statistics_url) &&
41194 buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
41195 return mod_status_handle_server_statistics(srv, con, p_d);
41199 return HANDLER_GO_ON;
41202 TRIGGER_FUNC(mod_status_trigger) {
41203 plugin_data *p = p_d;
41207 /* check all connections */
41208 for (i = 0; i < srv->conns->used; i++) {
41209 connection *c = srv->conns->ptr[i];
41212 p->bytes_written += c->bytes_written_cur_second;
41216 /* a sliding average */
41217 p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
41218 p->mod_5s_requests [p->mod_5s_ndx] = p->requests;
41221 p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
41224 p->abs_traffic_out += p->bytes_written;
41225 p->rel_traffic_out += p->bytes_written;
41228 p->bytes_written = 0;
41231 /* reset storage - second */
41232 p->traffic_out = 0;
41236 return HANDLER_GO_ON;
41239 REQUESTDONE_FUNC(mod_status_account) {
41240 plugin_data *p = p_d;
41250 p->bytes_written += con->bytes_written_cur_second;
41253 return HANDLER_GO_ON;
41256 int mod_status_plugin_init(plugin *p) {
41257 p->version = LIGHTTPD_VERSION_ID;
41258 p->name = buffer_init_string("status");
41261 p->init = mod_status_init;
41262 p->cleanup = mod_status_free;
41263 p->set_defaults= mod_status_set_defaults;
41266 p->handle_uri_clean = mod_status_handler;
41267 p->handle_trigger = mod_status_trigger;
41268 p->handle_request_done = mod_status_account;
41276 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c 2005-09-23 22:53:55.000000000 +0300
41277 +++ lighttpd-1.4.12/src/mod_trigger_b4_dl.c 2006-07-16 00:26:03.000000000 +0300
41278 @@ -24,18 +24,18 @@
41281 * this is a trigger_b4_dl for a lighttpd plugin
41286 /* plugin config for all request/connections */
41289 buffer *db_filename;
41292 buffer *trigger_url;
41293 buffer *download_url;
41298 buffer *mc_namespace;
41299 #if defined(HAVE_PCRE_H)
41300 @@ -46,58 +46,58 @@
41304 -#if defined(HAVE_MEMCACHE_H)
41305 +#if defined(HAVE_MEMCACHE_H)
41306 struct memcache *mc;
41310 unsigned short trigger_timeout;
41311 unsigned short debug;
41321 plugin_config **config_storage;
41323 - plugin_config conf;
41325 + plugin_config conf;
41328 /* init the plugin data */
41329 INIT_FUNC(mod_trigger_b4_dl_init) {
41333 p = calloc(1, sizeof(*p));
41336 p->tmp_buf = buffer_init();
41342 /* detroy the plugin data */
41343 FREE_FUNC(mod_trigger_b4_dl_free) {
41344 plugin_data *p = p_d;
41349 if (!p) return HANDLER_GO_ON;
41352 if (p->config_storage) {
41354 for (i = 0; i < srv->config_context->used; i++) {
41355 plugin_config *s = p->config_storage[i];
41360 buffer_free(s->db_filename);
41361 buffer_free(s->download_url);
41362 buffer_free(s->trigger_url);
41363 buffer_free(s->deny_url);
41366 buffer_free(s->mc_namespace);
41367 array_free(s->mc_hosts);
41370 #if defined(HAVE_PCRE_H)
41371 if (s->trigger_regex) pcre_free(s->trigger_regex);
41372 if (s->download_regex) pcre_free(s->download_regex);
41373 @@ -108,16 +108,16 @@
41374 #if defined(HAVE_MEMCACHE_H)
41375 if (s->mc) mc_free(s->mc);
41381 free(p->config_storage);
41385 buffer_free(p->tmp_buf);
41391 return HANDLER_GO_ON;
41394 @@ -126,9 +126,9 @@
41395 SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
41396 plugin_data *p = p_d;
41400 - config_values_t cv[] = {
41403 + config_values_t cv[] = {
41404 { "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
41405 { "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
41406 { "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
41407 @@ -139,18 +139,18 @@
41408 { "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
41409 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41413 if (!p) return HANDLER_ERROR;
41416 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41419 for (i = 0; i < srv->config_context->used; i++) {
41421 #if defined(HAVE_PCRE_H)
41422 const char *errptr;
41427 s = calloc(1, sizeof(plugin_config));
41428 s->db_filename = buffer_init();
41429 s->download_url = buffer_init();
41430 @@ -158,7 +158,7 @@
41431 s->deny_url = buffer_init();
41432 s->mc_hosts = array_init();
41433 s->mc_namespace = buffer_init();
41436 cv[0].destination = s->db_filename;
41437 cv[1].destination = s->trigger_url;
41438 cv[2].destination = s->download_url;
41439 @@ -167,41 +167,41 @@
41440 cv[5].destination = s->mc_hosts;
41441 cv[6].destination = s->mc_namespace;
41442 cv[7].destination = &(s->debug);
41445 p->config_storage[i] = s;
41448 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41449 return HANDLER_ERROR;
41451 #if defined(HAVE_GDBM_H)
41452 if (!buffer_is_empty(s->db_filename)) {
41453 if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
41454 - log_error_write(srv, __FILE__, __LINE__, "s",
41455 + log_error_write(srv, __FILE__, __LINE__, "s",
41456 "gdbm-open failed");
41457 return HANDLER_ERROR;
41461 -#if defined(HAVE_PCRE_H)
41462 +#if defined(HAVE_PCRE_H)
41463 if (!buffer_is_empty(s->download_url)) {
41464 if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
41465 0, &errptr, &erroff, NULL))) {
41467 - log_error_write(srv, __FILE__, __LINE__, "sbss",
41468 - "compiling regex for download-url failed:",
41470 + log_error_write(srv, __FILE__, __LINE__, "sbss",
41471 + "compiling regex for download-url failed:",
41472 s->download_url, "pos:", erroff);
41473 return HANDLER_ERROR;
41478 if (!buffer_is_empty(s->trigger_url)) {
41479 if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
41480 0, &errptr, &erroff, NULL))) {
41482 - log_error_write(srv, __FILE__, __LINE__, "sbss",
41483 - "compiling regex for trigger-url failed:",
41485 + log_error_write(srv, __FILE__, __LINE__, "sbss",
41486 + "compiling regex for trigger-url failed:",
41487 s->trigger_url, "pos:", erroff);
41490 return HANDLER_ERROR;
41493 @@ -211,100 +211,97 @@
41494 #if defined(HAVE_MEMCACHE_H)
41499 for (k = 0; k < s->mc_hosts->used; k++) {
41500 data_string *ds = (data_string *)s->mc_hosts->data[k];
41503 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
41504 - log_error_write(srv, __FILE__, __LINE__, "sb",
41505 - "connection to host failed:",
41506 + log_error_write(srv, __FILE__, __LINE__, "sb",
41507 + "connection to host failed:",
41511 return HANDLER_ERROR;
41515 - log_error_write(srv, __FILE__, __LINE__, "s",
41516 + log_error_write(srv, __FILE__, __LINE__, "s",
41517 "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
41518 return HANDLER_ERROR;
41524 #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
41525 - log_error_write(srv, __FILE__, __LINE__, "s",
41526 + log_error_write(srv, __FILE__, __LINE__, "s",
41527 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
41528 return HANDLER_ERROR;
41533 return HANDLER_GO_ON;
41536 -#define PATCH(x) \
41537 - p->conf.x = s->x;
41538 static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
41540 plugin_config *s = p->config_storage[0];
41543 #if defined(HAVE_GDBM)
41546 + PATCH_OPTION(db);
41548 #if defined(HAVE_PCRE_H)
41549 - PATCH(download_regex);
41550 - PATCH(trigger_regex);
41552 - PATCH(trigger_timeout);
41554 - PATCH(mc_namespace);
41556 + PATCH_OPTION(download_regex);
41557 + PATCH_OPTION(trigger_regex);
41559 + PATCH_OPTION(trigger_timeout);
41560 + PATCH_OPTION(deny_url);
41561 + PATCH_OPTION(mc_namespace);
41562 + PATCH_OPTION(debug);
41563 #if defined(HAVE_MEMCACHE_H)
41565 + PATCH_OPTION(mc);
41569 /* skip the first, the global context */
41570 for (i = 1; i < srv->config_context->used; i++) {
41571 data_config *dc = (data_config *)srv->config_context->data[i];
41572 s = p->config_storage[i];
41575 /* condition didn't match */
41576 if (!config_check_cond(srv, con, dc)) continue;
41580 for (j = 0; j < dc->value->used; j++) {
41581 data_unset *du = dc->value->data[j];
41583 if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
41584 #if defined(HAVE_PCRE_H)
41585 - PATCH(download_regex);
41586 + PATCH_OPTION(download_regex);
41588 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
41589 # if defined(HAVE_PCRE_H)
41590 - PATCH(trigger_regex);
41591 + PATCH_OPTION(trigger_regex);
41593 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
41594 #if defined(HAVE_GDBM_H)
41596 + PATCH_OPTION(db);
41598 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
41599 - PATCH(trigger_timeout);
41600 + PATCH_OPTION(trigger_timeout);
41601 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
41603 + PATCH_OPTION(debug);
41604 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
41606 + PATCH_OPTION(deny_url);
41607 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
41608 - PATCH(mc_namespace);
41609 + PATCH_OPTION(mc_namespace);
41610 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
41611 #if defined(HAVE_MEMCACHE_H)
41613 + PATCH_OPTION(mc);
41624 URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
41625 plugin_data *p = p_d;
41626 @@ -315,20 +312,20 @@
41632 if (con->uri.path->used == 0) return HANDLER_GO_ON;
41635 mod_trigger_b4_dl_patch_connection(srv, con, p);
41638 if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
41641 # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
41642 return HANDLER_GO_ON;
41643 # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
41644 if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
41645 if (p->conf.db && p->conf.mc) {
41646 /* can't decide which one */
41649 return HANDLER_GO_ON;
41651 # elif defined(HAVE_GDBM_H)
41652 @@ -336,12 +333,12 @@
41654 if (!p->conf.mc) return HANDLER_GO_ON;
41658 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
41659 /* X-Forwarded-For contains the ip behind the proxy */
41662 remote_ip = ds->value->ptr;
41665 /* memcache can't handle spaces */
41667 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
41668 @@ -350,13 +347,13 @@
41669 if (p->conf.debug) {
41670 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
41674 /* check if URL is a trigger -> insert IP into DB */
41675 if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41676 if (n != PCRE_ERROR_NOMATCH) {
41677 log_error_write(srv, __FILE__, __LINE__, "sd",
41678 "execution error while matching:", n);
41681 return HANDLER_ERROR;
41684 @@ -364,34 +361,34 @@
41686 /* the trigger matched */
41690 key.dptr = (char *)remote_ip;
41691 key.dsize = strlen(remote_ip);
41694 val.dptr = (char *)&(srv->cur_ts);
41695 val.dsize = sizeof(srv->cur_ts);
41698 if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41699 log_error_write(srv, __FILE__, __LINE__, "s",
41704 -# if defined(HAVE_MEMCACHE_H)
41705 +# if defined(HAVE_MEMCACHE_H)
41708 buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41709 buffer_append_string(p->tmp_buf, remote_ip);
41712 for (i = 0; i < p->tmp_buf->used - 1; i++) {
41713 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41717 if (p->conf.debug) {
41718 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
41721 - if (0 != mc_set(p->conf.mc,
41722 + if (0 != mc_set(p->conf.mc,
41723 CONST_BUF_LEN(p->tmp_buf),
41724 (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41725 p->conf.trigger_timeout, 0)) {
41726 @@ -401,7 +398,7 @@
41732 /* check if URL is a download -> check IP in DB, update timestamp */
41733 if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41734 if (n != PCRE_ERROR_NOMATCH) {
41735 @@ -411,93 +408,93 @@
41738 /* the download uri matched */
41739 -# if defined(HAVE_GDBM_H)
41740 +# if defined(HAVE_GDBM_H)
41746 key.dptr = (char *)remote_ip;
41747 key.dsize = strlen(remote_ip);
41750 val = gdbm_fetch(p->conf.db, key);
41753 if (val.dptr == NULL) {
41754 /* not found, redirect */
41757 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41760 con->http_status = 307;
41763 return HANDLER_FINISHED;
41767 last_hit = *(time_t *)(val.dptr);
41773 if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
41774 /* found, but timeout, redirect */
41777 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41778 con->http_status = 307;
41782 if (0 != gdbm_delete(p->conf.db, key)) {
41783 log_error_write(srv, __FILE__, __LINE__, "s",
41789 return HANDLER_FINISHED;
41793 val.dptr = (char *)&(srv->cur_ts);
41794 val.dsize = sizeof(srv->cur_ts);
41797 if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41798 log_error_write(srv, __FILE__, __LINE__, "s",
41804 -# if defined(HAVE_MEMCACHE_H)
41806 +# if defined(HAVE_MEMCACHE_H)
41812 buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41813 buffer_append_string(p->tmp_buf, remote_ip);
41816 for (i = 0; i < p->tmp_buf->used - 1; i++) {
41817 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41821 if (p->conf.debug) {
41822 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
41828 * memcached is do expiration for us, as long as we can fetch it every thing is ok
41829 - * and the timestamp is updated
41831 + * and the timestamp is updated
41834 - if (NULL == (r = mc_aget(p->conf.mc,
41835 + if (NULL == (r = mc_aget(p->conf.mc,
41836 CONST_BUF_LEN(p->tmp_buf)
41840 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41843 con->http_status = 307;
41846 return HANDLER_FINISHED;
41853 /* set a new timeout */
41854 - if (0 != mc_set(p->conf.mc,
41855 + if (0 != mc_set(p->conf.mc,
41856 CONST_BUF_LEN(p->tmp_buf),
41857 (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41858 p->conf.trigger_timeout, 0)) {
41859 @@ -507,13 +504,13 @@
41872 return HANDLER_GO_ON;
41875 @@ -521,21 +518,21 @@
41876 TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
41877 plugin_data *p = p_d;
41881 /* check DB each minute */
41882 if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
41886 for (i = 0; i < srv->config_context->used; i++) {
41887 plugin_config *s = p->config_storage[i];
41888 datum key, val, okey;
41891 if (!s->db) continue;
41896 - /* according to the manual this loop + delete does delete all entries on its way
41899 + /* according to the manual this loop + delete does delete all entries on its way
41901 * we don't care as the next round will remove them. We don't have to perfect here.
41903 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
41904 @@ -544,21 +541,21 @@
41910 val = gdbm_fetch(s->db, key);
41913 last_hit = *(time_t *)(val.dptr);
41919 if (srv->cur_ts - last_hit > s->trigger_timeout) {
41920 gdbm_delete(s->db, key);
41926 if (okey.dptr) free(okey.dptr);
41929 /* reorg once a day */
41930 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
41932 @@ -571,7 +568,7 @@
41933 int mod_trigger_b4_dl_plugin_init(plugin *p) {
41934 p->version = LIGHTTPD_VERSION_ID;
41935 p->name = buffer_init_string("trigger_b4_dl");
41938 p->init = mod_trigger_b4_dl_init;
41939 p->handle_uri_clean = mod_trigger_b4_dl_uri_handler;
41940 p->set_defaults = mod_trigger_b4_dl_set_defaults;
41941 @@ -579,8 +576,8 @@
41942 p->handle_trigger = mod_trigger_b4_dl_handle_trigger;
41944 p->cleanup = mod_trigger_b4_dl_free;
41952 --- ../lighttpd-1.4.11/src/mod_userdir.c 2005-10-28 16:48:28.000000000 +0300
41953 +++ lighttpd-1.4.12/src/mod_userdir.c 2006-07-16 00:26:04.000000000 +0300
41955 #include "response.h"
41957 #include "plugin.h"
41958 +#include "sys-files.h"
41962 @@ -25,54 +26,54 @@
41972 plugin_config **config_storage;
41974 - plugin_config conf;
41976 + plugin_config conf;
41979 /* init the plugin data */
41980 INIT_FUNC(mod_userdir_init) {
41984 p = calloc(1, sizeof(*p));
41987 p->username = buffer_init();
41988 p->temp_path = buffer_init();
41994 /* detroy the plugin data */
41995 FREE_FUNC(mod_userdir_free) {
41996 plugin_data *p = p_d;
41999 if (!p) return HANDLER_GO_ON;
42002 if (p->config_storage) {
42006 for (i = 0; i < srv->config_context->used; i++) {
42007 plugin_config *s = p->config_storage[i];
42010 array_free(s->include_user);
42011 array_free(s->exclude_user);
42012 buffer_free(s->path);
42013 buffer_free(s->basepath);
42018 free(p->config_storage);
42022 buffer_free(p->username);
42023 buffer_free(p->temp_path);
42029 return HANDLER_GO_ON;
42032 @@ -81,81 +82,78 @@
42033 SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
42034 plugin_data *p = p_d;
42037 - config_values_t cv[] = {
42039 + config_values_t cv[] = {
42040 { "userdir.path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
42041 { "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
42042 { "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
42043 { "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
42044 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42048 if (!p) return HANDLER_ERROR;
42051 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42054 for (i = 0; i < srv->config_context->used; i++) {
42058 s = calloc(1, sizeof(plugin_config));
42059 s->exclude_user = array_init();
42060 s->include_user = array_init();
42061 s->path = buffer_init();
42062 s->basepath = buffer_init();
42065 cv[0].destination = s->path;
42066 cv[1].destination = s->exclude_user;
42067 cv[2].destination = s->include_user;
42068 cv[3].destination = s->basepath;
42071 p->config_storage[i] = s;
42074 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42075 return HANDLER_ERROR;
42080 return HANDLER_GO_ON;
42083 -#define PATCH(x) \
42084 - p->conf.x = s->x;
42085 static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
42087 plugin_config *s = p->config_storage[0];
42090 - PATCH(exclude_user);
42091 - PATCH(include_user);
42095 + PATCH_OPTION(path);
42096 + PATCH_OPTION(exclude_user);
42097 + PATCH_OPTION(include_user);
42098 + PATCH_OPTION(basepath);
42100 /* skip the first, the global context */
42101 for (i = 1; i < srv->config_context->used; i++) {
42102 data_config *dc = (data_config *)srv->config_context->data[i];
42103 s = p->config_storage[i];
42106 /* condition didn't match */
42107 if (!config_check_cond(srv, con, dc)) continue;
42111 for (j = 0; j < dc->value->used; j++) {
42112 data_unset *du = dc->value->data[j];
42115 if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
42117 + PATCH_OPTION(path);
42118 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
42119 - PATCH(exclude_user);
42120 + PATCH_OPTION(exclude_user);
42121 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
42122 - PATCH(include_user);
42123 + PATCH_OPTION(include_user);
42124 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
42126 + PATCH_OPTION(basepath);
42136 URIHANDLER_FUNC(mod_userdir_docroot_handler) {
42137 plugin_data *p = p_d;
42138 @@ -169,18 +167,18 @@
42139 if (con->uri.path->used == 0) return HANDLER_GO_ON;
42141 mod_userdir_patch_connection(srv, con, p);
42144 uri_len = con->uri.path->used - 1;
42147 /* /~user/foo.html -> /home/user/public_html/foo.html */
42150 if (con->uri.path->ptr[0] != '/' ||
42151 con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
42154 if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
42155 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
42156 http_response_redirect_to_directory(srv, con);
42159 return HANDLER_FINISHED;
42162 @@ -188,10 +186,10 @@
42163 if (0 == rel_url - (con->uri.path->ptr + 2)) {
42164 return HANDLER_GO_ON;
42168 buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
42170 - if (buffer_is_empty(p->conf.basepath)
42172 + if (buffer_is_empty(p->conf.basepath)
42174 && NULL == (pwd = getpwnam(p->username->ptr))
42176 @@ -200,31 +198,31 @@
42177 return HANDLER_GO_ON;
42182 for (k = 0; k < p->conf.exclude_user->used; k++) {
42183 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
42186 if (buffer_is_equal(ds->value, p->username)) {
42187 /* user in exclude list */
42188 return HANDLER_GO_ON;
42193 if (p->conf.include_user->used) {
42194 int found_user = 0;
42195 for (k = 0; k < p->conf.include_user->used; k++) {
42196 data_string *ds = (data_string *)p->conf.include_user->data[k];
42199 if (buffer_is_equal(ds->value, p->username)) {
42200 /* user in include list */
42207 if (!found_user) return HANDLER_GO_ON;
42211 /* we build the physical path */
42213 if (buffer_is_empty(p->conf.basepath)) {
42214 @@ -252,23 +250,23 @@
42217 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
42218 - BUFFER_APPEND_SLASH(p->temp_path);
42219 + PATHNAME_APPEND_SLASH(p->temp_path);
42220 buffer_append_string_buffer(p->temp_path, p->username);
42222 - BUFFER_APPEND_SLASH(p->temp_path);
42223 - buffer_append_string_buffer(p->temp_path, p->conf.path);
42224 + PATHNAME_APPEND_SLASH(p->temp_path);
42225 + buffer_append_string_buffer(p->temp_path, p->conf.path);
42227 if (buffer_is_empty(p->conf.basepath)) {
42232 ret = stat(p->temp_path->ptr, &st);
42233 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
42234 return HANDLER_GO_ON;
42239 - BUFFER_APPEND_SLASH(p->temp_path);
42240 + PATHNAME_APPEND_SLASH(p->temp_path);
42241 buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
42242 buffer_copy_string_buffer(con->physical.path, p->temp_path);
42244 @@ -282,13 +280,13 @@
42245 int mod_userdir_plugin_init(plugin *p) {
42246 p->version = LIGHTTPD_VERSION_ID;
42247 p->name = buffer_init_string("userdir");
42250 p->init = mod_userdir_init;
42251 p->handle_physical = mod_userdir_docroot_handler;
42252 p->set_defaults = mod_userdir_set_defaults;
42253 p->cleanup = mod_userdir_free;
42261 --- ../lighttpd-1.4.11/src/mod_usertrack.c 2006-01-31 15:01:20.000000000 +0200
42262 +++ lighttpd-1.4.12/src/mod_usertrack.c 2006-07-16 00:26:04.000000000 +0300
42263 @@ -24,44 +24,44 @@
42269 plugin_config **config_storage;
42271 - plugin_config conf;
42273 + plugin_config conf;
42276 /* init the plugin data */
42277 INIT_FUNC(mod_usertrack_init) {
42281 p = calloc(1, sizeof(*p));
42287 /* detroy the plugin data */
42288 FREE_FUNC(mod_usertrack_free) {
42289 plugin_data *p = p_d;
42295 if (!p) return HANDLER_GO_ON;
42298 if (p->config_storage) {
42300 for (i = 0; i < srv->config_context->used; i++) {
42301 plugin_config *s = p->config_storage[i];
42304 buffer_free(s->cookie_name);
42305 buffer_free(s->cookie_domain);
42310 free(p->config_storage);
42317 return HANDLER_GO_ON;
42320 @@ -70,38 +70,38 @@
42321 SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
42322 plugin_data *p = p_d;
42325 - config_values_t cv[] = {
42327 + config_values_t cv[] = {
42328 { "usertrack.cookie-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
42329 { "usertrack.cookie-max-age", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
42330 { "usertrack.cookie-domain", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
42332 - { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
42334 + { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
42335 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42339 if (!p) return HANDLER_ERROR;
42342 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42345 for (i = 0; i < srv->config_context->used; i++) {
42349 s = calloc(1, sizeof(plugin_config));
42350 s->cookie_name = buffer_init();
42351 s->cookie_domain = buffer_init();
42352 s->cookie_max_age = 0;
42355 cv[0].destination = s->cookie_name;
42356 cv[1].destination = &(s->cookie_max_age);
42357 cv[2].destination = s->cookie_domain;
42360 p->config_storage[i] = s;
42363 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42364 return HANDLER_ERROR;
42368 if (buffer_is_empty(s->cookie_name)) {
42369 buffer_copy_string(s->cookie_name, "TRACKID");
42371 @@ -109,68 +109,65 @@
42372 for (j = 0; j < s->cookie_name->used - 1; j++) {
42373 char c = s->cookie_name->ptr[j] | 32;
42374 if (c < 'a' || c > 'z') {
42375 - log_error_write(srv, __FILE__, __LINE__, "sb",
42376 - "invalid character in usertrack.cookie-name:",
42377 + log_error_write(srv, __FILE__, __LINE__, "sb",
42378 + "invalid character in usertrack.cookie-name:",
42382 return HANDLER_ERROR;
42388 if (!buffer_is_empty(s->cookie_domain)) {
42390 for (j = 0; j < s->cookie_domain->used - 1; j++) {
42391 char c = s->cookie_domain->ptr[j];
42392 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
42393 - log_error_write(srv, __FILE__, __LINE__, "sb",
42394 - "invalid character in usertrack.cookie-domain:",
42395 + log_error_write(srv, __FILE__, __LINE__, "sb",
42396 + "invalid character in usertrack.cookie-domain:",
42400 return HANDLER_ERROR;
42407 return HANDLER_GO_ON;
42410 -#define PATCH(x) \
42411 - p->conf.x = s->x;
42412 static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
42414 plugin_config *s = p->config_storage[0];
42416 - PATCH(cookie_name);
42417 - PATCH(cookie_domain);
42418 - PATCH(cookie_max_age);
42421 + PATCH_OPTION(cookie_name);
42422 + PATCH_OPTION(cookie_domain);
42423 + PATCH_OPTION(cookie_max_age);
42425 /* skip the first, the global context */
42426 for (i = 1; i < srv->config_context->used; i++) {
42427 data_config *dc = (data_config *)srv->config_context->data[i];
42428 s = p->config_storage[i];
42431 /* condition didn't match */
42432 if (!config_check_cond(srv, con, dc)) continue;
42436 for (j = 0; j < dc->value->used; j++) {
42437 data_unset *du = dc->value->data[j];
42440 if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
42441 - PATCH(cookie_name);
42442 + PATCH_OPTION(cookie_name);
42443 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
42444 - PATCH(cookie_max_age);
42445 + PATCH_OPTION(cookie_max_age);
42446 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
42447 - PATCH(cookie_domain);
42448 + PATCH_OPTION(cookie_domain);
42458 URIHANDLER_FUNC(mod_usertrack_uri_handler) {
42459 plugin_data *p = p_d;
42460 @@ -178,38 +175,38 @@
42461 unsigned char h[16];
42466 if (con->uri.path->used == 0) return HANDLER_GO_ON;
42469 mod_usertrack_patch_connection(srv, con, p);
42472 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
42474 /* we have a cookie, does it contain a valid name ? */
42476 - /* parse the cookie
42479 + /* parse the cookie
42481 * check for cookiename + (WS | '=')
42487 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
42492 for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
42496 /* ok, found the key of our own cookie */
42499 if (strlen(nc) > 32) {
42501 return HANDLER_GO_ON;
42510 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
42511 ds = data_response_init();
42512 @@ -217,39 +214,39 @@
42513 buffer_copy_string(ds->key, "Set-Cookie");
42514 buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
42515 buffer_append_string(ds->value, "=");
42519 /* taken from mod_auth.c */
42522 /* generate shared-secret */
42524 MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
42525 MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
42528 /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
42529 ltostr(hh, srv->cur_ts);
42530 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42531 ltostr(hh, rand());
42532 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
42535 MD5_Final(h, &Md5Ctx);
42538 buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
42539 buffer_append_string(ds->value, "; Path=/");
42540 buffer_append_string(ds->value, "; Version=1");
42543 if (!buffer_is_empty(p->conf.cookie_domain)) {
42544 buffer_append_string(ds->value, "; Domain=");
42545 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
42549 if (p->conf.cookie_max_age) {
42550 buffer_append_string(ds->value, "; max-age=");
42551 buffer_append_long(ds->value, p->conf.cookie_max_age);
42555 array_insert_unique(con->response.headers, (data_unset *)ds);
42558 return HANDLER_GO_ON;
42561 @@ -258,13 +255,13 @@
42562 int mod_usertrack_plugin_init(plugin *p) {
42563 p->version = LIGHTTPD_VERSION_ID;
42564 p->name = buffer_init_string("usertrack");
42567 p->init = mod_usertrack_init;
42568 p->handle_uri_clean = mod_usertrack_uri_handler;
42569 p->set_defaults = mod_usertrack_set_defaults;
42570 p->cleanup = mod_usertrack_free;
42578 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
42579 +++ lighttpd-1.4.12/src/mod_webdav.c 2006-07-18 13:03:40.000000000 +0300
42582 #include <stdlib.h>
42583 #include <string.h>
42584 -#include <dirent.h>
42586 -#include <unistd.h>
42589 #include <assert.h>
42590 -#include <sys/mman.h>
42592 #ifdef HAVE_CONFIG_H
42593 #include "config.h"
42595 #include <sqlite3.h>
42598 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
42600 +#include <uuid/uuid.h>
42605 #include "buffer.h"
42606 @@ -33,13 +35,16 @@
42607 #include "stream.h"
42608 #include "stat_cache.h"
42610 +#include "sys-files.h"
42611 +#include "sys-mmap.h"
42612 +#include "sys-strings.h"
42615 * this is a webdav for a lighttpd plugin
42617 - * at least a very basic one.
42618 + * at least a very basic one.
42619 * - for now it is read-only and we only support PROPFIND
42625 @@ -58,64 +63,70 @@
42626 sqlite3_stmt *stmt_delete_prop;
42627 sqlite3_stmt *stmt_select_prop;
42628 sqlite3_stmt *stmt_select_propnames;
42631 sqlite3_stmt *stmt_delete_uri;
42632 sqlite3_stmt *stmt_move_uri;
42633 sqlite3_stmt *stmt_copy_uri;
42635 + sqlite3_stmt *stmt_remove_lock;
42636 + sqlite3_stmt *stmt_create_lock;
42637 + sqlite3_stmt *stmt_read_lock;
42638 + sqlite3_stmt *stmt_read_lock_by_uri;
42639 + sqlite3_stmt *stmt_refresh_lock;
42651 plugin_config **config_storage;
42653 - plugin_config conf;
42655 + plugin_config conf;
42658 /* init the plugin data */
42659 INIT_FUNC(mod_webdav_init) {
42663 p = calloc(1, sizeof(*p));
42666 p->tmp_buf = buffer_init();
42668 p->uri.scheme = buffer_init();
42669 p->uri.path_raw = buffer_init();
42670 p->uri.path = buffer_init();
42671 p->uri.authority = buffer_init();
42674 p->physical.path = buffer_init();
42675 p->physical.rel_path = buffer_init();
42676 p->physical.doc_root = buffer_init();
42677 p->physical.basedir = buffer_init();
42683 /* detroy the plugin data */
42684 FREE_FUNC(mod_webdav_free) {
42685 plugin_data *p = p_d;
42690 if (!p) return HANDLER_GO_ON;
42693 if (p->config_storage) {
42695 for (i = 0; i < srv->config_context->used; i++) {
42696 plugin_config *s = p->config_storage[i];
42701 buffer_free(s->sqlite_db_name);
42702 #ifdef USE_PROPPATCH
42705 sqlite3_finalize(s->stmt_delete_prop);
42706 sqlite3_finalize(s->stmt_delete_uri);
42707 sqlite3_finalize(s->stmt_copy_uri);
42708 @@ -123,9 +134,15 @@
42709 sqlite3_finalize(s->stmt_update_prop);
42710 sqlite3_finalize(s->stmt_select_prop);
42711 sqlite3_finalize(s->stmt_select_propnames);
42713 + sqlite3_finalize(s->stmt_read_lock);
42714 + sqlite3_finalize(s->stmt_read_lock_by_uri);
42715 + sqlite3_finalize(s->stmt_create_lock);
42716 + sqlite3_finalize(s->stmt_remove_lock);
42717 + sqlite3_finalize(s->stmt_refresh_lock);
42718 sqlite3_close(s->sql);
42724 free(p->config_storage);
42725 @@ -135,16 +152,16 @@
42726 buffer_free(p->uri.path_raw);
42727 buffer_free(p->uri.path);
42728 buffer_free(p->uri.authority);
42731 buffer_free(p->physical.path);
42732 buffer_free(p->physical.rel_path);
42733 buffer_free(p->physical.doc_root);
42734 buffer_free(p->physical.basedir);
42737 buffer_free(p->tmp_buf);
42743 return HANDLER_GO_ON;
42746 @@ -153,32 +170,32 @@
42747 SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
42748 plugin_data *p = p_d;
42751 - config_values_t cv[] = {
42753 + config_values_t cv[] = {
42754 { "webdav.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
42755 { "webdav.is-readonly", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
42756 { "webdav.sqlite-db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
42757 { "webdav.log-xml", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
42758 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42762 if (!p) return HANDLER_ERROR;
42765 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42768 for (i = 0; i < srv->config_context->used; i++) {
42772 s = calloc(1, sizeof(plugin_config));
42773 s->sqlite_db_name = buffer_init();
42776 cv[0].destination = &(s->enabled);
42777 cv[1].destination = &(s->is_readonly);
42778 cv[2].destination = s->sqlite_db_name;
42779 cv[3].destination = &(s->log_xml);
42782 p->config_storage[i] = s;
42785 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42786 return HANDLER_ERROR;
42788 @@ -193,8 +210,26 @@
42789 return HANDLER_ERROR;
42792 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42793 - CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42794 + if (SQLITE_OK != sqlite3_exec(s->sql,
42795 + "CREATE TABLE properties ("
42796 + " resource TEXT NOT NULL,"
42797 + " prop TEXT NOT NULL,"
42798 + " ns TEXT NOT NULL,"
42799 + " value TEXT NOT NULL,"
42800 + " PRIMARY KEY(resource, prop, ns))",
42801 + NULL, NULL, &err)) {
42803 + if (0 != strcmp(err, "table properties already exists")) {
42804 + log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42805 + sqlite3_free(err);
42807 + return HANDLER_ERROR;
42809 + sqlite3_free(err);
42812 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42813 + CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42814 &(s->stmt_select_prop), &next_stmt)) {
42815 /* prepare failed */
42817 @@ -202,8 +237,8 @@
42818 return HANDLER_ERROR;
42821 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42822 - CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42823 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42824 + CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42825 &(s->stmt_select_propnames), &next_stmt)) {
42826 /* prepare failed */
42828 @@ -211,16 +246,67 @@
42829 return HANDLER_ERROR;
42832 - if (SQLITE_OK != sqlite3_exec(s->sql,
42833 - "CREATE TABLE properties ("
42835 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42836 + CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42837 + &(s->stmt_update_prop), &next_stmt)) {
42838 + /* prepare failed */
42840 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42841 + return HANDLER_ERROR;
42844 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42845 + CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42846 + &(s->stmt_delete_prop), &next_stmt)) {
42847 + /* prepare failed */
42848 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42850 + return HANDLER_ERROR;
42853 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42854 + CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42855 + &(s->stmt_delete_uri), &next_stmt)) {
42856 + /* prepare failed */
42857 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42859 + return HANDLER_ERROR;
42862 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42863 + CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42864 + &(s->stmt_copy_uri), &next_stmt)) {
42865 + /* prepare failed */
42866 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42868 + return HANDLER_ERROR;
42871 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42872 + CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42873 + &(s->stmt_move_uri), &next_stmt)) {
42874 + /* prepare failed */
42875 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42877 + return HANDLER_ERROR;
42882 + if (SQLITE_OK != sqlite3_exec(s->sql,
42883 + "CREATE TABLE locks ("
42884 + " locktoken TEXT NOT NULL,"
42885 " resource TEXT NOT NULL,"
42886 - " prop TEXT NOT NULL,"
42887 - " ns TEXT NOT NULL,"
42888 - " value TEXT NOT NULL,"
42889 - " PRIMARY KEY(resource, prop, ns))",
42890 + " lockscope TEXT NOT NULL,"
42891 + " locktype TEXT NOT NULL,"
42892 + " owner TEXT NOT NULL,"
42893 + " depth INT NOT NULL,"
42894 + " timeout TIMESTAMP NOT NULL,"
42895 + " PRIMARY KEY(locktoken))",
42896 NULL, NULL, &err)) {
42898 - if (0 != strcmp(err, "table properties already exists")) {
42899 + if (0 != strcmp(err, "table locks already exists")) {
42900 log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42903 @@ -228,127 +314,138 @@
42908 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42909 - CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42910 - &(s->stmt_update_prop), &next_stmt)) {
42912 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42913 + CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
42914 + &(s->stmt_create_lock), &next_stmt)) {
42915 /* prepare failed */
42916 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42918 - log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42919 return HANDLER_ERROR;
42922 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42923 - CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42924 - &(s->stmt_delete_prop), &next_stmt)) {
42925 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42926 + CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
42927 + &(s->stmt_remove_lock), &next_stmt)) {
42928 /* prepare failed */
42929 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42931 return HANDLER_ERROR;
42934 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42935 - CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42936 - &(s->stmt_delete_uri), &next_stmt)) {
42937 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42938 + CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
42939 + &(s->stmt_read_lock), &next_stmt)) {
42940 /* prepare failed */
42941 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42943 return HANDLER_ERROR;
42946 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42947 - CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42948 - &(s->stmt_copy_uri), &next_stmt)) {
42949 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42950 + CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
42951 + &(s->stmt_read_lock_by_uri), &next_stmt)) {
42952 /* prepare failed */
42953 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42955 return HANDLER_ERROR;
42958 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42959 - CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42960 - &(s->stmt_move_uri), &next_stmt)) {
42961 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42962 + CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
42963 + &(s->stmt_refresh_lock), &next_stmt)) {
42964 /* prepare failed */
42965 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42967 return HANDLER_ERROR;
42972 log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
42973 return HANDLER_ERROR;
42979 return HANDLER_GO_ON;
42982 -#define PATCH(x) \
42983 - p->conf.x = s->x;
42984 static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
42986 plugin_config *s = p->config_storage[0];
42989 - PATCH(is_readonly);
42993 + PATCH_OPTION(enabled);
42994 + PATCH_OPTION(is_readonly);
42995 + PATCH_OPTION(log_xml);
42997 #ifdef USE_PROPPATCH
42999 - PATCH(stmt_update_prop);
43000 - PATCH(stmt_delete_prop);
43001 - PATCH(stmt_select_prop);
43002 - PATCH(stmt_select_propnames);
43004 - PATCH(stmt_delete_uri);
43005 - PATCH(stmt_move_uri);
43006 - PATCH(stmt_copy_uri);
43007 + PATCH_OPTION(sql);
43008 + PATCH_OPTION(stmt_update_prop);
43009 + PATCH_OPTION(stmt_delete_prop);
43010 + PATCH_OPTION(stmt_select_prop);
43011 + PATCH_OPTION(stmt_select_propnames);
43013 + PATCH_OPTION(stmt_delete_uri);
43014 + PATCH_OPTION(stmt_move_uri);
43015 + PATCH_OPTION(stmt_copy_uri);
43017 + PATCH_OPTION(stmt_remove_lock);
43018 + PATCH_OPTION(stmt_refresh_lock);
43019 + PATCH_OPTION(stmt_create_lock);
43020 + PATCH_OPTION(stmt_read_lock);
43021 + PATCH_OPTION(stmt_read_lock_by_uri);
43023 /* skip the first, the global context */
43024 for (i = 1; i < srv->config_context->used; i++) {
43025 data_config *dc = (data_config *)srv->config_context->data[i];
43026 s = p->config_storage[i];
43029 /* condition didn't match */
43030 if (!config_check_cond(srv, con, dc)) continue;
43034 for (j = 0; j < dc->value->used; j++) {
43035 data_unset *du = dc->value->data[j];
43038 if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
43040 + PATCH_OPTION(enabled);
43041 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
43042 - PATCH(is_readonly);
43043 + PATCH_OPTION(is_readonly);
43044 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
43046 + PATCH_OPTION(log_xml);
43047 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
43048 #ifdef USE_PROPPATCH
43050 - PATCH(stmt_update_prop);
43051 - PATCH(stmt_delete_prop);
43052 - PATCH(stmt_select_prop);
43053 - PATCH(stmt_select_propnames);
43055 - PATCH(stmt_delete_uri);
43056 - PATCH(stmt_move_uri);
43057 - PATCH(stmt_copy_uri);
43058 + PATCH_OPTION(sql);
43059 + PATCH_OPTION(stmt_update_prop);
43060 + PATCH_OPTION(stmt_delete_prop);
43061 + PATCH_OPTION(stmt_select_prop);
43062 + PATCH_OPTION(stmt_select_propnames);
43064 + PATCH_OPTION(stmt_delete_uri);
43065 + PATCH_OPTION(stmt_move_uri);
43066 + PATCH_OPTION(stmt_copy_uri);
43068 + PATCH_OPTION(stmt_remove_lock);
43069 + PATCH_OPTION(stmt_refresh_lock);
43070 + PATCH_OPTION(stmt_create_lock);
43071 + PATCH_OPTION(stmt_read_lock);
43072 + PATCH_OPTION(stmt_read_lock_by_uri);
43083 URIHANDLER_FUNC(mod_webdav_uri_handler) {
43084 plugin_data *p = p_d;
43089 if (con->uri.path->used == 0) return HANDLER_GO_ON;
43092 mod_webdav_patch_connection(srv, con, p);
43094 if (!p->conf.enabled) return HANDLER_GO_ON;
43095 @@ -362,20 +459,20 @@
43096 if (p->conf.is_readonly) {
43097 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
43099 - response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
43100 + response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
43109 return HANDLER_GO_ON;
43111 -static int webdav_gen_prop_tag(server *srv, connection *con,
43115 +static int webdav_gen_prop_tag(server *srv, connection *con,
43122 @@ -414,7 +511,7 @@
43123 buffer_append_string_buffer(b, dst->rel_path);
43124 buffer_append_string(b,"</D:href>\n");
43125 buffer_append_string(b,"<D:status>\n");
43128 if (con->request.http_version == HTTP_VERSION_1_1) {
43129 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
43131 @@ -458,14 +555,13 @@
43133 /* bind the values to the insert */
43135 - sqlite3_bind_text(stmt, 1,
43136 - dst->rel_path->ptr,
43137 + sqlite3_bind_text(stmt, 1,
43138 + dst->rel_path->ptr,
43139 dst->rel_path->used - 1,
43143 if (SQLITE_DONE != sqlite3_step(stmt)) {
43149 @@ -493,14 +589,14 @@
43150 (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
43152 /* ignore the parent dir */
43156 buffer_copy_string_buffer(d.path, dst->path);
43157 - BUFFER_APPEND_SLASH(d.path);
43158 + PATHNAME_APPEND_SLASH(d.path);
43159 buffer_append_string(d.path, de->d_name);
43162 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43163 - BUFFER_APPEND_SLASH(d.rel_path);
43164 + PATHNAME_APPEND_SLASH(d.rel_path);
43165 buffer_append_string(d.rel_path, de->d_name);
43167 /* stat and unlink afterwards */
43168 @@ -508,7 +604,7 @@
43169 /* don't about it yet, rmdir will fail too */
43170 } else if (S_ISDIR(st.st_mode)) {
43171 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
43174 /* try to unlink it */
43175 if (-1 == rmdir(d.path->ptr)) {
43177 @@ -535,14 +631,13 @@
43179 /* bind the values to the insert */
43181 - sqlite3_bind_text(stmt, 1,
43183 + sqlite3_bind_text(stmt, 1,
43185 d.rel_path->used - 1,
43189 if (SQLITE_DONE != sqlite3_step(stmt)) {
43195 @@ -569,7 +664,7 @@
43196 if (stream_open(&s, src->path)) {
43201 if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
43202 /* opening the destination failed for some reason */
43204 @@ -601,7 +696,7 @@
43213 @@ -614,19 +709,18 @@
43214 sqlite3_reset(stmt);
43216 /* bind the values to the insert */
43217 - sqlite3_bind_text(stmt, 1,
43218 - dst->rel_path->ptr,
43219 + sqlite3_bind_text(stmt, 1,
43220 + dst->rel_path->ptr,
43221 dst->rel_path->used - 1,
43224 - sqlite3_bind_text(stmt, 2,
43225 - src->rel_path->ptr,
43226 + sqlite3_bind_text(stmt, 2,
43227 + src->rel_path->ptr,
43228 src->rel_path->used - 1,
43232 if (SQLITE_DONE != sqlite3_step(stmt)) {
43238 @@ -655,21 +749,21 @@
43239 (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
43244 buffer_copy_string_buffer(s.path, src->path);
43245 - BUFFER_APPEND_SLASH(s.path);
43246 + PATHNAME_APPEND_SLASH(s.path);
43247 buffer_append_string(s.path, de->d_name);
43249 buffer_copy_string_buffer(d.path, dst->path);
43250 - BUFFER_APPEND_SLASH(d.path);
43251 + PATHNAME_APPEND_SLASH(d.path);
43252 buffer_append_string(d.path, de->d_name);
43254 buffer_copy_string_buffer(s.rel_path, src->rel_path);
43255 - BUFFER_APPEND_SLASH(s.rel_path);
43256 + PATHNAME_APPEND_SLASH(s.rel_path);
43257 buffer_append_string(s.rel_path, de->d_name);
43259 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43260 - BUFFER_APPEND_SLASH(d.rel_path);
43261 + PATHNAME_APPEND_SLASH(d.rel_path);
43262 buffer_append_string(d.rel_path, de->d_name);
43264 if (-1 == stat(s.path->ptr, &st)) {
43265 @@ -692,19 +786,18 @@
43266 sqlite3_reset(stmt);
43268 /* bind the values to the insert */
43269 - sqlite3_bind_text(stmt, 1,
43270 - dst->rel_path->ptr,
43271 + sqlite3_bind_text(stmt, 1,
43272 + dst->rel_path->ptr,
43273 dst->rel_path->used - 1,
43276 - sqlite3_bind_text(stmt, 2,
43277 - src->rel_path->ptr,
43278 + sqlite3_bind_text(stmt, 2,
43279 + src->rel_path->ptr,
43280 src->rel_path->used - 1,
43284 if (SQLITE_DONE != sqlite3_step(stmt)) {
43290 @@ -721,7 +814,7 @@
43291 buffer_free(s.rel_path);
43292 buffer_free(d.path);
43293 buffer_free(d.rel_path);
43299 @@ -748,12 +841,12 @@
43300 if (S_ISDIR(sce->st.st_mode)) {
43301 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
43303 - } else if(S_ISREG(sce->st.st_mode)) {
43304 + } else if(S_ISREG(sce->st.st_mode)) {
43305 for (k = 0; k < con->conf.mimetypes->used; k++) {
43306 data_string *ds = (data_string *)con->conf.mimetypes->data[k];
43309 if (ds->key->used == 0) continue;
43312 if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
43313 buffer_append_string(b,"<D:getcontenttype>");
43314 buffer_append_string_buffer(b, ds->value);
43315 @@ -807,23 +900,23 @@
43317 /* bind the values to the insert */
43319 - sqlite3_bind_text(stmt, 1,
43320 - dst->rel_path->ptr,
43321 + sqlite3_bind_text(stmt, 1,
43322 + dst->rel_path->ptr,
43323 dst->rel_path->used - 1,
43325 - sqlite3_bind_text(stmt, 2,
43326 + sqlite3_bind_text(stmt, 2,
43330 - sqlite3_bind_text(stmt, 3,
43331 + sqlite3_bind_text(stmt, 3,
43337 - while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
43338 + while (SQLITE_ROW == sqlite3_step(stmt)) {
43339 /* there is a row for us, we only expect a single col 'value' */
43340 - webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
43341 + webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
43345 @@ -840,7 +933,7 @@
43349 -webdav_property live_properties[] = {
43350 +webdav_property live_properties[] = {
43351 { "DAV:", "creationdate" },
43352 { "DAV:", "displayname" },
43353 { "DAV:", "getcontentlanguage" },
43354 @@ -871,8 +964,8 @@
43355 webdav_property *prop;
43357 prop = props->ptr[i];
43359 - if (0 != webdav_get_property(srv, con, p,
43361 + if (0 != webdav_get_property(srv, con, p,
43362 dst, prop->prop, prop->ns, b_200)) {
43363 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
43365 @@ -916,12 +1009,12 @@
43366 if (-1 == c->file.fd && /* open the file if not already open */
43367 -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43368 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43375 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43376 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43377 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43378 strerror(errno), c->file.name, c->file.fd);
43381 @@ -938,7 +1031,7 @@
43382 if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
43383 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43387 c->offset += weHave;
43388 cq->bytes_out += weHave;
43390 @@ -956,7 +1049,7 @@
43391 if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
43392 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
43396 c->offset += weHave;
43397 cq->bytes_out += weHave;
43399 @@ -991,6 +1084,113 @@
43403 +int webdav_lockdiscovery(server *srv, connection *con,
43404 + buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
43408 + response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
43410 + response_header_overwrite(srv, con,
43411 + CONST_STR_LEN("Content-Type"),
43412 + CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43414 + b = chunkqueue_get_append_buffer(con->write_queue);
43416 + buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43418 + buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43419 + buffer_append_string(b,"<D:lockdiscovery>\n");
43420 + buffer_append_string(b,"<D:activelock>\n");
43422 + buffer_append_string(b,"<D:lockscope>");
43423 + buffer_append_string(b,"<D:");
43424 + buffer_append_string(b, lockscope);
43425 + buffer_append_string(b, "/>");
43426 + buffer_append_string(b,"</D:lockscope>\n");
43428 + buffer_append_string(b,"<D:locktype>");
43429 + buffer_append_string(b,"<D:");
43430 + buffer_append_string(b, locktype);
43431 + buffer_append_string(b, "/>");
43432 + buffer_append_string(b,"</D:locktype>\n");
43434 + buffer_append_string(b,"<D:depth>");
43435 + buffer_append_string(b, depth == 0 ? "0" : "infinity");
43436 + buffer_append_string(b,"</D:depth>\n");
43438 + buffer_append_string(b,"<D:timeout>");
43439 + buffer_append_string(b, "Second-600");
43440 + buffer_append_string(b,"</D:timeout>\n");
43442 + buffer_append_string(b,"<D:owner>");
43443 + buffer_append_string(b,"</D:owner>\n");
43445 + buffer_append_string(b,"<D:locktoken>");
43446 + buffer_append_string(b, "<D:href>");
43447 + buffer_append_string_buffer(b, locktoken);
43448 + buffer_append_string(b, "</D:href>");
43449 + buffer_append_string(b,"</D:locktoken>\n");
43451 + buffer_append_string(b,"</D:activelock>\n");
43452 + buffer_append_string(b,"</D:lockdiscovery>\n");
43453 + buffer_append_string(b,"</D:prop>\n");
43458 + * check if resource is having the right locks to access to resource
43463 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
43464 + int has_lock = 1;
43474 + * there is NOT, AND and OR
43475 + * and a list can be tagged
43477 + * (<lock-token>) is untagged
43478 + * <tag> (<lock-token>) is tagged
43480 + * as long as we don't handle collections it is simple. :)
43482 + * X-Litmus: locks: 11 (owner_modify)
43483 + * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
43485 + * X-Litmus: locks: 16 (fail_cond_put)
43486 + * If: (<DAV:no-lock> ["-1622396671"])
43488 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43490 + /* we didn't provided a lock-token -> */
43491 + /* if the resource is locked -> 423 */
43493 + sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43495 + sqlite3_reset(stmt);
43497 + sqlite3_bind_text(stmt, 1,
43498 + CONST_BUF_LEN(uri),
43499 + SQLITE_TRANSIENT);
43501 + while (SQLITE_ROW == sqlite3_step(stmt)) {
43510 URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
43511 plugin_data *p = p_d;
43513 @@ -1001,7 +1201,8 @@
43516 webdav_properties *req_props;
43518 + stat_cache_entry *sce = NULL;
43522 if (!p->conf.enabled) return HANDLER_GO_ON;
43523 @@ -1019,7 +1220,19 @@
43526 /* is there a content-body ? */
43529 + switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
43530 + case HANDLER_ERROR:
43531 + if (errno == ENOENT) {
43532 + con->http_status = 404;
43533 + return HANDLER_FINISHED;
43541 #ifdef USE_PROPPATCH
43542 /* any special requests or just allprop ? */
43543 if (con->request.content_length) {
43544 @@ -1087,14 +1300,13 @@
43545 /* get all property names (EMPTY) */
43546 sqlite3_reset(stmt);
43547 /* bind the values to the insert */
43549 - sqlite3_bind_text(stmt, 1,
43550 - con->uri.path->ptr,
43552 + sqlite3_bind_text(stmt, 1,
43553 + con->uri.path->ptr,
43554 con->uri.path->used - 1,
43558 if (SQLITE_DONE != sqlite3_step(stmt)) {
43562 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
43563 @@ -1115,13 +1327,13 @@
43564 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43566 b = chunkqueue_get_append_buffer(con->write_queue);
43569 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43571 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
43576 prop_200 = buffer_init();
43577 prop_404 = buffer_init();
43579 @@ -1129,7 +1341,7 @@
43582 webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
43585 buffer_append_string(b,"<D:response>\n");
43586 buffer_append_string(b,"<D:href>");
43587 buffer_append_string_buffer(b, con->uri.scheme);
43588 @@ -1145,9 +1357,9 @@
43589 buffer_append_string_buffer(b, prop_200);
43591 buffer_append_string(b,"</D:prop>\n");
43594 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43597 buffer_append_string(b,"</D:propstat>\n");
43599 if (!buffer_is_empty(prop_404)) {
43600 @@ -1157,16 +1369,16 @@
43601 buffer_append_string_buffer(b, prop_404);
43603 buffer_append_string(b,"</D:prop>\n");
43606 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43609 buffer_append_string(b,"</D:propstat>\n");
43612 buffer_append_string(b,"</D:response>\n");
43617 if (NULL != (dir = opendir(con->physical.path->ptr))) {
43620 @@ -1179,16 +1391,16 @@
43621 if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
43623 /* ignore the parent dir */
43627 buffer_copy_string_buffer(d.path, dst->path);
43628 - BUFFER_APPEND_SLASH(d.path);
43629 + PATHNAME_APPEND_SLASH(d.path);
43631 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43632 - BUFFER_APPEND_SLASH(d.rel_path);
43633 + PATHNAME_APPEND_SLASH(d.rel_path);
43635 if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
43636 - /* don't append the . */
43637 + /* don't append the . */
43639 buffer_append_string(d.path, de->d_name);
43640 buffer_append_string(d.rel_path, de->d_name);
43641 @@ -1198,7 +1410,7 @@
43642 buffer_reset(prop_404);
43644 webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
43647 buffer_append_string(b,"<D:response>\n");
43648 buffer_append_string(b,"<D:href>");
43649 buffer_append_string_buffer(b, con->uri.scheme);
43650 @@ -1214,9 +1426,9 @@
43651 buffer_append_string_buffer(b, prop_200);
43653 buffer_append_string(b,"</D:prop>\n");
43656 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43659 buffer_append_string(b,"</D:propstat>\n");
43661 if (!buffer_is_empty(prop_404)) {
43662 @@ -1226,9 +1438,9 @@
43663 buffer_append_string_buffer(b, prop_404);
43665 buffer_append_string(b,"</D:prop>\n");
43668 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43671 buffer_append_string(b,"</D:propstat>\n");
43674 @@ -1275,7 +1487,7 @@
43676 return HANDLER_FINISHED;
43680 /* let's create the directory */
43682 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
43683 @@ -1303,7 +1515,13 @@
43684 con->http_status = 403;
43685 return HANDLER_FINISHED;
43689 + /* does the client have a lock for this connection ? */
43690 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43691 + con->http_status = 423;
43692 + return HANDLER_FINISHED;
43695 /* stat and unlink afterwards */
43696 if (-1 == stat(con->physical.path->ptr, &st)) {
43697 /* don't about it yet, unlink will fail too */
43698 @@ -1323,7 +1541,7 @@
43699 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43701 b = chunkqueue_get_append_buffer(con->write_queue);
43704 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43706 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
43707 @@ -1331,7 +1549,7 @@
43708 buffer_append_string_buffer(b, multi_status_resp);
43710 buffer_append_string(b,"</D:multistatus>\n");
43713 if (p->conf.log_xml) {
43714 log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
43716 @@ -1340,7 +1558,7 @@
43717 con->file_finished = 1;
43719 /* everything went fine, remove the directory */
43722 if (-1 == rmdir(con->physical.path->ptr)) {
43725 @@ -1375,97 +1593,174 @@
43726 case HTTP_METHOD_PUT: {
43728 chunkqueue *cq = con->request_content_queue;
43730 + data_string *ds_range;
43732 if (p->conf.is_readonly) {
43733 con->http_status = 403;
43734 return HANDLER_FINISHED;
43737 + /* is a exclusive lock set on the source */
43738 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43739 + con->http_status = 423;
43740 + return HANDLER_FINISHED;
43744 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
43746 - /* taken what we have in the request-body and write it to a file */
43747 - if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
43748 - /* we can't open the file */
43749 - con->http_status = 403;
43752 + /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
43753 + * - most important Content-Range
43756 + * Example: Content-Range: bytes 100-1037/1038 */
43758 - con->http_status = 201; /* created */
43759 - con->file_finished = 1;
43760 + if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
43761 + const char *num = ds_range->value->ptr;
43763 + char *err = NULL;
43765 - for (c = cq->first; c; c = cq->first) {
43767 + if (0 != strncmp(num, "bytes ", 6)) {
43768 + con->http_status = 501; /* not implemented */
43770 - /* copy all chunks */
43771 - switch(c->type) {
43774 - if (c->file.mmap.start == MAP_FAILED) {
43775 - if (-1 == c->file.fd && /* open the file if not already open */
43776 - -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43777 - log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43782 - if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43783 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43784 - strerror(errno), c->file.name, c->file.fd);
43785 + return HANDLER_FINISHED;
43790 + /* we only support <num>- ... */
43792 - c->file.mmap.length = c->file.length;
43795 - close(c->file.fd);
43798 - /* chunk_reset() or chunk_free() will cleanup for us */
43801 - if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43804 - con->http_status = 507;
43808 - con->http_status = 403;
43814 - if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43817 - con->http_status = 507;
43821 - con->http_status = 403;
43826 + while (*num == ' ' || *num == '\t') num++;
43828 + if (*num == '\0') {
43829 + con->http_status = 501; /* not implemented */
43831 + return HANDLER_FINISHED;
43834 + offset = strtoll(num, &err, 10);
43836 + if (*err != '-' || offset < 0) {
43837 + con->http_status = 501; /* not implemented */
43839 + return HANDLER_FINISHED;
43842 + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
43845 + con->http_status = 404; /* not found */
43847 - case UNUSED_CHUNK:
43849 + con->http_status = 403; /* not found */
43852 + return HANDLER_FINISHED;
43855 + if (-1 == lseek(fd, offset, SEEK_SET)) {
43856 + con->http_status = 501; /* not implemented */
43860 + return HANDLER_FINISHED;
43862 + con->http_status = 200; /* modified */
43864 + /* take what we have in the request-body and write it to a file */
43866 + /* if the file doesn't exist, create it */
43867 + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
43868 + if (errno == ENOENT &&
43869 + -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
43870 + /* we can't open the file */
43871 + con->http_status = 403;
43875 - cq->bytes_out += r;
43876 + return HANDLER_FINISHED;
43879 + con->http_status = 201; /* created */
43882 + con->http_status = 200; /* modified */
43886 + con->file_finished = 1;
43888 + for (c = cq->first; c; c = cq->first) {
43891 + /* copy all chunks */
43892 + switch(c->type) {
43895 + if (c->file.mmap.start == MAP_FAILED) {
43896 + if (-1 == c->file.fd && /* open the file if not already open */
43897 + -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43898 + log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43903 + if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43904 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43905 + strerror(errno), c->file.name, c->file.fd);
43910 + c->file.mmap.length = c->file.length;
43912 + close(c->file.fd);
43915 + /* chunk_reset() or chunk_free() will cleanup for us */
43918 + if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43921 + con->http_status = 507;
43925 + con->http_status = 403;
43929 - chunkqueue_remove_finished_chunks(cq);
43932 + if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43935 + con->http_status = 507;
43939 + con->http_status = 403;
43944 + case UNUSED_CHUNK:
43951 + cq->bytes_out += r;
43955 + chunkqueue_remove_finished_chunks(cq);
43959 return HANDLER_FINISHED;
43961 - case HTTP_METHOD_MOVE:
43962 + case HTTP_METHOD_MOVE:
43963 case HTTP_METHOD_COPY: {
43964 buffer *destination = NULL;
43966 @@ -1475,7 +1770,15 @@
43967 con->http_status = 403;
43968 return HANDLER_FINISHED;
43972 + /* is a exclusive lock set on the source */
43973 + if (con->request.http_method == HTTP_METHOD_MOVE) {
43974 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43975 + con->http_status = 423;
43976 + return HANDLER_FINISHED;
43980 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
43981 destination = ds->value;
43983 @@ -1549,10 +1852,10 @@
43986 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
43987 - BUFFER_APPEND_SLASH(p->physical.path);
43988 + PATHNAME_APPEND_SLASH(p->physical.path);
43989 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
43991 - /* don't add a second / */
43992 + /* don't add a second / */
43993 if (p->physical.rel_path->ptr[0] == '/') {
43994 buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
43996 @@ -1613,6 +1916,12 @@
43997 /* it is just a file, good */
44000 + /* does the client have a lock for this connection ? */
44001 + if (!webdav_has_lock(srv, con, p, p->uri.path)) {
44002 + con->http_status = 423;
44003 + return HANDLER_FINISHED;
44006 /* destination exists */
44007 if (0 == (r = stat(p->physical.path->ptr, &st))) {
44008 if (S_ISDIR(st.st_mode)) {
44009 @@ -1636,7 +1945,7 @@
44010 return HANDLER_FINISHED;
44012 } else if (overwrite == 0) {
44013 - /* destination exists, but overwrite is not set */
44014 + /* destination exists, but overwrite is not set */
44015 con->http_status = 412;
44016 return HANDLER_FINISHED;
44018 @@ -1655,16 +1964,16 @@
44019 sqlite3_reset(stmt);
44021 /* bind the values to the insert */
44022 - sqlite3_bind_text(stmt, 1,
44023 - p->uri.path->ptr,
44024 + sqlite3_bind_text(stmt, 1,
44025 + p->uri.path->ptr,
44026 p->uri.path->used - 1,
44029 - sqlite3_bind_text(stmt, 2,
44030 - con->uri.path->ptr,
44031 + sqlite3_bind_text(stmt, 2,
44032 + con->uri.path->ptr,
44033 con->uri.path->used - 1,
44037 if (SQLITE_DONE != sqlite3_step(stmt)) {
44038 log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
44040 @@ -1691,12 +2000,17 @@
44042 return HANDLER_FINISHED;
44044 - case HTTP_METHOD_PROPPATCH: {
44045 + case HTTP_METHOD_PROPPATCH:
44046 if (p->conf.is_readonly) {
44047 con->http_status = 403;
44048 return HANDLER_FINISHED;
44051 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
44052 + con->http_status = 423;
44053 + return HANDLER_FINISHED;
44056 /* check if destination exists */
44057 if (-1 == stat(con->physical.path->ptr, &st)) {
44059 @@ -1737,7 +2051,7 @@
44061 sqlite3_stmt *stmt;
44063 - stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
44064 + stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
44065 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
44067 for (props = cmd->children; props; props = props->next) {
44068 @@ -1762,34 +2076,35 @@
44070 /* bind the values to the insert */
44072 - sqlite3_bind_text(stmt, 1,
44073 - con->uri.path->ptr,
44074 + sqlite3_bind_text(stmt, 1,
44075 + con->uri.path->ptr,
44076 con->uri.path->used - 1,
44078 - sqlite3_bind_text(stmt, 2,
44079 + sqlite3_bind_text(stmt, 2,
44080 (char *)prop->name,
44081 strlen((char *)prop->name),
44084 - sqlite3_bind_text(stmt, 3,
44085 + sqlite3_bind_text(stmt, 3,
44086 (char *)prop->ns->href,
44087 strlen((char *)prop->ns->href),
44090 - sqlite3_bind_text(stmt, 3,
44091 + sqlite3_bind_text(stmt, 3,
44096 if (stmt == p->conf.stmt_update_prop) {
44097 - sqlite3_bind_text(stmt, 4,
44098 + sqlite3_bind_text(stmt, 4,
44099 (char *)xmlNodeGetContent(prop),
44100 strlen((char *)xmlNodeGetContent(prop)),
44105 if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
44106 - log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
44107 + log_error_write(srv, __FILE__, __LINE__, "ss",
44108 + "sql-set failed:", sqlite3_errmsg(p->conf.sql));
44112 @@ -1804,7 +2119,7 @@
44114 goto propmatch_cleanup;
44118 con->http_status = 400;
44120 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
44121 @@ -1821,6 +2136,7 @@
44128 con->http_status = 400;
44129 @@ -1830,11 +2146,307 @@
44131 con->http_status = 501;
44132 return HANDLER_FINISHED;
44134 + case HTTP_METHOD_LOCK:
44136 + * a mac wants to write
44138 + * LOCK /dav/expire.txt HTTP/1.1\r\n
44139 + * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
44140 + * Accept: * / *\r\n
44142 + * Timeout: Second-600\r\n
44143 + * Content-Type: text/xml; charset=\"utf-8\"\r\n
44144 + * Content-Length: 229\r\n
44145 + * Connection: keep-alive\r\n
44146 + * Host: 192.168.178.23:1025\r\n
44148 + * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
44149 + * <D:lockinfo xmlns:D=\"DAV:\">\n
44150 + * <D:lockscope><D:exclusive/></D:lockscope>\n
44151 + * <D:locktype><D:write/></D:locktype>\n
44153 + * <D:href>http://www.apple.com/webdav_fs/</D:href>\n
44155 + * </D:lockinfo>\n
44158 + if (depth != 0 && depth != -1) {
44159 + con->http_status = 400;
44161 + return HANDLER_FINISHED;
44165 + if (con->request.content_length) {
44167 + buffer *hdr_if = NULL;
44169 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
44170 + hdr_if = ds->value;
44173 + /* we don't support Depth: Infinity on locks */
44174 + if (hdr_if == NULL && depth == -1) {
44175 + con->http_status = 409; /* Conflict */
44177 + return HANDLER_FINISHED;
44180 + if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
44181 + xmlNode *rootnode = xmlDocGetRootElement(xml);
44183 + assert(rootnode);
44185 + if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
44186 + xmlNode *lockinfo;
44187 + const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
44189 + for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
44190 + if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
44192 + for (value = lockinfo->children; value; value = value->next) {
44193 + if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
44194 + (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
44195 + lockscope = value->name;
44197 + con->http_status = 400;
44200 + return HANDLER_FINISHED;
44203 + } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
44205 + for (value = lockinfo->children; value; value = value->next) {
44206 + if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
44207 + locktype = value->name;
44209 + con->http_status = 400;
44212 + return HANDLER_FINISHED;
44216 + } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
44220 + if (lockscope && locktype) {
44221 + sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
44223 + /* is this resourse already locked ? */
44225 + /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
44227 + * WHERE resource = ? */
44231 + sqlite3_reset(stmt);
44233 + sqlite3_bind_text(stmt, 1,
44234 + p->uri.path->ptr,
44235 + p->uri.path->used - 1,
44236 + SQLITE_TRANSIENT);
44238 + /* it is the PK */
44239 + while (SQLITE_ROW == sqlite3_step(stmt)) {
44240 + /* we found a lock
44241 + * 1. is it compatible ?
44242 + * 2. is it ours */
44243 + char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
44245 + if (strcmp(sql_lockscope, "exclusive")) {
44246 + con->http_status = 423;
44247 + } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
44248 + /* resourse is locked with a shared lock
44249 + * client wants exclusive */
44250 + con->http_status = 423;
44253 + if (con->http_status == 423) {
44255 + return HANDLER_FINISHED;
44259 + stmt = p->conf.stmt_create_lock;
44261 + /* create a lock-token */
44263 + char uuid[37] /* 36 + \0 */;
44265 + uuid_generate(id);
44266 + uuid_unparse(id, uuid);
44268 + buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
44269 + buffer_append_string(p->tmp_buf, uuid);
44271 + /* "CREATE TABLE locks ("
44272 + * " locktoken TEXT NOT NULL,"
44273 + * " resource TEXT NOT NULL,"
44274 + * " lockscope TEXT NOT NULL,"
44275 + * " locktype TEXT NOT NULL,"
44276 + * " owner TEXT NOT NULL,"
44277 + * " depth INT NOT NULL,"
44280 + sqlite3_reset(stmt);
44282 + sqlite3_bind_text(stmt, 1,
44283 + CONST_BUF_LEN(p->tmp_buf),
44284 + SQLITE_TRANSIENT);
44286 + sqlite3_bind_text(stmt, 2,
44287 + CONST_BUF_LEN(con->uri.path),
44288 + SQLITE_TRANSIENT);
44290 + sqlite3_bind_text(stmt, 3,
44292 + xmlStrlen(lockscope),
44293 + SQLITE_TRANSIENT);
44295 + sqlite3_bind_text(stmt, 4,
44297 + xmlStrlen(locktype),
44298 + SQLITE_TRANSIENT);
44301 + sqlite3_bind_text(stmt, 5,
44304 + SQLITE_TRANSIENT);
44307 + sqlite3_bind_int(stmt, 6,
44311 + if (SQLITE_DONE != sqlite3_step(stmt)) {
44312 + log_error_write(srv, __FILE__, __LINE__, "ss",
44313 + "create lock:", sqlite3_errmsg(p->conf.sql));
44316 + /* looks like we survived */
44317 + webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
44319 + con->http_status = 201;
44320 + con->file_finished = 1;
44326 + return HANDLER_FINISHED;
44328 + con->http_status = 400;
44329 + return HANDLER_FINISHED;
44333 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
44334 + buffer *locktoken = ds->value;
44335 + sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
44337 + /* remove the < > around the token */
44338 + if (locktoken->used < 6) {
44339 + con->http_status = 400;
44341 + return HANDLER_FINISHED;
44344 + buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
44346 + sqlite3_reset(stmt);
44348 + sqlite3_bind_text(stmt, 1,
44349 + CONST_BUF_LEN(p->tmp_buf),
44350 + SQLITE_TRANSIENT);
44352 + if (SQLITE_DONE != sqlite3_step(stmt)) {
44353 + log_error_write(srv, __FILE__, __LINE__, "ss",
44354 + "refresh lock:", sqlite3_errmsg(p->conf.sql));
44357 + webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
44359 + con->http_status = 200;
44360 + con->file_finished = 1;
44361 + return HANDLER_FINISHED;
44363 + /* we need a lock-token to refresh */
44364 + con->http_status = 400;
44366 + return HANDLER_FINISHED;
44371 + con->http_status = 501;
44372 + return HANDLER_FINISHED;
44374 + case HTTP_METHOD_UNLOCK:
44376 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
44377 + buffer *locktoken = ds->value;
44378 + sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
44380 + /* remove the < > around the token */
44381 + if (locktoken->used < 4) {
44382 + con->http_status = 400;
44384 + return HANDLER_FINISHED;
44390 + * if the resourse is locked:
44391 + * - by us: unlock
44392 + * - by someone else: 401
44393 + * if the resource is not locked:
44397 + buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
44399 + sqlite3_reset(stmt);
44401 + sqlite3_bind_text(stmt, 1,
44402 + CONST_BUF_LEN(p->tmp_buf),
44403 + SQLITE_TRANSIENT);
44405 + sqlite3_bind_text(stmt, 2,
44406 + CONST_BUF_LEN(con->uri.path),
44407 + SQLITE_TRANSIENT);
44409 + if (SQLITE_DONE != sqlite3_step(stmt)) {
44410 + log_error_write(srv, __FILE__, __LINE__, "ss",
44411 + "remove lock:", sqlite3_errmsg(p->conf.sql));
44414 + if (0 == sqlite3_changes(p->conf.sql)) {
44415 + con->http_status = 401;
44417 + con->http_status = 204;
44419 + return HANDLER_FINISHED;
44421 + /* we need a lock-token to unlock */
44422 + con->http_status = 400;
44424 + return HANDLER_FINISHED;
44428 + con->http_status = 501;
44429 + return HANDLER_FINISHED;
44437 return HANDLER_GO_ON;
44439 @@ -1845,14 +2457,14 @@
44440 int mod_webdav_plugin_init(plugin *p) {
44441 p->version = LIGHTTPD_VERSION_ID;
44442 p->name = buffer_init_string("webdav");
44445 p->init = mod_webdav_init;
44446 p->handle_uri_clean = mod_webdav_uri_handler;
44447 p->handle_physical = mod_webdav_subrequest_handler;
44448 p->set_defaults = mod_webdav_set_defaults;
44449 p->cleanup = mod_webdav_free;
44457 --- ../lighttpd-1.4.11/src/network.c 2006-03-04 16:45:46.000000000 +0200
44458 +++ lighttpd-1.4.12/src/network.c 2006-07-18 13:03:40.000000000 +0300
44460 #include <sys/types.h>
44461 #include <sys/stat.h>
44462 -#include <sys/time.h>
44466 -#include <unistd.h>
44467 #include <string.h>
44468 #include <stdlib.h>
44469 #include <assert.h>
44471 +#include <stdio.h>
44473 #include "network.h"
44474 #include "fdevent.h"
44476 @@ -19,11 +19,12 @@
44477 #include "network_backends.h"
44478 #include "sys-mmap.h"
44479 #include "sys-socket.h"
44480 +#include "sys-files.h"
44483 -# include <openssl/ssl.h>
44484 -# include <openssl/err.h>
44485 -# include <openssl/rand.h>
44486 +# include <openssl/ssl.h>
44487 +# include <openssl/err.h>
44488 +# include <openssl/rand.h>
44491 handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
44492 @@ -31,25 +32,25 @@
44493 server_socket *srv_socket = (server_socket *)context;
44501 if (revents != FDEVENT_IN) {
44502 - log_error_write(srv, __FILE__, __LINE__, "sdd",
44503 + log_error_write(srv, __FILE__, __LINE__, "sdd",
44504 "strange event for server socket",
44506 + srv_socket->sock->fd,
44508 return HANDLER_ERROR;
44511 /* accept()s at most 100 connections directly
44513 - * we jump out after 100 to give the waiting connections a chance */
44514 + * we jump out after 100 to give the waiting connections a chance */
44515 for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
44519 connection_state_machine(srv, con);
44522 switch(r = plugins_call_handle_joblist(srv, con)) {
44523 case HANDLER_FINISHED:
44524 case HANDLER_GO_ON:
44525 @@ -72,18 +73,18 @@
44527 int is_unix_domain_socket = 0;
44531 #ifdef SO_ACCEPTFILTER
44532 struct accept_filter_arg afa;
44537 WORD wVersionRequested;
44542 wVersionRequested = MAKEWORD( 2, 2 );
44545 err = WSAStartup( wVersionRequested, &wsaData );
44547 /* Tell the user that we could not find a usable */
44548 @@ -91,37 +92,37 @@
44554 srv_socket = calloc(1, sizeof(*srv_socket));
44555 - srv_socket->fd = -1;
44557 + srv_socket->sock = iosocket_init();
44559 srv_socket->srv_token = buffer_init();
44560 buffer_copy_string_buffer(srv_socket->srv_token, host_token);
44564 buffer_copy_string_buffer(b, host_token);
44571 if (NULL == (sp = strrchr(b->ptr, ':'))) {
44572 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
44582 /* check for [ and ] */
44583 if (b->ptr[0] == '[' && *(sp-1) == ']') {
44595 port = strtol(sp, NULL, 10);
44597 if (host[0] == '/') {
44598 @@ -129,18 +130,18 @@
44599 is_unix_domain_socket = 1;
44600 } else if (port == 0 || port > 65535) {
44601 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
44608 if (*host == '\0') host = NULL;
44610 if (is_unix_domain_socket) {
44611 #ifdef HAVE_SYS_UN_H
44613 srv_socket->addr.plain.sa_family = AF_UNIX;
44615 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44617 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44618 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44621 @@ -154,32 +155,32 @@
44624 srv_socket->addr.plain.sa_family = AF_INET6;
44626 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44628 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44629 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44632 srv_socket->use_ipv6 = 1;
44636 - if (srv_socket->fd == -1) {
44638 + if (srv_socket->sock->fd == -1) {
44639 srv_socket->addr.plain.sa_family = AF_INET;
44640 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44641 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44642 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44649 - srv->cur_fds = srv_socket->fd;
44651 + srv->cur_fds = srv_socket->sock->fd;
44654 - if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44655 + if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44656 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
44661 switch(srv_socket->addr.plain.sa_family) {
44664 @@ -190,23 +191,23 @@
44666 struct addrinfo hints, *res;
44670 memset(&hints, 0, sizeof(hints));
44673 hints.ai_family = AF_INET6;
44674 hints.ai_socktype = SOCK_STREAM;
44675 hints.ai_protocol = IPPROTO_TCP;
44678 if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
44679 - log_error_write(srv, __FILE__, __LINE__,
44680 - "sssss", "getaddrinfo failed: ",
44681 + log_error_write(srv, __FILE__, __LINE__,
44682 + "sssss", "getaddrinfo failed: ",
44683 gai_strerror(r), "'", host, "'");
44690 memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
44695 srv_socket->addr.ipv6.sin6_port = htons(port);
44696 @@ -221,33 +222,34 @@
44698 struct hostent *he;
44699 if (NULL == (he = gethostbyname(host))) {
44700 - log_error_write(srv, __FILE__, __LINE__,
44701 - "sds", "gethostbyname failed: ",
44702 + log_error_write(srv, __FILE__, __LINE__,
44703 + "sds", "gethostbyname failed: ",
44709 if (he->h_addrtype != AF_INET) {
44710 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
44715 if (he->h_length != sizeof(struct in_addr)) {
44716 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
44721 memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
44723 srv_socket->addr.ipv4.sin_port = htons(port);
44726 addr_len = sizeof(struct sockaddr_in);
44732 srv_socket->addr.un.sun_family = AF_UNIX;
44733 strcpy(srv_socket->addr.un.sun_path, host);
44737 addr_len = SUN_LEN(&srv_socket->addr.un);
44739 @@ -256,11 +258,11 @@
44742 /* check if the socket exists and try to connect to it. */
44743 - if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44744 + if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44747 - log_error_write(srv, __FILE__, __LINE__, "ss",
44748 - "server socket is still in use:",
44749 + log_error_write(srv, __FILE__, __LINE__, "ss",
44750 + "server socket is still in use:",
44754 @@ -275,88 +277,89 @@
44758 - log_error_write(srv, __FILE__, __LINE__, "sds",
44759 - "testing socket failed:",
44760 + log_error_write(srv, __FILE__, __LINE__, "sds",
44761 + "testing socket failed:",
44762 host, strerror(errno));
44776 - if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44778 + if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44779 switch(srv_socket->addr.plain.sa_family) {
44781 - log_error_write(srv, __FILE__, __LINE__, "sds",
44782 - "can't bind to socket:",
44783 + log_error_write(srv, __FILE__, __LINE__, "sds",
44784 + "can't bind to socket:",
44785 host, strerror(errno));
44788 - log_error_write(srv, __FILE__, __LINE__, "ssds",
44789 - "can't bind to port:",
44790 + log_error_write(srv, __FILE__, __LINE__, "ssds",
44791 + "can't bind to port:",
44792 host, port, strerror(errno));
44798 - if (-1 == listen(srv_socket->fd, 128 * 8)) {
44800 + if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
44801 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
44808 if (srv->ssl_is_init == 0) {
44809 SSL_load_error_strings();
44810 SSL_library_init();
44811 srv->ssl_is_init = 1;
44814 if (0 == RAND_status()) {
44815 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44816 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44817 "not enough entropy in the pool");
44823 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
44824 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44825 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44826 ERR_error_string(ERR_get_error(), NULL));
44831 if (buffer_is_empty(s->ssl_pemfile)) {
44832 log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
44837 if (!buffer_is_empty(s->ssl_ca_file)) {
44838 if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
44839 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44840 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44841 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
44847 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44848 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44849 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44850 ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44855 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44856 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44857 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44858 ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44863 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
44864 - log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44865 + log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44866 "Private key does not match the certificate public key, reason:",
44867 ERR_error_string(ERR_get_error(), NULL),
44869 @@ -364,15 +367,15 @@
44871 srv_socket->ssl_ctx = s->ssl_ctx;
44875 buffer_free(srv_socket->srv_token);
44881 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44883 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44884 "ssl requested but openssl support is not compiled in");
44890 @@ -383,17 +386,16 @@
44892 memset(&afa, 0, sizeof(afa));
44893 strcpy(afa.af_name, "httpready");
44894 - if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44895 + if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44896 if (errno != ENOENT) {
44897 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
44904 srv_socket->is_ssl = s->is_ssl;
44905 - srv_socket->fde_ndx = -1;
44908 if (srv->srv_sockets.size == 0) {
44909 srv->srv_sockets.size = 4;
44910 srv->srv_sockets.used = 0;
44911 @@ -402,11 +404,10 @@
44912 srv->srv_sockets.size += 4;
44913 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
44917 srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
44925 @@ -414,45 +415,60 @@
44927 for (i = 0; i < srv->srv_sockets.used; i++) {
44928 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44930 - if (srv_socket->fd != -1) {
44932 + if (srv_socket->sock->fd != -1) {
44933 /* check if server fd are already registered */
44934 - if (srv_socket->fde_ndx != -1) {
44935 - fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
44936 - fdevent_unregister(srv->ev, srv_socket->fd);
44937 + if (srv_socket->sock->fde_ndx != -1) {
44938 + fdevent_event_del(srv->ev, srv_socket->sock);
44939 + fdevent_unregister(srv->ev, srv_socket->sock);
44942 - close(srv_socket->fd);
44944 + closesocket(srv_socket->sock->fd);
44947 + if (srv_socket->is_ssl) {
44948 +#ifdef USE_OPENSSL
44949 + SSL_CTX_free(srv_socket->ssl_ctx);
44954 + iosocket_free(srv_socket->sock);
44956 buffer_free(srv_socket->srv_token);
44963 +#ifdef USE_OPENSSL
44964 + ERR_free_strings();
44966 free(srv->srv_sockets.ptr);
44973 NETWORK_BACKEND_UNSET,
44975 NETWORK_BACKEND_WRITE,
44976 NETWORK_BACKEND_WRITEV,
44977 NETWORK_BACKEND_LINUX_SENDFILE,
44978 NETWORK_BACKEND_FREEBSD_SENDFILE,
44979 - NETWORK_BACKEND_SOLARIS_SENDFILEV
44980 + NETWORK_BACKEND_SOLARIS_SENDFILEV,
44982 + NETWORK_BACKEND_WIN32_SEND,
44983 + NETWORK_BACKEND_WIN32_TRANSMITFILE,
44984 } network_backend_t;
44986 int network_init(server *srv) {
44989 network_backend_t backend;
44992 - network_backend_t nb;
44993 - const char *name;
44994 - } network_backends[] = {
44997 + network_backend_t nb;
44998 + const char *name;
44999 + } network_backends[] = {
45000 /* lowest id wins */
45001 #if defined USE_LINUX_SENDFILE
45002 { NETWORK_BACKEND_LINUX_SENDFILE, "linux-sendfile" },
45003 @@ -466,21 +482,30 @@
45004 #if defined USE_WRITEV
45005 { NETWORK_BACKEND_WRITEV, "writev" },
45007 +#if defined USE_WRITE
45008 { NETWORK_BACKEND_WRITE, "write" },
45010 +#if defined USE_WIN32_TRANSMITFILE
45011 + { NETWORK_BACKEND_WIN32_TRANSMITFILE, "win32-transmitfile" },
45013 +#if defined USE_WIN32_SEND
45014 + { NETWORK_BACKEND_WIN32_SEND, "win32-send" },
45017 { NETWORK_BACKEND_UNSET, NULL }
45024 buffer_copy_string_buffer(b, srv->srvconf.bindhost);
45025 buffer_append_string(b, ":");
45026 buffer_append_long(b, srv->srvconf.port);
45029 if (0 != network_server_init(srv, b, srv->config_storage[0])) {
45036 srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
45038 @@ -500,54 +525,80 @@
45039 if (NULL == network_backends[i].name) {
45040 /* we don't know it */
45042 - log_error_write(srv, __FILE__, __LINE__, "sb",
45043 - "server.network-backend has a unknown value:",
45044 + log_error_write(srv, __FILE__, __LINE__, "sb",
45045 + "server.network-backend has a unknown value:",
45046 srv->srvconf.network_backend);
45052 +#define SET_NETWORK_BACKEND(read, write) \
45053 + srv->network_backend_write = network_write_chunkqueue_##write;\
45054 + srv->network_backend_read = network_read_chunkqueue_##read
45056 +#define SET_NETWORK_BACKEND_SSL(read, write) \
45057 + srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
45058 + srv->network_ssl_backend_read = network_read_chunkqueue_##read
45062 +#ifdef USE_WIN32_SEND
45063 + case NETWORK_BACKEND_WIN32_SEND:
45064 + SET_NETWORK_BACKEND(win32recv, win32send);
45066 +#ifdef USE_WIN32_TRANSMITFILE
45067 + case NETWORK_BACKEND_WIN32_TRANSMITFILE:
45068 + SET_NETWORK_BACKEND(win32recv, win32transmitfile);
45074 case NETWORK_BACKEND_WRITE:
45075 - srv->network_backend_write = network_write_chunkqueue_write;
45076 + SET_NETWORK_BACKEND(read, write);
45080 case NETWORK_BACKEND_WRITEV:
45081 - srv->network_backend_write = network_write_chunkqueue_writev;
45082 + SET_NETWORK_BACKEND(read, writev);
45085 #ifdef USE_LINUX_SENDFILE
45086 case NETWORK_BACKEND_LINUX_SENDFILE:
45087 - srv->network_backend_write = network_write_chunkqueue_linuxsendfile;
45088 + SET_NETWORK_BACKEND(read, linuxsendfile);
45091 #ifdef USE_FREEBSD_SENDFILE
45092 case NETWORK_BACKEND_FREEBSD_SENDFILE:
45093 - srv->network_backend_write = network_write_chunkqueue_freebsdsendfile;
45094 + SET_NETWORK_BACKEND(read, freebsdsendfile);
45097 #ifdef USE_SOLARIS_SENDFILEV
45098 case NETWORK_BACKEND_SOLARIS_SENDFILEV:
45099 - srv->network_backend_write = network_write_chunkqueue_solarissendfilev;
45100 + SET_NETWORK_BACKEND(read, solarissendfilev);
45107 +#ifdef USE_OPENSSL
45108 + SET_NETWORK_BACKEND_SSL(openssl, openssl);
45111 /* check for $SERVER["socket"] */
45112 for (i = 1; i < srv->config_context->used; i++) {
45113 data_config *dc = (data_config *)srv->config_context->data[i];
45114 specific_config *s = srv->config_storage[i];
45118 /* not our stage */
45119 if (COMP_SERVER_SOCKET != dc->comp) continue;
45122 if (dc->cond != CONFIG_COND_EQ) {
45123 log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
45129 @@ -558,36 +609,47 @@
45135 if (j == srv->srv_sockets.used) {
45136 if (0 != network_server_init(srv, dc->string, s)) return -1;
45144 int network_register_fdevents(server *srv) {
45147 if (-1 == fdevent_reset(srv->ev)) {
45151 /* register fdevents after reset */
45152 for (i = 0; i < srv->srv_sockets.used; i++) {
45153 server_socket *srv_socket = srv->srv_sockets.ptr[i];
45155 - fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
45156 - fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
45157 + fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
45158 + fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
45163 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45165 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45166 + server_socket *srv_socket = con->srv_socket;
45168 + if (srv_socket->is_ssl) {
45169 +#ifdef USE_OPENSSL
45170 + return srv->network_ssl_backend_read(srv, con, con->sock, cq);
45172 + return NETWORK_STATUS_FATAL_ERROR;
45175 + return srv->network_backend_read(srv, con, con->sock, cq);
45179 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
45180 + network_status_t ret = NETWORK_STATUS_UNSET;
45186 server_socket *srv_socket = con->srv_socket;
45187 @@ -600,37 +662,42 @@
45188 joblist_append(srv, con);
45194 written = cq->bytes_out;
45198 /* Linux: put a cork into the socket as we want to combine the write() calls
45199 * but only if we really have multiple chunks
45201 if (cq->first && cq->first->next) {
45203 - setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45204 + setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45209 if (srv_socket->is_ssl) {
45211 - ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
45212 + ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
45215 - ret = srv->network_backend_write(srv, con, con->fd, cq);
45216 + ret = srv->network_backend_write(srv, con, con->sock, cq);
45222 + case NETWORK_STATUS_WAIT_FOR_EVENT:
45223 + case NETWORK_STATUS_SUCCESS:
45224 chunkqueue_remove_finished_chunks(cq);
45225 - ret = chunkqueue_is_empty(cq) ? 0 : 1;
45236 - setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45237 + setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
45241 @@ -639,13 +706,13 @@
45242 con->bytes_written_cur_second += written;
45244 *(con->conf.global_bytes_per_second_cnt_ptr) += written;
45247 if (con->conf.kbytes_per_second &&
45248 (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
45249 /* we reached the traffic limit */
45251 con->traffic_limit_reached = 1;
45252 joblist_append(srv, con);
45257 --- ../lighttpd-1.4.11/src/network.h 2005-08-11 01:26:42.000000000 +0300
45258 +++ lighttpd-1.4.12/src/network.h 2006-07-18 13:03:40.000000000 +0300
45261 #include "server.h"
45263 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45264 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
45265 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *c);
45267 int network_init(server *srv);
45268 int network_close(server *srv);
45270 int network_register_fdevents(server *srv);
45271 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
45274 --- ../lighttpd-1.4.11/src/network_backends.h 2005-10-24 15:13:51.000000000 +0300
45275 +++ lighttpd-1.4.12/src/network_backends.h 2006-07-18 13:03:40.000000000 +0300
45276 @@ -43,16 +43,47 @@
45277 # define USE_AIX_SENDFILE
45281 +* unix can use read/write or recv/send on sockets
45282 +* win32 only recv/send
45285 +# define USE_WIN32_SEND
45286 +/* wait for async-io support
45287 +# define USE_WIN32_TRANSMITFILE
45290 +# define USE_WRITE
45294 +#include "network.h"
45296 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
45297 + network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
45299 +#define NETWORK_BACKEND_WRITE(x) \
45300 + network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45301 +#define NETWORK_BACKEND_READ(x) \
45302 + network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
45304 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
45306 +NETWORK_BACKEND_WRITE(write);
45307 +NETWORK_BACKEND_WRITE(writev);
45308 +NETWORK_BACKEND_WRITE(linuxsendfile);
45309 +NETWORK_BACKEND_WRITE(freebsdsendfile);
45310 +NETWORK_BACKEND_WRITE(solarissendfilev);
45312 +NETWORK_BACKEND_WRITE(win32transmitfile);
45313 +NETWORK_BACKEND_WRITE(win32send);
45315 +NETWORK_BACKEND_READ(read);
45316 +NETWORK_BACKEND_READ(win32recv);
45318 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
45319 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
45320 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45321 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
45322 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
45324 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
45325 +NETWORK_BACKEND_WRITE(openssl);
45326 +NETWORK_BACKEND_READ(openssl);
45330 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c 2005-10-22 12:28:18.000000000 +0300
45331 +++ lighttpd-1.4.12/src/network_freebsd_sendfile.c 2006-07-16 00:26:04.000000000 +0300
45332 @@ -26,142 +26,61 @@
45335 # ifdef __FreeBSD__
45336 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
45337 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
45338 # define UIO_MAXIOV 1024
45342 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45343 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
45345 size_t chunks_written = 0;
45348 for(c = cq->first; c; c = c->next, chunks_written++) {
45349 int chunk_finished = 0;
45351 + network_status_t ret;
45354 - case MEM_CHUNK: {
45359 - size_t num_chunks, i;
45360 - struct iovec chunks[UIO_MAXIOV];
45362 - size_t num_bytes = 0;
45364 - /* we can't send more then SSIZE_MAX bytes in one chunk */
45366 - /* build writev list
45368 - * 1. limit: num_chunks < UIO_MAXIOV
45369 - * 2. limit: num_bytes < SSIZE_MAX
45371 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45373 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45374 - if (tc->mem->used == 0) {
45375 - chunks[i].iov_base = tc->mem->ptr;
45376 - chunks[i].iov_len = 0;
45378 - offset = tc->mem->ptr + tc->offset;
45379 - toSend = tc->mem->used - 1 - tc->offset;
45381 - chunks[i].iov_base = offset;
45383 - /* protect the return value of writev() */
45384 - if (toSend > SSIZE_MAX ||
45385 - num_bytes + toSend > SSIZE_MAX) {
45386 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
45388 - num_chunks = i + 1;
45391 - chunks[i].iov_len = toSend;
45394 - num_bytes += toSend;
45398 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
45408 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45409 - "writev failed:", strerror(errno), fd);
45414 + ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
45419 - /* check which chunks have been written */
45420 - cq->bytes_out += r;
45422 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45423 - if (r >= (ssize_t)chunks[i].iov_len) {
45425 - r -= chunks[i].iov_len;
45426 - tc->offset += chunks[i].iov_len;
45428 - if (chunk_finished) {
45429 - /* skip the chunks from further touches */
45430 - chunks_written++;
45433 - /* chunks_written + c = c->next is done in the for()*/
45434 - chunk_finished++;
45437 - /* partially written */
45440 - chunk_finished = 0;
45444 + if (ret != NETWORK_STATUS_SUCCESS) {
45449 + chunk_finished = 1;
45456 stat_cache_entry *sce = NULL;
45460 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45461 log_error_write(srv, __FILE__, __LINE__, "sb",
45462 strerror(errno), c->file.name);
45464 + return NETWORK_STATUS_FATAL_ERROR;
45468 offset = c->file.start + c->offset;
45469 /* limit the toSend to 2^31-1 bytes in a chunk */
45470 - toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45471 + toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45472 ((1 << 30) - 1) : c->file.length - c->offset;
45475 if (offset > sce->st.st_size) {
45476 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45480 + return NETWORK_STATUS_FATAL_ERROR;
45484 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45485 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45489 + return NETWORK_STATUS_FATAL_ERROR;
45496 /* FreeBSD sendfile() */
45497 if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
45499 @@ -169,39 +88,39 @@
45504 + return NETWORK_STATUS_CONNECTION_CLOSE;
45506 log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
45509 + return NETWORK_STATUS_FATAL_ERROR;
45516 cq->bytes_out += r;
45519 if (c->offset == c->file.length) {
45520 chunk_finished = 1;
45529 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45536 if (!chunk_finished) {
45537 /* not finished yet */
45544 - return chunks_written;
45545 + return NETWORK_STATUS_SUCCESS;
45549 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c 2006-02-15 20:02:36.000000000 +0200
45550 +++ lighttpd-1.4.12/src/network_linux_sendfile.c 2006-07-18 13:03:40.000000000 +0300
45551 @@ -26,122 +26,54 @@
45552 /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
45553 #undef HAVE_POSIX_FADVISE
45555 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
45557 +NETWORK_BACKEND_WRITE(linuxsendfile) {
45559 size_t chunks_written = 0;
45562 for(c = cq->first; c; c = c->next, chunks_written++) {
45563 int chunk_finished = 0;
45565 + network_status_t ret;
45568 - case MEM_CHUNK: {
45573 - size_t num_chunks, i;
45574 - struct iovec chunks[UIO_MAXIOV];
45576 - size_t num_bytes = 0;
45578 - /* we can't send more then SSIZE_MAX bytes in one chunk */
45580 - /* build writev list
45582 - * 1. limit: num_chunks < UIO_MAXIOV
45583 - * 2. limit: num_bytes < SSIZE_MAX
45585 - for (num_chunks = 0, tc = c;
45586 - tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV;
45587 - tc = tc->next, num_chunks++);
45589 - for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45590 - if (tc->mem->used == 0) {
45591 - chunks[i].iov_base = tc->mem->ptr;
45592 - chunks[i].iov_len = 0;
45594 - offset = tc->mem->ptr + tc->offset;
45595 - toSend = tc->mem->used - 1 - tc->offset;
45597 - chunks[i].iov_base = offset;
45599 - /* protect the return value of writev() */
45600 - if (toSend > SSIZE_MAX ||
45601 - num_bytes + toSend > SSIZE_MAX) {
45602 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
45604 - num_chunks = i + 1;
45607 - chunks[i].iov_len = toSend;
45610 - num_bytes += toSend;
45614 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
45624 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45625 - "writev failed:", strerror(errno), fd);
45631 - /* check which chunks have been written */
45632 - cq->bytes_out += r;
45634 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
45636 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45637 - if (r >= (ssize_t)chunks[i].iov_len) {
45639 - r -= chunks[i].iov_len;
45640 - tc->offset += chunks[i].iov_len;
45642 + /* check which chunks are finished now */
45643 + for (tc = c; tc; tc = tc->next) {
45644 + /* finished the chunk */
45645 + if (tc->offset == tc->mem->used - 1) {
45646 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
45647 if (chunk_finished) {
45648 - /* skip the chunks from further touches */
45649 - chunks_written++;
45652 - /* chunks_written + c = c->next is done in the for()*/
45653 - chunk_finished++;
45654 + chunk_finished = 1;
45657 - /* partially written */
45660 - chunk_finished = 0;
45667 + if (ret != NETWORK_STATUS_SUCCESS) {
45677 stat_cache_entry *sce = NULL;
45680 offset = c->file.start + c->offset;
45681 /* limit the toSend to 2^31-1 bytes in a chunk */
45682 - toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45683 + toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45684 ((1 << 30) - 1) : c->file.length - c->offset;
45686 - /* open file if not already opened */
45688 + /* open file if not already opened */
45689 if (-1 == c->file.fd) {
45690 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
45691 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45697 @@ -151,14 +83,14 @@
45698 /* tell the kernel that we want to stream the file */
45699 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
45700 if (ENOSYS != errno) {
45701 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45702 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45703 "posix_fadvise failed:", strerror(errno), c->file.fd);
45709 - if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
45710 + if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
45714 @@ -166,11 +98,11 @@
45719 + return NETWORK_STATUS_CONNECTION_CLOSE;
45721 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45722 - "sendfile failed:", strerror(errno), fd);
45724 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45725 + "sendfile failed:", strerror(errno), sock->fd);
45726 + return NETWORK_STATUS_FATAL_ERROR;
45730 @@ -179,39 +111,39 @@
45732 * - the file shrinked -> error
45733 * - the remote side closed inbetween -> remote-close */
45736 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45737 /* file is gone ? */
45739 + return NETWORK_STATUS_FATAL_ERROR;
45742 if (offset > sce->st.st_size) {
45743 /* file shrinked, close the connection */
45745 + return NETWORK_STATUS_FATAL_ERROR;
45749 + return NETWORK_STATUS_CONNECTION_CLOSE;
45752 #ifdef HAVE_POSIX_FADVISE
45755 -#define M * 1024 K
45756 +#define M * 1024 K
45757 #define READ_AHEAD 4 M
45758 /* check if we need a new chunk */
45759 if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
45760 /* tell the kernel that we want to stream the file */
45761 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
45762 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45763 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45764 "posix_fadvise failed:", strerror(errno), c->file.fd);
45772 cq->bytes_out += r;
45775 if (c->offset == c->file.length) {
45776 chunk_finished = 1;
45778 @@ -222,24 +154,24 @@
45789 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45793 + return NETWORK_STATUS_FATAL_ERROR;
45797 if (!chunk_finished) {
45798 /* not finished yet */
45802 + return NETWORK_STATUS_WAIT_FOR_EVENT;
45806 - return chunks_written;
45807 + return NETWORK_STATUS_SUCCESS;
45811 --- ../lighttpd-1.4.11/src/network_openssl.c 2005-11-17 14:53:29.000000000 +0200
45812 +++ lighttpd-1.4.12/src/network_openssl.c 2006-07-18 13:03:40.000000000 +0300
45813 @@ -23,17 +23,87 @@
45815 #include "stat_cache.h"
45817 -# include <openssl/ssl.h>
45818 -# include <openssl/err.h>
45819 +# include <openssl/ssl.h>
45820 +# include <openssl/err.h>
45822 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
45823 +NETWORK_BACKEND_READ(openssl) {
45827 + b = chunkqueue_get_append_buffer(cq);
45828 + buffer_prepare_copy(b, 8192);
45829 + len = SSL_read(sock->ssl, b->ptr, b->size - 1);
45831 + log_error_write(srv, __FILE__, __LINE__, "so", "SSL:", len);
45836 + switch ((r = SSL_get_error(sock->ssl, len))) {
45837 + case SSL_ERROR_WANT_READ:
45838 + return NETWORK_STATUS_WAIT_FOR_EVENT;
45839 + case SSL_ERROR_SYSCALL:
45841 + * man SSL_get_error()
45843 + * SSL_ERROR_SYSCALL
45844 + * Some I/O error occurred. The OpenSSL error queue may contain more
45845 + * information on the error. If the error queue is empty (i.e.
45846 + * ERR_get_error() returns 0), ret can be used to find out more about
45847 + * the error: If ret == 0, an EOF was observed that violates the
45848 + * protocol. If ret == -1, the underlying BIO reported an I/O error
45849 + * (for socket I/O on Unix systems, consult errno for details).
45852 + while((ssl_err = ERR_get_error())) {
45853 + /* get all errors from the error-queue */
45854 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45855 + r, ERR_error_string(ssl_err, NULL));
45860 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45862 + strerror(errno));
45867 + case SSL_ERROR_ZERO_RETURN:
45868 + /* clean shutdown on the remote side */
45871 + /* FIXME: later */
45874 + /* fall thourgh */
45876 + while((ssl_err = ERR_get_error())) {
45877 + /* get all errors from the error-queue */
45878 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45879 + r, ERR_error_string(ssl_err, NULL));
45887 + b->ptr[b->used - 1] = '\0';
45889 + return NETWORK_STATUS_SUCCESS;
45893 +NETWORK_BACKEND_WRITE(openssl) {
45896 size_t chunks_written = 0;
45898 /* this is a 64k sendbuffer
45900 - * it has to stay at the same location all the time to satisfy the needs
45901 + * it has to stay at the same location all the time to satisfy the needs
45902 * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
45904 * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
45905 @@ -43,59 +113,61 @@
45906 * In reality we would like to use mmap() but we don't have a guarantee that
45907 * we get the same mmap() address for each call. On openbsd the mmap() address
45909 - * That means either we keep the mmap() open or we do a read() into a
45910 - * constant buffer
45911 + * That means either we keep the mmap() open or we do a read() into a
45912 + * constant buffer
45914 #define LOCAL_SEND_BUFSIZE (64 * 1024)
45915 static char *local_send_buffer = NULL;
45917 /* the remote side closed the connection before without shutdown request
45921 * if keep-alive is disabled */
45923 if (con->keep_alive == 0) {
45924 - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
45925 + SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
45928 for(c = cq->first; c; c = c->next) {
45929 int chunk_finished = 0;
45940 if (c->mem->used == 0) {
45941 chunk_finished = 1;
45946 offset = c->mem->ptr + c->offset;
45947 toSend = c->mem->used - 1 - c->offset;
45951 * SSL_write man-page
45955 * When an SSL_write() operation has to be repeated because of
45956 * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
45957 * repeated with the same arguments.
45960 + * SSL_write(..., 0) return 0 which is handle as an error (Success)
45961 + * checking toSend and not calling SSL_write() is simpler
45964 - if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
45966 + if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
45969 - switch ((ssl_r = SSL_get_error(ssl, r))) {
45970 + switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45971 case SSL_ERROR_WANT_WRITE:
45973 case SSL_ERROR_SYSCALL:
45974 /* perhaps we have error waiting in our error-queue */
45975 if (0 != (err = ERR_get_error())) {
45977 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45978 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45980 ERR_error_string(err, NULL));
45981 } while((err = ERR_get_error()));
45982 @@ -105,43 +177,43 @@
45986 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45987 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45993 /* neither error-queue nor errno ? */
45994 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45995 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
46002 case SSL_ERROR_ZERO_RETURN:
46003 /* clean shutdown on the remote side */
46006 if (r == 0) return -2;
46011 while((err = ERR_get_error())) {
46012 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46013 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46015 ERR_error_string(err, NULL));
46023 cq->bytes_out += r;
46027 if (c->offset == (off_t)c->mem->used - 1) {
46028 chunk_finished = 1;
46035 @@ -150,7 +222,7 @@
46036 stat_cache_entry *sce = NULL;
46038 int write_wait = 0;
46041 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46042 log_error_write(srv, __FILE__, __LINE__, "sb",
46043 strerror(errno), c->file.name);
46044 @@ -164,13 +236,13 @@
46047 off_t offset = c->file.start + c->offset;
46048 - off_t toSend = c->file.length - c->offset;
46049 + off_t toSend = c->file.length - c->offset;
46051 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
46054 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46055 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
46061 @@ -183,13 +255,13 @@
46064 s = local_send_buffer;
46069 - if ((r = SSL_write(ssl, s, toSend)) <= 0) {
46071 + if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
46074 - switch ((ssl_r = SSL_get_error(ssl, r))) {
46075 + switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
46076 case SSL_ERROR_WANT_WRITE:
46079 @@ -197,7 +269,7 @@
46080 /* perhaps we have error waiting in our error-queue */
46081 if (0 != (err = ERR_get_error())) {
46083 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46084 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46086 ERR_error_string(err, NULL));
46087 } while((err = ERR_get_error()));
46088 @@ -207,62 +279,62 @@
46092 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
46093 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
46099 /* neither error-queue nor errno ? */
46100 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
46101 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
46108 case SSL_ERROR_ZERO_RETURN:
46109 /* clean shutdown on the remote side */
46112 if (r == 0) return -2;
46117 while((err = ERR_get_error())) {
46118 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46119 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
46121 ERR_error_string(err, NULL));
46129 cq->bytes_out += r;
46133 if (c->offset == c->file.length) {
46134 chunk_finished = 1;
46136 } while(!chunk_finished && !write_wait);
46142 log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
46149 if (!chunk_finished) {
46150 /* not finished yet */
46160 - return chunks_written;
46161 + return NETWORK_STATUS_SUCCESS;
46165 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c 2005-10-22 12:28:27.000000000 +0300
46166 +++ lighttpd-1.4.12/src/network_solaris_sendfilev.c 2006-07-16 00:26:04.000000000 +0300
46167 @@ -29,114 +29,34 @@
46171 - * a very simple sendfilev() interface for solaris which can be optimised a lot more
46172 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
46173 * as solaris sendfilev() supports 'sending everythin in one syscall()'
46175 - * If you want such an interface and need the performance, just give me an account on
46178 + * If you want such an interface and need the performance, just give me an account on
46180 * - jan@kneschke.de
46184 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
46185 +NETWORK_BACKEND_WRITE(solarissendfilev) {
46187 size_t chunks_written = 0;
46190 for(c = cq->first; c; c = c->next, chunks_written++) {
46191 int chunk_finished = 0;
46193 + network_status_t ret;
46196 - case MEM_CHUNK: {
46201 - size_t num_chunks, i;
46202 - struct iovec chunks[UIO_MAXIOV];
46205 - size_t num_bytes = 0;
46207 - /* we can't send more then SSIZE_MAX bytes in one chunk */
46209 - /* build writev list
46211 - * 1. limit: num_chunks < UIO_MAXIOV
46212 - * 2. limit: num_bytes < SSIZE_MAX
46214 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46216 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46217 - if (tc->mem->used == 0) {
46218 - chunks[i].iov_base = tc->mem->ptr;
46219 - chunks[i].iov_len = 0;
46221 - offset = tc->mem->ptr + tc->offset;
46222 - toSend = tc->mem->used - 1 - tc->offset;
46224 - chunks[i].iov_base = offset;
46226 - /* protect the return value of writev() */
46227 - if (toSend > SSIZE_MAX ||
46228 - num_bytes + toSend > SSIZE_MAX) {
46229 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
46231 - num_chunks = i + 1;
46234 - chunks[i].iov_len = toSend;
46237 - num_bytes += toSend;
46241 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
46251 - log_error_write(srv, __FILE__, __LINE__, "ssd",
46252 - "writev failed:", strerror(errno), fd);
46258 - /* check which chunks have been written */
46259 - cq->bytes_out += r;
46261 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46262 - if (r >= (ssize_t)chunks[i].iov_len) {
46264 - r -= chunks[i].iov_len;
46265 - tc->offset += chunks[i].iov_len;
46267 - if (chunk_finished) {
46268 - /* skip the chunks from further touches */
46269 - chunks_written++;
46272 - /* chunks_written + c = c->next is done in the for()*/
46273 - chunk_finished++;
46276 - /* partially written */
46279 - chunk_finished = 0;
46284 + ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
46286 + if (ret != NETWORK_STATUS_SUCCESS) {
46291 + chunk_finished = 1;
46298 @@ -144,25 +64,25 @@
46299 sendfilevec_t fvec;
46300 stat_cache_entry *sce = NULL;
46304 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46305 log_error_write(srv, __FILE__, __LINE__, "sb",
46306 strerror(errno), c->file.name);
46311 offset = c->file.start + c->offset;
46312 toSend = c->file.length - c->offset;
46315 if (offset > sce->st.st_size) {
46316 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46322 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46323 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46329 @@ -170,44 +90,43 @@
46331 fvec.sfv_off = offset;
46332 fvec.sfv_len = toSend;
46335 /* Solaris sendfilev() */
46336 if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
46337 if (errno != EAGAIN) {
46338 log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
46343 + return NETWORK_STATUS_FATAL_ERROR;
46352 c->offset += written;
46353 cq->bytes_out += written;
46356 if (c->offset == c->file.length) {
46357 chunk_finished = 1;
46365 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46369 + return NETWORK_STATUS_FATAL_ERROR;
46373 if (!chunk_finished) {
46374 /* not finished yet */
46381 - return chunks_written;
46382 + return NETWORK_STATUS_SUCCESS;
46386 --- ../lighttpd-1.4.11/src/network_write.c 2005-10-22 12:27:56.000000000 +0300
46387 +++ lighttpd-1.4.12/src/network_write.c 2006-07-18 13:03:40.000000000 +0300
46389 #include <sys/types.h>
46390 #include <sys/stat.h>
46391 -#include <sys/time.h>
46395 -#include <unistd.h>
46396 #include <string.h>
46397 #include <stdlib.h>
46398 +#include <assert.h>
46400 #include "network.h"
46401 #include "fdevent.h"
46403 #include "stat_cache.h"
46405 #include "sys-socket.h"
46406 +#include "sys-files.h"
46408 #include "network_backends.h"
46412 #ifdef HAVE_SYS_FILIO_H
46413 # include <sys/filio.h>
46415 @@ -24,47 +27,92 @@
46416 #include <sys/resource.h>
46419 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
46422 +* fill the chunkqueue will all the data that we can get
46424 +* this might be optimized into a readv() which uses the chunks
46427 +NETWORK_BACKEND_READ(read) {
46433 + * a EAGAIN is a successful read if we already read something to the chunkqueue
46435 + int read_something = 0;
46437 + /* use a chunk-size of 8k */
46441 + b = chunkqueue_get_append_buffer(cq);
46443 + buffer_prepare_copy(b, toread);
46445 + if (-1 == (r = read(sock->fd, b->ptr, toread))) {
46448 + /* remove the last chunk from the chunkqueue */
46449 + chunkqueue_remove_empty_last_chunk(cq);
46450 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
46452 + ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
46454 + return NETWORK_STATUS_FATAL_ERROR;
46459 + chunkqueue_remove_empty_last_chunk(cq);
46460 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
46463 + read_something = 1;
46466 + b->ptr[b->used++] = '\0';
46467 + } while (r == toread);
46469 + return NETWORK_STATUS_SUCCESS;
46472 +NETWORK_BACKEND_WRITE(write) {
46474 size_t chunks_written = 0;
46477 for(c = cq->first; c; c = c->next) {
46478 int chunk_finished = 0;
46488 if (c->mem->used == 0) {
46489 chunk_finished = 1;
46494 offset = c->mem->ptr + c->offset;
46495 toSend = c->mem->used - 1 - c->offset;
46497 - if ((r = send(fd, offset, toSend, 0)) < 0) {
46498 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46503 - if ((r = write(fd, offset, toSend)) < 0) {
46504 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
46508 + if ((r = write(sock->fd, offset, toSend)) < 0) {
46509 + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
46511 + return NETWORK_STATUS_FATAL_ERROR;
46517 cq->bytes_out += r;
46520 if (c->offset == (off_t)c->mem->used - 1) {
46521 chunk_finished = 1;
46528 @@ -76,93 +124,89 @@
46530 stat_cache_entry *sce = NULL;
46534 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46535 log_error_write(srv, __FILE__, __LINE__, "sb",
46536 strerror(errno), c->file.name);
46538 + return NETWORK_STATUS_FATAL_ERROR;
46542 offset = c->file.start + c->offset;
46543 toSend = c->file.length - c->offset;
46546 if (offset > sce->st.st_size) {
46547 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
46551 + return NETWORK_STATUS_FATAL_ERROR;
46554 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
46555 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
46559 + return NETWORK_STATUS_FATAL_ERROR;
46563 #if defined USE_MMAP
46564 if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
46565 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
46571 + return NETWORK_STATUS_FATAL_ERROR;
46575 - if ((r = write(fd, p + offset, toSend)) <= 0) {
46576 + if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
46577 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
46578 munmap(p, sce->st.st_size);
46580 + return NETWORK_STATUS_FATAL_ERROR;
46584 munmap(p, sce->st.st_size);
46586 buffer_prepare_copy(srv->tmp_buf, toSend);
46589 lseek(ifd, offset, SEEK_SET);
46590 if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
46591 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
46596 + return NETWORK_STATUS_FATAL_ERROR;
46600 - if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
46601 + if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
46602 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
46606 + return NETWORK_STATUS_FATAL_ERROR;
46610 cq->bytes_out += r;
46613 if (c->offset == c->file.length) {
46614 chunk_finished = 1;
46623 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46627 + return NETWORK_STATUS_FATAL_ERROR;
46631 if (!chunk_finished) {
46632 /* not finished yet */
46642 - return chunks_written;
46643 + return NETWORK_STATUS_SUCCESS;
46647 -network_write_init(void) {
46648 - p->write = network_write_write_chunkset;
46651 --- ../lighttpd-1.4.11/src/network_writev.c 2006-02-15 01:02:36.000000000 +0200
46652 +++ lighttpd-1.4.12/src/network_writev.c 2006-07-18 13:03:40.000000000 +0300
46653 @@ -28,10 +28,10 @@
46656 # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
46657 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46658 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46659 # define UIO_MAXIOV 1024
46660 # elif defined(__sgi)
46661 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46662 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46663 # define UIO_MAXIOV 512
46664 # elif defined(__sun)
46665 /* Solaris (and SunOS?) defines IOV_MAX instead */
46666 @@ -51,105 +51,121 @@
46667 #define LOCAL_BUFFERING 1
46670 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
46672 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
46677 + size_t num_chunks, i;
46678 + struct iovec chunks[UIO_MAXIOV];
46679 + chunk *tc; /* transfer chunks */
46680 + size_t num_bytes = 0;
46682 + /* we can't send more then SSIZE_MAX bytes in one chunk */
46684 + /* build writev list
46686 + * 1. limit: num_chunks < UIO_MAXIOV
46687 + * 2. limit: num_bytes < SSIZE_MAX
46689 + for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46691 + for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46692 + if (tc->mem->used == 0) {
46693 + chunks[i].iov_base = tc->mem->ptr;
46694 + chunks[i].iov_len = 0;
46696 + offset = tc->mem->ptr + tc->offset;
46697 + toSend = tc->mem->used - 1 - tc->offset;
46699 + chunks[i].iov_base = offset;
46701 + /* protect the return value of writev() */
46702 + if (toSend > SSIZE_MAX ||
46703 + num_bytes + toSend > SSIZE_MAX) {
46704 + chunks[i].iov_len = SSIZE_MAX - num_bytes;
46706 + num_chunks = i + 1;
46709 + chunks[i].iov_len = toSend;
46712 + num_bytes += toSend;
46716 + if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
46719 + return NETWORK_STATUS_WAIT_FOR_EVENT;
46721 + return NETWORK_STATUS_INTERRUPTED;
46724 + return NETWORK_STATUS_CONNECTION_CLOSE;
46726 + log_error_write(srv, __FILE__, __LINE__, "ssd",
46727 + "writev failed:", strerror(errno), sock->fd);
46729 + return NETWORK_STATUS_FATAL_ERROR;
46733 + cq->bytes_out += r;
46735 + /* check which chunks have been written */
46737 + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46738 + if (r >= (ssize_t)chunks[i].iov_len) {
46740 + r -= chunks[i].iov_len;
46741 + tc->offset += chunks[i].iov_len;
46743 + /* partially written */
46747 + return NETWORK_STATUS_WAIT_FOR_EVENT;
46751 + /* all chunks have been pushed out */
46752 + return NETWORK_STATUS_SUCCESS;
46755 +NETWORK_BACKEND_WRITE(writev) {
46757 size_t chunks_written = 0;
46760 for(c = cq->first; c; c = c->next) {
46761 int chunk_finished = 0;
46763 + network_status_t ret;
46766 - case MEM_CHUNK: {
46771 - size_t num_chunks, i;
46772 - struct iovec chunks[UIO_MAXIOV];
46774 - size_t num_bytes = 0;
46776 - /* we can't send more then SSIZE_MAX bytes in one chunk */
46778 - /* build writev list
46780 - * 1. limit: num_chunks < UIO_MAXIOV
46781 - * 2. limit: num_bytes < SSIZE_MAX
46783 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46785 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46786 - if (tc->mem->used == 0) {
46787 - chunks[i].iov_base = tc->mem->ptr;
46788 - chunks[i].iov_len = 0;
46790 - offset = tc->mem->ptr + tc->offset;
46791 - toSend = tc->mem->used - 1 - tc->offset;
46793 - chunks[i].iov_base = offset;
46795 - /* protect the return value of writev() */
46796 - if (toSend > SSIZE_MAX ||
46797 - num_bytes + toSend > SSIZE_MAX) {
46798 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
46800 - num_chunks = i + 1;
46803 - chunks[i].iov_len = toSend;
46806 - num_bytes += toSend;
46810 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
46820 - log_error_write(srv, __FILE__, __LINE__, "ssd",
46821 - "writev failed:", strerror(errno), fd);
46827 - cq->bytes_out += r;
46829 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
46831 - /* check which chunks have been written */
46833 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46834 - if (r >= (ssize_t)chunks[i].iov_len) {
46836 - r -= chunks[i].iov_len;
46837 - tc->offset += chunks[i].iov_len;
46839 + /* check which chunks are finished now */
46840 + for (tc = c; tc; tc = tc->next) {
46841 + /* finished the chunk */
46842 + if (tc->offset == tc->mem->used - 1) {
46843 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
46844 if (chunk_finished) {
46845 - /* skip the chunks from further touches */
46846 - chunks_written++;
46849 - /* chunks_written + c = c->next is done in the for()*/
46850 - chunk_finished++;
46851 + chunk_finished = 1;
46854 - /* partially written */
46857 - chunk_finished = 0;
46864 + if (ret != NETWORK_STATUS_SUCCESS) {
46873 @@ -159,26 +175,26 @@
46874 #define KByte * 1024
46875 #define MByte * 1024 KByte
46876 #define GByte * 1024 MByte
46877 - const off_t we_want_to_mmap = 512 KByte;
46878 + const off_t we_want_to_mmap = 512 KByte;
46879 char *start = NULL;
46881 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46882 log_error_write(srv, __FILE__, __LINE__, "sb",
46883 strerror(errno), c->file.name);
46885 + return NETWORK_STATUS_FATAL_ERROR;
46888 abs_offset = c->file.start + c->offset;
46891 if (abs_offset > sce->st.st_size) {
46892 - log_error_write(srv, __FILE__, __LINE__, "sb",
46893 + log_error_write(srv, __FILE__, __LINE__, "sb",
46894 "file was shrinked:", c->file.name);
46898 + return NETWORK_STATUS_FATAL_ERROR;
46901 - /* mmap the buffer
46903 + /* mmap the buffer
46905 * - new mmap as the we are at the end of the last one */
46906 if (c->file.mmap.start == MAP_FAILED ||
46907 abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
46908 @@ -188,7 +204,7 @@
46909 * adaptive mem-mapping
46911 * we mmap() the whole file. If someone has alot large files and 32bit
46912 - * machine the virtual address area will be unrun and we will have a failing
46913 + * machine the virtual address area will be unrun and we will have a failing
46916 * only mmap 16M in one chunk and move the window as soon as we have finished
46917 @@ -234,8 +250,8 @@
46918 if (-1 == c->file.fd) { /* open the file if not already open */
46919 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
46920 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
46924 + return NETWORK_STATUS_FATAL_ERROR;
46927 fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
46928 @@ -245,10 +261,10 @@
46929 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
46930 /* close it here, otherwise we'd have to set FD_CLOEXEC */
46932 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46933 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46934 strerror(errno), c->file.name, c->file.fd);
46937 + return NETWORK_STATUS_FATAL_ERROR;
46940 c->file.mmap.length = to_mmap;
46941 @@ -258,7 +274,7 @@
46942 #ifdef HAVE_MADVISE
46943 /* don't advise files < 64Kb */
46944 if (c->file.mmap.length > (64 KByte)) {
46945 - /* darwin 7 is returning EINVAL all the time and I don't know how to
46946 + /* darwin 7 is returning EINVAL all the time and I don't know how to
46947 * detect this at runtime.i
46949 * ignore the return value for now */
46950 @@ -274,12 +290,12 @@
46951 toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
46954 - log_error_write(srv, __FILE__, __LINE__, "soooo",
46955 + log_error_write(srv, __FILE__, __LINE__, "soooo",
46956 "toSend is negative:",
46958 c->file.mmap.length,
46960 - c->file.mmap.offset);
46961 + c->file.mmap.offset);
46962 assert(toSend < 0);
46965 @@ -289,7 +305,7 @@
46966 start = c->file.mmap.start;
46969 - if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46970 + if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46974 @@ -297,18 +313,18 @@
46979 + return NETWORK_STATUS_CONNECTION_CLOSE;
46981 - log_error_write(srv, __FILE__, __LINE__, "ssd",
46982 - "write failed:", strerror(errno), fd);
46985 + log_error_write(srv, __FILE__, __LINE__, "ssd",
46986 + "write failed:", strerror(errno), sock->fd);
46988 + return NETWORK_STATUS_FATAL_ERROR;
46994 cq->bytes_out += r;
46997 if (c->offset == c->file.length) {
46998 chunk_finished = 1;
47000 @@ -318,26 +334,26 @@
47001 c->file.mmap.start = MAP_FAILED;
47011 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
47015 + return NETWORK_STATUS_FATAL_ERROR;
47019 if (!chunk_finished) {
47020 /* not finished yet */
47030 - return chunks_written;
47031 + return NETWORK_STATUS_SUCCESS;
47035 --- ../lighttpd-1.4.11/src/plugin.c 2006-02-08 14:00:54.000000000 +0200
47036 +++ lighttpd-1.4.12/src/plugin.c 2006-07-16 00:26:04.000000000 +0300
47037 @@ -13,27 +13,27 @@
47038 #include <valgrind/valgrind.h>
47048 * if you change this enum to add a new callback, be sure
47049 * - that PLUGIN_FUNC_SIZEOF is the last entry
47050 * - that you add PLUGIN_TO_SLOT twice:
47051 - * 1. as callback-dispatcher
47052 + * 1. as callback-dispatcher
47053 * 2. in plugins_call_init()
47065 - PLUGIN_FUNC_HANDLE_URI_CLEAN,
47066 - PLUGIN_FUNC_HANDLE_URI_RAW,
47067 + PLUGIN_FUNC_HANDLE_URI_CLEAN,
47068 + PLUGIN_FUNC_HANDLE_URI_RAW,
47069 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
47070 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
47071 PLUGIN_FUNC_HANDLE_TRIGGER,
47072 @@ -44,38 +44,42 @@
47073 PLUGIN_FUNC_HANDLE_DOCROOT,
47074 PLUGIN_FUNC_HANDLE_PHYSICAL,
47075 PLUGIN_FUNC_CONNECTION_RESET,
47076 - PLUGIN_FUNC_INIT,
47077 + PLUGIN_FUNC_INIT,
47078 PLUGIN_FUNC_CLEANUP,
47079 PLUGIN_FUNC_SET_DEFAULTS,
47085 static plugin *plugin_init(void) {
47089 p = calloc(1, sizeof(*p));
47092 + p->required_plugins = array_init();
47097 static void plugin_free(plugin *p) {
47098 int use_dlclose = 1;
47099 if (p->name) buffer_free(p->name);
47101 + array_free(p->required_plugins);
47102 #ifdef HAVE_VALGRIND_VALGRIND_H
47103 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
47106 #ifndef LIGHTTPD_STATIC
47107 - if (use_dlclose && p->lib) {
47109 + if (use_dlclose && p->lib) {
47111 FreeLibrary(p->lib);
47122 @@ -89,17 +93,17 @@
47123 srv->plugins.size += 4;
47124 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
47128 ps = srv->plugins.ptr;
47129 ps[srv->plugins.used++] = p;
47144 #ifdef LIGHTTPD_STATIC
47145 @@ -121,30 +125,35 @@
47147 int plugins_load(server *srv) {
47152 int (*init)(plugin *pl);
47160 for (i = 0; i < srv->srvconf.modules->used; i++) {
47161 data_string *d = (data_string *)srv->srvconf.modules->data[i];
47162 char *modules = d->value->ptr;
47165 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
47167 buffer_append_string(srv->tmp_buf, "/");
47168 buffer_append_string(srv->tmp_buf, modules);
47169 -#if defined(__WIN32) || defined(__CYGWIN__)
47170 +#if defined(_WIN32) || defined(__CYGWIN__)
47171 buffer_append_string(srv->tmp_buf, ".dll");
47173 buffer_append_string(srv->tmp_buf, ".so");
47180 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
47183 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
47184 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
47185 FORMAT_MESSAGE_FROM_SYSTEM,
47188 @@ -152,36 +161,36 @@
47189 (LPTSTR) &lpMsgBuf,
47192 - log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
47193 + log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
47194 lpMsgBuf, srv->tmp_buf);
47205 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
47206 - log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
47207 + log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
47208 srv->tmp_buf, dlerror());
47219 buffer_reset(srv->tmp_buf);
47220 buffer_copy_string(srv->tmp_buf, modules);
47221 buffer_append_string(srv->tmp_buf, "_plugin_init");
47225 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
47227 if (init == NULL) {
47230 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
47231 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
47232 FORMAT_MESSAGE_FROM_SYSTEM,
47235 @@ -190,7 +199,7 @@
47238 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
47244 @@ -203,24 +212,43 @@
47246 if ((error = dlerror()) != NULL) {
47247 log_error_write(srv, __FILE__, __LINE__, "s", error);
47257 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
47264 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
47266 + /* check if the required plugin is loaded */
47267 + for (k = 0; k < p->required_plugins->used; k++) {
47268 + data_string *req = (data_string *)p->required_plugins->data[k];
47270 + for (j = 0; j < i; j++) {
47271 + data_string *mod = (data_string *)srv->srvconf.modules->data[j];
47273 + if (buffer_is_equal(req->value, mod->value)) break;
47278 + log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
47285 plugins_register(srv, p);
47292 @@ -253,8 +281,8 @@
47296 - * plugins that use
47298 + * plugins that use
47301 * - connection *con
47302 * - void *p_d (plugin_data *)
47303 @@ -301,12 +329,12 @@
47307 - * plugins that use
47309 + * plugins that use
47312 * - void *p_d (plugin_data *)
47316 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
47317 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
47318 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
47319 @@ -314,18 +342,18 @@
47321 #undef PLUGIN_TO_SLOT
47332 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
47337 ps = srv->plugins.ptr;
47340 for (i = 0; i < srv->plugins.used; i++) {
47342 if (p->handle_fdevent) {
47343 @@ -344,34 +372,34 @@
47349 return HANDLER_GO_ON;
47355 * - call init function of all plugins to init the plugin-internals
47356 * - added each plugin that supports has callback to the corresponding slot
47359 * - is only called once.
47362 handler_t plugins_call_init(server *srv) {
47367 ps = srv->plugins.ptr;
47373 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
47376 for (i = 0; i < srv->plugins.used; i++) {
47378 /* check which calls are supported */
47384 #define PLUGIN_TO_SLOT(x, y) \
47386 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
47387 @@ -384,11 +412,11 @@
47394 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
47395 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
47399 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
47400 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
47401 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
47402 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
47403 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
47404 @@ -402,19 +430,19 @@
47405 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
47406 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
47407 #undef PLUGIN_TO_SLOT
47411 if (NULL == (p->data = p->init())) {
47412 - log_error_write(srv, __FILE__, __LINE__, "sb",
47413 + log_error_write(srv, __FILE__, __LINE__, "sb",
47414 "plugin-init failed for module", p->name);
47415 return HANDLER_ERROR;
47419 /* used for con->mode, DIRECT == 0, plugins above that */
47420 ((plugin_data *)(p->data))->id = i + 1;
47423 if (p->version != LIGHTTPD_VERSION_ID) {
47424 - log_error_write(srv, __FILE__, __LINE__, "sb",
47425 + log_error_write(srv, __FILE__, __LINE__, "sb",
47426 "plugin-version doesn't match lighttpd-version for", p->name);
47427 return HANDLER_ERROR;
47429 @@ -422,29 +450,46 @@
47435 return HANDLER_GO_ON;
47439 + * get the config-storage of the named plugin
47441 +void *plugin_get_config(server *srv, const char *name) {
47444 + for (i = 0; i < srv->plugins.used; i++) {
47445 + plugin *p = ((plugin **)srv->plugins.ptr)[i];
47447 + if (buffer_is_equal_string(p->name, name, strlen(name))) {
47455 void plugins_free(server *srv) {
47457 plugins_call_cleanup(srv);
47460 for (i = 0; i < srv->plugins.used; i++) {
47461 plugin *p = ((plugin **)srv->plugins.ptr)[i];
47468 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
47469 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
47472 if (slot) free(slot);
47476 free(srv->plugin_slots);
47477 srv->plugin_slots = NULL;
47480 free(srv->plugins.ptr);
47481 srv->plugins.ptr = NULL;
47482 srv->plugins.used = 0;
47483 --- ../lighttpd-1.4.11/src/plugin.h 2005-08-15 12:28:56.000000000 +0300
47484 +++ lighttpd-1.4.12/src/plugin.h 2006-07-16 00:26:04.000000000 +0300
47487 #define INIT_FUNC(x) \
47490 + * The PATCH_OPTION() macro is used in the patch_connection() functions
47491 + * of the modules to update the config object for the current request.
47493 +#define PATCH_OPTION(x) \
47496 #define FREE_FUNC SERVER_FUNC
47497 #define TRIGGER_FUNC SERVER_FUNC
47498 @@ -25,19 +31,19 @@
47499 #define URIHANDLER_FUNC CONNECTION_FUNC
47501 #define PLUGIN_DATA size_t id
47508 buffer *name; /* name of the plugin */
47512 handler_t (* set_defaults) (server *srv, void *p_d);
47513 handler_t (* cleanup) (server *srv, void *p_d);
47514 /* is called ... */
47515 handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */
47516 handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */
47519 handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */
47520 handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */
47521 handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */
47522 @@ -45,20 +51,22 @@
47523 handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */
47524 handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */
47525 handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */
47529 - handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
47531 - /* when a handler for the request
47535 + handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
47537 + /* when a handler for the request
47540 handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
47541 handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
47545 /* dlopen handle */
47548 + array *required_plugins;
47551 int plugins_load(server *srv);
47553 int config_patch_connection(server *srv, connection *con, comp_key_t comp);
47554 int config_check_cond(server *srv, connection *con, data_config *dc);
47555 int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
47556 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
47558 +void *plugin_get_config(server *srv, const char *name);
47561 --- ../lighttpd-1.4.11/src/proc_open.c 2005-08-11 01:26:39.000000000 +0300
47562 +++ lighttpd-1.4.12/src/proc_open.c 2006-07-16 00:26:04.000000000 +0300
47563 @@ -13,13 +13,13 @@
47569 /* {{{ win32 stuff */
47570 # define SHELLENV "ComSpec"
47571 # define SECURITY_DC , SECURITY_ATTRIBUTES *security
47572 # define SECURITY_CC , security
47573 # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
47574 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47575 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
47577 HANDLE copy, self = GetCurrentProcess();
47579 @@ -148,11 +148,14 @@
47582 SECURITY_ATTRIBUTES security;
47583 - const char *shell;
47584 + const char *shell = NULL;
47585 + const char *windir = NULL;
47588 - if (NULL == (shell = getenv(SHELLENV))) {
47589 - fprintf(stderr, "env %s is required", SHELLENV);
47590 + if (NULL == (shell = getenv(SHELLENV)) &&
47591 + NULL == (windir = getenv("SystemRoot")) &&
47592 + NULL == (windir = getenv("windir"))) {
47593 + fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
47597 @@ -177,17 +180,23 @@
47598 memset(&pi, 0, sizeof(pi));
47600 cmdline = buffer_init();
47601 - buffer_append_string(cmdline, shell);
47603 + buffer_append_string(cmdline, shell);
47605 + buffer_append_string(cmdline, windir);
47606 + buffer_append_string(cmdline, "\\system32\\cmd.exe");
47608 buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
47609 buffer_append_string(cmdline, command);
47610 procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
47611 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
47612 - buffer_free(cmdline);
47614 if (FALSE == procok) {
47615 - fprintf(stderr, "failed to CreateProcess");
47616 + fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
47617 + buffer_free(cmdline);
47620 + buffer_free(cmdline);
47622 proc->child = pi.hProcess;
47623 CloseHandle(pi.hThread);
47624 @@ -226,8 +235,7 @@
47627 if (NULL == (shell = getenv(SHELLENV))) {
47628 - fprintf(stderr, "env %s is required", SHELLENV);
47630 + shell = "/bin/sh";
47633 if (proc_open_pipes(proc) != 0) {
47634 @@ -262,11 +270,11 @@
47638 -#endif /* WIN32 */
47639 +#endif /* _WIN32 */
47641 /* {{{ proc_read_fd_to_buffer */
47642 static void proc_read_fd_to_buffer(int fd, buffer *b) {
47644 + int s; /* win32 has not ssize_t */
47647 buffer_prepare_append(b, 512);
47648 --- ../lighttpd-1.4.11/src/proc_open.h 2005-08-11 01:26:39.000000000 +0300
47649 +++ lighttpd-1.4.12/src/proc_open.h 2006-07-16 00:26:04.000000000 +0300
47652 #include "buffer.h"
47656 #include <windows.h>
47657 typedef HANDLE descriptor_t;
47658 typedef HANDLE proc_pid_t;
47659 --- ../lighttpd-1.4.11/src/request.c 2006-03-05 11:58:09.000000000 +0200
47660 +++ lighttpd-1.4.12/src/request.c 2006-07-18 13:03:40.000000000 +0300
47661 @@ -10,15 +10,17 @@
47662 #include "keyvalue.h"
47665 +#include "sys-strings.h"
47667 static int request_check_hostname(server *srv, connection *con, buffer *host) {
47668 enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
47673 - int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47674 + int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47681 @@ -32,17 +34,17 @@
47682 * IPv6address = "[" ... "]"
47688 if (!host || host->used == 0) return 0;
47691 host_len = host->used - 1;
47695 if (host->ptr[0] == '[') {
47696 char *c = host->ptr + 1;
47700 /* check portnumber */
47701 for (; *c && *c != ']'; c++) {
47703 @@ -53,12 +55,12 @@
47716 if (*(c+1) == ':') {
47717 for (c += 2; *c; c++) {
47718 @@ -69,39 +71,39 @@
47724 if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
47725 char *c = colon + 1;
47728 /* check portnumber */
47730 if (!light_isdigit(*c)) return -1;
47734 /* remove the port from the host-len */
47735 host_len = colon - host->ptr;
47739 /* Host is empty */
47740 if (host_len == 0) return -1;
47743 /* scan from the right and skip the \0 */
47744 for (i = host_len - 1; i + 1 > 0; i--) {
47745 const char c = host->ptr[i];
47751 /* only switch stage, if this is not the last character */
47752 if (i != host_len - 1) {
47753 if (label_len == 0) {
47758 /* check the first character at right of the dot */
47760 if (!light_isalpha(host->ptr[i+1])) {
47764 } else if (!light_isdigit(host->ptr[i+1])) {
47766 @@ -111,9 +113,9 @@
47772 stage = DOMAINLABEL;
47777 } else if (i == 0) {
47778 @@ -135,7 +137,7 @@
47787 @@ -143,7 +145,7 @@
47788 if (label_len == 0) {
47795 } else if (!light_isdigit(c)) {
47796 @@ -156,12 +158,12 @@
47797 if (label_len == 0) {
47802 /* c is either - or alphanum here */
47803 if ('-' == host->ptr[i+1]) {
47810 } else if (i == 0) {
47811 @@ -176,20 +178,20 @@
47822 /* a IP has to consist of 4 parts */
47823 if (is_ip == 1 && level != 3) {
47828 if (label_len == 0) {
47836 @@ -201,53 +203,53 @@
47846 * val1, val2, val3, val4
47849 * into a array (more or less a explode() incl. striping of whitespaces
47853 if (b->used == 0) return 0;
47859 for (i =0; i < b->used - 1; ) {
47860 char *start = NULL, *end = NULL;
47869 for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
47876 case 1: /* value */
47880 for (; *s != ',' && i < b->used - 1; i++, s++);
47884 for (; (*end == ' ' || *end == '\t') && end > start; end--);
47887 if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
47888 ds = data_string_init();
47891 buffer_copy_string_len(ds->value, start, end-start+1);
47892 array_insert_unique(vals, (data_unset *)ds);
47900 /* end of string */
47906 @@ -263,7 +265,7 @@
47907 if (c <= 32) return 0;
47908 if (c == 127) return 0;
47909 if (c == 255) return 0;
47915 @@ -271,28 +273,28 @@
47916 char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
47917 int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
47918 char *value = NULL, *key = NULL;
47921 enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
47927 int request_line_stage = 0;
47934 data_string *ds = NULL;
47937 - * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47938 - * Option : "^([-a-zA-Z]+): (.+)$"
47941 + * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47942 + * Option : "^([-a-zA-Z]+): (.+)$"
47946 if (con->conf.log_request_header) {
47947 - log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47949 - "request-len:", con->request.request->used,
47950 + log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47951 + "fd:", con->sock->fd,
47952 + "request-len:", con->request.request->used,
47953 "\n", con->request.request);
47956 @@ -300,13 +302,13 @@
47957 con->request.request->ptr[0] == '\r' &&
47958 con->request.request->ptr[1] == '\n') {
47959 /* we are in keep-alive and might get \r\n after a previous POST request.*/
47962 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
47964 /* fill the local request buffer */
47965 buffer_copy_string_buffer(con->parse_request, con->request.request);
47969 keep_alive_set = 0;
47970 con_length_set = 0;
47972 @@ -318,25 +320,25 @@
47974 for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
47975 char *cur = con->parse_request->ptr + i;
47981 if (con->parse_request->ptr[i+1] == '\n') {
47988 con->parse_request->ptr[i] = '\0';
47989 con->parse_request->ptr[i+1] = '\0';
47992 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
47995 if (request_line_stage != 2) {
47996 con->http_status = 400;
47997 con->response.keep_alive = 0;
47998 con->keep_alive = 0;
48001 if (srv->srvconf.log_request_header_on_error) {
48002 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
48003 log_error_write(srv, __FILE__, __LINE__, "Sb",
48004 @@ -345,36 +347,36 @@
48010 proto = con->parse_request->ptr + first;
48014 *(proto - 1) = '\0';
48017 /* we got the first one :) */
48018 if (-1 == (r = get_http_method_key(method))) {
48019 con->http_status = 501;
48020 con->response.keep_alive = 0;
48021 con->keep_alive = 0;
48024 if (srv->srvconf.log_request_header_on_error) {
48025 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
48026 log_error_write(srv, __FILE__, __LINE__, "Sb",
48027 "request-header:\n",
48028 con->request.request);
48036 con->request.http_method = r;
48043 * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
48047 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
48048 char * major = proto + sizeof("HTTP/") - 1;
48049 char * minor = strchr(major, '.');
48050 @@ -413,10 +415,10 @@
48053 if (major_num == 1 && minor_num == 1) {
48054 - con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
48055 + con->request.http_version = HTTP_VERSION_1_1;
48056 } else if (major_num == 1 && minor_num == 0) {
48057 con->request.http_version = HTTP_VERSION_1_0;
48060 con->http_status = 505;
48062 if (srv->srvconf.log_request_header_on_error) {
48063 @@ -439,30 +441,30 @@
48069 if (0 == strncmp(uri, "http://", 7) &&
48070 NULL != (nuri = strchr(uri + 7, '/'))) {
48071 /* ignore the host-part */
48074 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
48076 /* everything looks good so far */
48077 buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
48081 /* check uri for invalid characters */
48082 for (j = 0; j < con->request.uri->used - 1; j++) {
48083 if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
48084 unsigned char buf[2];
48085 con->http_status = 400;
48086 con->keep_alive = 0;
48089 if (srv->srvconf.log_request_header_on_error) {
48090 buf[0] = con->request.uri->ptr[j];
48094 if (con->request.uri->ptr[j] > 32 &&
48095 - con->request.uri->ptr[j] != 127) {
48096 + con->request.uri->ptr[j] != 127) {
48097 /* the character is printable -> print it */
48098 log_error_write(srv, __FILE__, __LINE__, "ss",
48099 "invalid character in URI -> 400",
48100 @@ -473,20 +475,20 @@
48101 "invalid character in URI -> 400",
48102 con->request.uri->ptr[j]);
48106 log_error_write(srv, __FILE__, __LINE__, "Sb",
48107 "request-header:\n",
48108 con->request.request);
48117 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
48120 con->http_status = 0;
48126 @@ -494,14 +496,14 @@
48129 switch(request_line_stage) {
48133 - method = con->parse_request->ptr + first;
48134 + method = con->parse_request->ptr + first;
48139 - uri = con->parse_request->ptr + first;
48140 + uri = con->parse_request->ptr + first;
48144 @@ -509,7 +511,7 @@
48145 con->http_status = 400;
48146 con->response.keep_alive = 0;
48147 con->keep_alive = 0;
48150 if (srv->srvconf.log_request_header_on_error) {
48151 log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
48152 log_error_write(srv, __FILE__, __LINE__, "Sb",
48153 @@ -518,12 +520,12 @@
48159 request_line_stage++;
48167 if (con->request.uri->used == 1) {
48168 @@ -540,30 +542,30 @@
48174 for (; i < con->parse_request->used && !done; i++) {
48175 char *cur = con->parse_request->ptr + i;
48184 * 1*<any CHAR except CTLs or separators>
48185 * CTLs == 0-31 + 127
48197 if (is_ws_after_key == 0) {
48198 key_len = i - first;
48200 is_ws_after_key = 0;
48206 @@ -584,8 +586,8 @@
48207 con->http_status = 400;
48208 con->keep_alive = 0;
48209 con->response.keep_alive = 0;
48211 - log_error_write(srv, __FILE__, __LINE__, "sbsds",
48213 + log_error_write(srv, __FILE__, __LINE__, "sbsds",
48214 "invalid character in key", con->request.request, cur, *cur, "-> 400");
48217 @@ -594,13 +596,13 @@
48229 key_len = i - first;
48232 /* skip every thing up to the : */
48233 for (j = 1; !got_colon; j++) {
48234 switch(con->parse_request->ptr[j + i]) {
48235 @@ -610,40 +612,40 @@
48250 if (srv->srvconf.log_request_header_on_error) {
48251 log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
48252 log_error_write(srv, __FILE__, __LINE__, "Sb",
48253 "request-header:\n",
48254 con->request.request);
48258 con->http_status = 400;
48259 con->response.keep_alive = 0;
48260 con->keep_alive = 0;
48270 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
48271 /* End of Header */
48272 con->parse_request->ptr[i] = '\0';
48273 con->parse_request->ptr[i+1] = '\0';
48284 if (srv->srvconf.log_request_header_on_error) {
48285 @@ -652,7 +654,7 @@
48286 "request-header:\n",
48287 con->request.request);
48291 con->http_status = 400;
48292 con->keep_alive = 0;
48293 con->response.keep_alive = 0;
48294 @@ -693,16 +695,16 @@
48295 con->http_status = 400;
48296 con->keep_alive = 0;
48297 con->response.keep_alive = 0;
48300 if (srv->srvconf.log_request_header_on_error) {
48301 - log_error_write(srv, __FILE__, __LINE__, "sbsds",
48302 + log_error_write(srv, __FILE__, __LINE__, "sbsds",
48303 "CTL character in key", con->request.request, cur, *cur, "-> 400");
48305 log_error_write(srv, __FILE__, __LINE__, "Sb",
48306 "request-header:\n",
48307 con->request.request);
48314 @@ -710,25 +712,25 @@
48320 if (con->parse_request->ptr[i+1] == '\n') {
48321 /* End of Headerline */
48322 con->parse_request->ptr[i] = '\0';
48323 con->parse_request->ptr[i+1] = '\0';
48331 if (srv->srvconf.log_request_header_on_error) {
48332 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
48335 log_error_write(srv, __FILE__, __LINE__, "Sb",
48336 "request-header:\n",
48337 con->request.request);
48342 con->http_status = 400;
48343 con->keep_alive = 0;
48344 con->response.keep_alive = 0;
48345 @@ -738,9 +740,9 @@
48348 key = con->parse_request->ptr + first;
48351 s_len = cur - value;
48356 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
48357 @@ -748,86 +750,87 @@
48359 buffer_copy_string_len(ds->key, key, key_len);
48360 buffer_copy_string_len(ds->value, value, s_len);
48362 - /* retreive values
48366 + /* retreive values
48369 * the list of options is sorted to simplify the search
48373 if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
48381 vals = srv->split_vals;
48386 http_request_split_value(vals, ds->value);
48389 for (vi = 0; vi < vals->used; vi++) {
48390 data_string *dsv = (data_string *)vals->data[vi];
48393 if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
48394 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
48398 } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
48399 keep_alive_set = HTTP_CONNECTION_CLOSE;
48407 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
48409 unsigned long int r;
48413 if (con_length_set) {
48414 con->http_status = 400;
48415 con->keep_alive = 0;
48418 if (srv->srvconf.log_request_header_on_error) {
48419 - log_error_write(srv, __FILE__, __LINE__, "s",
48420 + log_error_write(srv, __FILE__, __LINE__, "s",
48421 "duplicate Content-Length-header -> 400");
48422 log_error_write(srv, __FILE__, __LINE__, "Sb",
48423 "request-header:\n",
48424 con->request.request);
48426 + ds->free((data_unset *) ds);
48431 if (ds->value->used == 0) SEGFAULT();
48434 for (j = 0; j < ds->value->used - 1; j++) {
48435 char c = ds->value->ptr[j];
48436 if (!isdigit((unsigned char)c)) {
48437 - log_error_write(srv, __FILE__, __LINE__, "sbs",
48438 + log_error_write(srv, __FILE__, __LINE__, "sbs",
48439 "content-length broken:", ds->value, "-> 400");
48442 con->http_status = 400;
48443 con->keep_alive = 0;
48446 array_insert_unique(con->request.headers, (data_unset *)ds);
48452 r = strtoul(ds->value->ptr, &err, 10);
48455 if (*err == '\0') {
48456 con_length_set = 1;
48457 con->request.content_length = r;
48459 - log_error_write(srv, __FILE__, __LINE__, "sbs",
48460 + log_error_write(srv, __FILE__, __LINE__, "sbs",
48461 "content-length broken:", ds->value, "-> 400");
48464 con->http_status = 400;
48465 con->keep_alive = 0;
48468 array_insert_unique(con->request.headers, (data_unset *)ds);
48471 @@ -838,23 +841,24 @@
48473 con->http_status = 400;
48474 con->keep_alive = 0;
48477 if (srv->srvconf.log_request_header_on_error) {
48478 - log_error_write(srv, __FILE__, __LINE__, "s",
48479 + log_error_write(srv, __FILE__, __LINE__, "s",
48480 "duplicate Content-Type-header -> 400");
48481 log_error_write(srv, __FILE__, __LINE__, "Sb",
48482 "request-header:\n",
48483 con->request.request);
48485 + ds->free((data_unset *) ds);
48488 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
48489 - /* HTTP 2616 8.2.3
48490 + /* HTTP 2616 8.2.3
48491 * Expect: 100-continue
48494 * -> (10.1.1) 100 (read content, process request, send final status-code)
48495 * -> (10.4.18) 417 (close)
48498 * (not handled at all yet, we always send 417 here)
48500 * What has to be added ?
48501 @@ -863,10 +867,10 @@
48507 con->http_status = 417;
48508 con->keep_alive = 0;
48511 array_insert_unique(con->request.headers, (data_unset *)ds);
48513 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
48514 @@ -875,14 +879,15 @@
48516 con->http_status = 400;
48517 con->keep_alive = 0;
48520 if (srv->srvconf.log_request_header_on_error) {
48521 - log_error_write(srv, __FILE__, __LINE__, "s",
48522 + log_error_write(srv, __FILE__, __LINE__, "s",
48523 "duplicate Host-header -> 400");
48524 log_error_write(srv, __FILE__, __LINE__, "Sb",
48525 "request-header:\n",
48526 con->request.request);
48528 + ds->free((data_unset *) ds);
48531 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
48532 @@ -897,14 +902,15 @@
48534 con->http_status = 400;
48535 con->keep_alive = 0;
48538 if (srv->srvconf.log_request_header_on_error) {
48539 - log_error_write(srv, __FILE__, __LINE__, "s",
48540 + log_error_write(srv, __FILE__, __LINE__, "s",
48541 "duplicate If-Modified-Since header -> 400");
48542 log_error_write(srv, __FILE__, __LINE__, "Sb",
48543 "request-header:\n",
48544 con->request.request);
48546 + ds->free((data_unset *) ds);
48549 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
48550 @@ -914,47 +920,49 @@
48552 con->http_status = 400;
48553 con->keep_alive = 0;
48556 if (srv->srvconf.log_request_header_on_error) {
48557 - log_error_write(srv, __FILE__, __LINE__, "s",
48558 + log_error_write(srv, __FILE__, __LINE__, "s",
48559 "duplicate If-None-Match-header -> 400");
48560 log_error_write(srv, __FILE__, __LINE__, "Sb",
48561 "request-header:\n",
48562 con->request.request);
48564 + ds->free((data_unset *) ds);
48567 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
48568 if (!con->request.http_range) {
48572 if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
48573 NULL != strchr(ds->value->ptr+6, '-')) {
48576 /* if dup, only the first one will survive */
48577 con->request.http_range = ds->value->ptr + 6;
48580 con->http_status = 400;
48581 con->keep_alive = 0;
48584 if (srv->srvconf.log_request_header_on_error) {
48585 - log_error_write(srv, __FILE__, __LINE__, "s",
48586 + log_error_write(srv, __FILE__, __LINE__, "s",
48587 "duplicate Range-header -> 400");
48588 log_error_write(srv, __FILE__, __LINE__, "Sb",
48589 "request-header:\n",
48590 con->request.request);
48592 + ds->free((data_unset *) ds);
48598 array_insert_unique(con->request.headers, (data_unset *)ds);
48600 /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
48608 @@ -963,10 +971,10 @@
48611 if (srv->srvconf.log_request_header_on_error) {
48612 - log_error_write(srv, __FILE__, __LINE__, "sbs",
48613 + log_error_write(srv, __FILE__, __LINE__, "sbs",
48614 "CR without LF", con->request.request, "-> 400");
48618 con->http_status = 400;
48619 con->keep_alive = 0;
48620 con->response.keep_alive = 0;
48621 @@ -982,28 +990,28 @@
48627 con->header_len = i;
48630 /* do some post-processing */
48632 if (con->request.http_version == HTTP_VERSION_1_1) {
48633 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
48634 /* no Connection-Header sent */
48637 /* HTTP/1.1 -> keep-alive default TRUE */
48638 con->keep_alive = 1;
48640 con->keep_alive = 0;
48644 /* RFC 2616, 14.23 */
48645 if (con->request.http_host == NULL ||
48646 buffer_is_empty(con->request.http_host)) {
48647 con->http_status = 400;
48648 con->response.keep_alive = 0;
48649 con->keep_alive = 0;
48652 if (srv->srvconf.log_request_header_on_error) {
48653 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
48654 log_error_write(srv, __FILE__, __LINE__, "Sb",
48655 @@ -1015,18 +1023,18 @@
48657 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
48658 /* no Connection-Header sent */
48661 /* HTTP/1.0 -> keep-alive default FALSE */
48662 con->keep_alive = 1;
48664 con->keep_alive = 0;
48669 /* check hostname field if it is set */
48670 if (NULL != con->request.http_host &&
48671 0 != request_check_hostname(srv, con, con->request.http_host)) {
48674 if (srv->srvconf.log_request_header_on_error) {
48675 log_error_write(srv, __FILE__, __LINE__, "s",
48676 "Invalid Hostname -> 400");
48677 @@ -1038,7 +1046,7 @@
48678 con->http_status = 400;
48679 con->response.keep_alive = 0;
48680 con->keep_alive = 0;
48686 @@ -1048,7 +1056,7 @@
48687 /* content-length is forbidden for those */
48688 if (con_length_set && con->request.content_length != 0) {
48689 /* content-length is missing */
48690 - log_error_write(srv, __FILE__, __LINE__, "s",
48691 + log_error_write(srv, __FILE__, __LINE__, "s",
48692 "GET/HEAD with content-length -> 400");
48694 con->keep_alive = 0;
48695 @@ -1060,7 +1068,7 @@
48696 /* content-length is required for them */
48697 if (!con_length_set) {
48698 /* content-length is missing */
48699 - log_error_write(srv, __FILE__, __LINE__, "s",
48700 + log_error_write(srv, __FILE__, __LINE__, "s",
48701 "POST-request, but content-length missing -> 411");
48703 con->keep_alive = 0;
48704 @@ -1073,16 +1081,16 @@
48705 /* the may have a content-length */
48712 /* check if we have read post data */
48713 if (con_length_set) {
48714 /* don't handle more the SSIZE_MAX bytes in content-length */
48715 if (con->request.content_length > SSIZE_MAX) {
48716 - con->http_status = 413;
48717 + con->http_status = 413;
48718 con->keep_alive = 0;
48720 - log_error_write(srv, __FILE__, __LINE__, "sds",
48721 + log_error_write(srv, __FILE__, __LINE__, "sds",
48722 "request-size too long:", con->request.content_length, "-> 413");
48725 @@ -1090,25 +1098,25 @@
48726 /* divide by 1024 as srvconf.max_request_size is in kBytes */
48727 if (srv->srvconf.max_request_size != 0 &&
48728 (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
48729 - /* the request body itself is larger then
48730 + /* the request body itself is larger then
48731 * our our max_request_size
48735 con->http_status = 413;
48736 con->keep_alive = 0;
48738 - log_error_write(srv, __FILE__, __LINE__, "sds",
48740 + log_error_write(srv, __FILE__, __LINE__, "sds",
48741 "request-size too long:", con->request.content_length, "-> 413");
48748 /* we have content */
48749 if (con->request.content_length != 0) {
48758 @@ -1116,9 +1124,9 @@
48761 if (con->request.request->used < 5) return 0;
48764 if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
48765 if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
48770 --- ../lighttpd-1.4.11/src/response.c 2006-03-04 16:41:39.000000000 +0200
48771 +++ lighttpd-1.4.12/src/response.c 2006-07-16 00:26:04.000000000 +0300
48773 #include <stdlib.h>
48774 #include <string.h>
48776 -#include <unistd.h>
48778 #include <assert.h>
48780 @@ -24,15 +23,17 @@
48781 #include "plugin.h"
48783 #include "sys-socket.h"
48784 +#include "sys-files.h"
48785 +#include "sys-strings.h"
48787 int http_response_write_header(server *srv, connection *con) {
48791 int have_server = 0;
48794 b = chunkqueue_get_prepend_buffer(con->write_queue);
48797 if (con->request.http_version == HTTP_VERSION_1_1) {
48798 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48800 @@ -41,25 +42,26 @@
48801 buffer_append_long(b, con->http_status);
48802 BUFFER_APPEND_STRING_CONST(b, " ");
48803 buffer_append_string(b, get_http_status_name(con->http_status));
48806 if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
48807 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
48808 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
48812 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
48813 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
48819 /* add all headers */
48820 for (i = 0; i < con->response.headers->used; i++) {
48824 ds = (data_string *)con->response.headers->data[i];
48827 if (ds->value->used && ds->key->used &&
48828 - 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
48829 + 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
48830 + 0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
48831 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
48832 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
48834 @@ -68,28 +70,28 @@
48835 BUFFER_APPEND_STRING_CONST(b, ": ");
48836 buffer_append_string_buffer(b, ds->value);
48838 - log_error_write(srv, __FILE__, __LINE__, "bb",
48839 + log_error_write(srv, __FILE__, __LINE__, "bb",
48840 ds->key, ds->value);
48847 /* HTTP/1.1 requires a Date: header */
48848 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
48851 /* cache the generated timestamp */
48852 if (srv->cur_ts != srv->last_generated_date_ts) {
48853 buffer_prepare_copy(srv->ts_date_str, 255);
48855 - strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48857 + strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48858 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
48861 srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
48864 srv->last_generated_date_ts = srv->cur_ts;
48868 buffer_append_string_buffer(b, srv->ts_date_str);
48871 @@ -101,16 +103,16 @@
48872 buffer_append_string_buffer(b, con->conf.server_tag);
48877 BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
48882 con->bytes_header = b->used - 1;
48885 if (con->conf.log_response_header) {
48886 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
48893 @@ -118,71 +120,71 @@
48895 handler_t http_response_prepare(server *srv, connection *con) {
48898 - /* looks like someone has already done a decision */
48899 - if (con->mode == DIRECT &&
48901 + /* looks like someone has already made a decision */
48902 + if (con->mode == DIRECT &&
48903 (con->http_status != 0 && con->http_status != 200)) {
48904 /* remove a packets in the queue */
48905 if (con->file_finished == 0) {
48906 chunkqueue_reset(con->write_queue);
48910 return HANDLER_FINISHED;
48914 /* no decision yet, build conf->filename */
48915 if (con->mode == DIRECT && con->physical.path->used == 0) {
48918 - /* we only come here when we have the parse the full request again
48920 - * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48921 + /* we only come here when we have to parse the full request again
48923 + * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48924 * problem here as mod_setenv might get called multiple times
48926 * fastcgi-auth might lead to a COMEBACK too
48927 * fastcgi again dead server too
48929 * mod_compress might add headers twice too
48935 if (con->conf.log_condition_handling) {
48936 log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
48938 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
48947 * - uri.path (secure)
48956 * Name according to RFC 2396
48965 * (scheme)://(authority)(path)?(query)
48973 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
48974 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
48975 buffer_to_lower(con->uri.authority);
48978 config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */
48979 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */
48980 config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */
48981 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */
48982 config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */
48985 /** extract query string from request.uri */
48986 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
48987 buffer_copy_string (con->uri.query, qstr + 1);
48988 @@ -200,22 +202,22 @@
48989 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path_raw);
48990 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query);
48994 /* disable keep-alive if requested */
48997 if (con->request_count > con->conf.max_keep_alive_requests) {
48998 con->keep_alive = 0;
49011 * - based on the raw URL
49017 switch(r = plugins_call_handle_uri_raw(srv, con)) {
49018 case HANDLER_GO_ON:
49020 @@ -229,14 +231,14 @@
49024 - /* build filename
49025 + /* build filename
49027 * - decode url-encodings (e.g. %20 -> ' ')
49028 * - remove path-modifiers (e.g. /../)
49036 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
49037 con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
49038 /* OPTIONS * ... */
49039 @@ -253,15 +255,20 @@
49049 * - based on the clean URL
49055 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
49058 + /* do we have to downgrade to 1.0 ? */
49059 + if (!con->conf.allow_http11) {
49060 + con->request.http_version = HTTP_VERSION_1_0;
49063 switch(r = plugins_call_handle_uri_clean(srv, con)) {
49064 case HANDLER_GO_ON:
49066 @@ -274,11 +281,11 @@
49067 log_error_write(srv, __FILE__, __LINE__, "");
49072 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
49073 con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
49074 - /* option requests are handled directly without checking of the path */
49076 + /* option requests are handled directly without checking the path */
49078 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
49080 con->http_status = 200;
49081 @@ -288,46 +295,47 @@
49091 * logical filename (URI) becomes a physical filename here
49108 * ... ISREG() -> ok, go on
49109 * ... ISDIR() -> index-file -> redirect
49124 * SEARCH DOCUMENT ROOT
49128 /* set a default */
49131 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
49132 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
49134 -#if defined(__WIN32) || defined(__CYGWIN__)
49135 - /* strip dots from the end and spaces
49137 + filename_unix2local(con->physical.rel_path);
49138 +#if defined(_WIN32) || defined(__CYGWIN__)
49139 + /* strip dots and spaces from the end
49141 * windows/dos handle those filenames as the same file
49143 * foo == foo. == foo..... == "foo... " == "foo.. ./"
49145 - * This will affect in some cases PATHINFO
49146 + * This will affect PATHINFO in some cases
49148 * on native windows we could prepend the filename with \\?\ to circumvent
49149 * this behaviour. I have no idea how to push this through cygwin
49150 @@ -377,36 +385,41 @@
49151 log_error_write(srv, __FILE__, __LINE__, "");
49155 - /* MacOS X and Windows can't distiguish between upper and lower-case
49157 - * convert to lower-case
49159 + /* The default Mac OS X and Windows filesystems can't distiguish between
49160 + * upper- and lowercase, so convert to lowercase
49162 if (con->conf.force_lowercase_filenames) {
49163 buffer_to_lower(con->physical.rel_path);
49166 - /* the docroot plugins might set the servername, if they don't we take http-host */
49167 + /* the docroot plugins might set the servername; if they don't we take http-host */
49168 if (buffer_is_empty(con->server_name)) {
49169 buffer_copy_string_buffer(con->server_name, con->uri.authority);
49173 - * create physical filename
49176 + * create physical filename
49177 * -> physical.path = docroot + rel_path
49183 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
49184 - BUFFER_APPEND_SLASH(con->physical.path);
49185 + PATHNAME_APPEND_SLASH(con->physical.path);
49186 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
49187 if (con->physical.rel_path->used &&
49188 - con->physical.rel_path->ptr[0] == '/') {
49189 + con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
49190 buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
49192 buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
49195 + /* win32: directories can't have a trailing slash */
49196 + if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
49197 + con->physical.path->ptr[con->physical.path->used - 2] = '\0';
49198 + con->physical.path->used--;
49201 if (con->conf.log_request_handling) {
49202 log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root");
49203 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
49204 @@ -426,7 +439,7 @@
49205 log_error_write(srv, __FILE__, __LINE__, "");
49210 if (con->conf.log_request_handling) {
49211 log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical");
49212 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
49213 @@ -434,38 +447,38 @@
49214 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49219 - * Noone catched away the file from normal path of execution yet (like mod_access)
49223 + * No one took the file away from the normal path of execution yet (like mod_access)
49225 * Go on and check of the file exists at all
49229 if (con->mode == DIRECT) {
49230 char *slash = NULL;
49231 char *pathinfo = NULL;
49233 stat_cache_entry *sce = NULL;
49236 if (con->conf.log_request_handling) {
49237 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path");
49238 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49242 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
49246 if (con->conf.log_request_handling) {
49247 log_error_write(srv, __FILE__, __LINE__, "s", "-- file found");
49248 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49252 if (S_ISDIR(sce->st.st_mode)) {
49253 - if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
49254 + if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
49255 /* redirect to .../ */
49258 http_response_redirect_to_directory(srv, con);
49261 return HANDLER_FINISHED;
49263 } else if (!S_ISREG(sce->st.st_mode)) {
49264 @@ -477,12 +490,12 @@
49267 con->http_status = 403;
49270 if (con->conf.log_request_handling) {
49271 log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied");
49272 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49276 buffer_reset(con->physical.path);
49277 return HANDLER_FINISHED;
49279 @@ -499,77 +512,77 @@
49280 /* PATH_INFO ! :) */
49283 - /* we have no idea what happend. let's tell the user so. */
49284 + /* we have no idea what happened, so tell the user. */
49285 con->http_status = 500;
49286 buffer_reset(con->physical.path);
49289 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
49290 "file not found ... or so: ", strerror(errno),
49292 "->", con->physical.path);
49295 return HANDLER_FINISHED;
49299 /* not found, perhaps PATHINFO */
49302 buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
49310 buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
49312 buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
49316 if (0 == stat(con->physical.path->ptr, &(st)) &&
49317 S_ISREG(st.st_mode)) {
49323 if (pathinfo != NULL) {
49326 slash = strrchr(srv->tmp_buf->ptr, '/');
49329 if (pathinfo != NULL) {
49335 if (slash) pathinfo = slash;
49336 } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
49340 - /* no it really doesn't exists */
49341 + /* no, it really doesn't exists */
49342 con->http_status = 404;
49345 if (con->conf.log_file_not_found) {
49346 log_error_write(srv, __FILE__, __LINE__, "sbsb",
49347 "file not found:", con->uri.path,
49348 "->", con->physical.path);
49352 buffer_reset(con->physical.path);
49355 return HANDLER_FINISHED;
49359 /* we have a PATHINFO */
49361 buffer_copy_string(con->request.pathinfo, pathinfo);
49369 con->uri.path->used -= strlen(pathinfo);
49370 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
49374 if (con->conf.log_request_handling) {
49375 log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check");
49376 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49377 @@ -577,12 +590,12 @@
49378 log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo);
49383 if (con->conf.log_request_handling) {
49384 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest");
49385 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
49389 /* call the handlers */
49390 switch(r = plugins_call_handle_subrequest_start(srv, con)) {
49391 case HANDLER_GO_ON:
49392 @@ -593,32 +606,32 @@
49393 if (con->conf.log_request_handling) {
49394 log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished");
49397 - /* something strange happend */
49399 + /* something strange happened */
49403 - /* if we are still here, no one wanted the file, status 403 is ok I think */
49406 + /* if we are still here, no one wanted the file; status 403 is ok I think */
49408 if (con->mode == DIRECT) {
49409 con->http_status = 403;
49412 return HANDLER_FINISHED;
49419 switch(r = plugins_call_handle_subrequest(srv, con)) {
49420 case HANDLER_GO_ON:
49421 - /* request was not handled, looks like we are done */
49422 + /* request was not handled; looks like we are done */
49423 return HANDLER_FINISHED;
49424 case HANDLER_FINISHED:
49425 /* request is finished */
49427 - /* something strange happend */
49428 + /* something strange happened */
49434 return HANDLER_COMEBACK;
49436 --- ../lighttpd-1.4.11/src/server.c 2006-03-04 19:12:17.000000000 +0200
49437 +++ lighttpd-1.4.12/src/server.c 2006-07-19 20:02:55.000000000 +0300
49439 #include <sys/types.h>
49440 -#include <sys/time.h>
49441 #include <sys/stat.h>
49443 #include <string.h>
49446 -#include <unistd.h>
49447 #include <stdlib.h>
49449 #include <signal.h>
49451 #include "plugin.h"
49452 #include "joblist.h"
49453 #include "network_backends.h"
49455 +#include "status_counter.h"
49457 +/* use local getopt implementation */
49458 +# undef HAVE_GETOPT_H
49460 #ifdef HAVE_GETOPT_H
49461 #include <getopt.h>
49463 +#include "getopt.h"
49466 #ifdef HAVE_VALGRIND_VALGRIND_H
49468 /* #define USE_ALARM */
49472 +#undef HAVE_SIGNAL
49475 +#include "sys-files.h"
49476 +#include "sys-process.h"
49477 +#include "sys-socket.h"
49479 static volatile sig_atomic_t srv_shutdown = 0;
49480 static volatile sig_atomic_t graceful_shutdown = 0;
49481 +static volatile sig_atomic_t graceful_restart = 0;
49482 static volatile sig_atomic_t handle_sig_alarm = 1;
49483 static volatile sig_atomic_t handle_sig_hup = 0;
49488 case SIGTERM: srv_shutdown = 1; break;
49491 if (graceful_shutdown) srv_shutdown = 1;
49492 - else graceful_shutdown = 1;
49493 + else graceful_shutdown = 1;
49496 case SIGALRM: handle_sig_alarm = 1; break;
49498 static void signal_handler(int sig) {
49500 case SIGTERM: srv_shutdown = 1; break;
49503 if (graceful_shutdown) srv_shutdown = 1;
49504 - else graceful_shutdown = 1;
49505 + else graceful_shutdown = 1;
49508 case SIGALRM: handle_sig_alarm = 1; break;
49509 @@ -110,35 +123,35 @@
49510 signal(SIGTSTP, SIG_IGN);
49512 if (0 != fork()) exit(0);
49515 if (-1 == setsid()) exit(0);
49517 signal(SIGHUP, SIG_IGN);
49519 if (0 != fork()) exit(0);
49522 if (0 != chdir("/")) exit(0);
49526 static server *server_init(void) {
49530 server *srv = calloc(1, sizeof(*srv));
49532 + srv->max_fds = 1024;
49534 srv->x = buffer_init();
49537 CLEAN(response_header);
49538 CLEAN(parse_full_path);
49539 CLEAN(ts_debug_str);
49540 CLEAN(ts_date_str);
49541 - CLEAN(errorlog_buf);
49542 CLEAN(response_range);
49544 srv->empty_string = buffer_init_string("");
49545 CLEAN(cond_check_buf);
49548 CLEAN(srvconf.errorlog_file);
49549 CLEAN(srvconf.groupname);
49550 CLEAN(srvconf.username);
49551 @@ -146,68 +159,62 @@
49552 CLEAN(srvconf.bindhost);
49553 CLEAN(srvconf.event_handler);
49554 CLEAN(srvconf.pid_file);
49557 CLEAN(tmp_chunk_len);
49562 srv->x = array_init();
49565 CLEAN(config_context);
49566 CLEAN(config_touched);
49571 for (i = 0; i < FILE_CACHE_MAX; i++) {
49572 srv->mtime_cache[i].str = buffer_init();
49576 srv->cur_ts = time(NULL);
49577 srv->startup_ts = srv->cur_ts;
49580 srv->conns = calloc(1, sizeof(*srv->conns));
49581 assert(srv->conns);
49584 srv->joblist = calloc(1, sizeof(*srv->joblist));
49585 assert(srv->joblist);
49588 srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
49589 assert(srv->fdwaitqueue);
49592 srv->srvconf.modules = array_init();
49593 srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
49594 srv->srvconf.network_backend = buffer_init();
49595 srv->srvconf.upload_tempdirs = array_init();
49598 - srv->errorlog_fd = -1;
49599 - srv->errorlog_mode = ERRORLOG_STDERR;
49601 srv->split_vals = array_init();
49607 static void server_free(server *srv) {
49611 for (i = 0; i < FILE_CACHE_MAX; i++) {
49612 buffer_free(srv->mtime_cache[i].str);
49617 buffer_free(srv->x);
49620 CLEAN(response_header);
49621 CLEAN(parse_full_path);
49622 CLEAN(ts_debug_str);
49623 CLEAN(ts_date_str);
49624 - CLEAN(errorlog_buf);
49625 CLEAN(response_range);
49627 CLEAN(empty_string);
49628 CLEAN(cond_check_buf);
49631 CLEAN(srvconf.errorlog_file);
49632 CLEAN(srvconf.groupname);
49633 CLEAN(srvconf.username);
49634 @@ -217,7 +224,7 @@
49635 CLEAN(srvconf.pid_file);
49636 CLEAN(srvconf.modules_dir);
49637 CLEAN(srvconf.network_backend);
49640 CLEAN(tmp_chunk_len);
49643 @@ -225,15 +232,15 @@
49644 fdevent_unregister(srv->ev, srv->fd);
49646 fdevent_free(srv->ev);
49652 if (srv->config_storage) {
49653 for (i = 0; i < srv->config_context->used; i++) {
49654 specific_config *s = srv->config_storage[i];
49659 buffer_free(s->document_root);
49660 buffer_free(s->server_name);
49661 buffer_free(s->server_tag);
49662 @@ -242,32 +249,31 @@
49663 buffer_free(s->error_handler);
49664 buffer_free(s->errorfile_prefix);
49665 array_free(s->mimetypes);
49670 free(srv->config_storage);
49671 srv->config_storage = NULL;
49676 array_free(srv->x);
49679 CLEAN(config_context);
49680 CLEAN(config_touched);
49682 CLEAN(srvconf.upload_tempdirs);
49686 joblist_free(srv, srv->joblist);
49687 fdwaitqueue_free(srv, srv->fdwaitqueue);
49690 if (srv->stat_cache) {
49691 stat_cache_free(srv->stat_cache);
49694 array_free(srv->srvconf.modules);
49695 array_free(srv->split_vals);
49701 @@ -281,14 +287,12 @@
49702 " - a light and fast webserver\n" \
49703 "Build-Date: " __DATE__ " " __TIME__ "\n";
49707 write(STDOUT_FILENO, b, strlen(b));
49710 static void show_features (void) {
49712 - printf("\nEvent Handlers:\n\n%s",
49714 + const char *s = ""
49716 "\t+ select (generic)\n"
49718 @@ -355,11 +359,6 @@
49720 "\t- crypt support\n"
49723 - "\t+ PAM support\n"
49725 - "\t- PAM support\n"
49728 "\t+ SSL Support\n"
49730 @@ -371,9 +370,9 @@
49731 "\t- PCRE support\n"
49734 - "\t+ mySQL support\n"
49735 + "\t+ MySQL support\n"
49737 - "\t- mySQL support\n"
49738 + "\t- MySQL support\n"
49740 #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
49741 "\t+ LDAP support\n"
49742 @@ -410,8 +409,11 @@
49744 "\t- GDBM support\n"
49752 + printf("\nEvent Handlers:\n\n%s", s);
49755 static void show_help (void) {
49756 @@ -433,197 +435,565 @@
49757 " -h show this help\n" \
49763 write(STDOUT_FILENO, b, strlen(b));
49766 -int main (int argc, char **argv) {
49767 - server *srv = NULL;
49768 - int print_config = 0;
49769 - int test_config = 0;
49772 - int num_childs = 0;
49773 - int pid_fd = -1, fd;
49775 -#ifdef HAVE_SIGACTION
49776 - struct sigaction act;
49778 -#ifdef HAVE_GETRLIMIT
49779 - struct rlimit rlim;
49783 - struct itimerval interval;
49785 - interval.it_interval.tv_sec = 1;
49786 - interval.it_interval.tv_usec = 0;
49787 - interval.it_value.tv_sec = 1;
49788 - interval.it_value.tv_usec = 0;
49792 - /* for nice %b handling in strfime() */
49793 - setlocale(LC_TIME, "C");
49795 - if (NULL == (srv = server_init())) {
49796 - fprintf(stderr, "did this really happen?\n");
49800 - /* init structs done */
49802 - srv->srvconf.port = 0;
49803 -#ifdef HAVE_GETUID
49804 - i_am_root = (getuid() == 0);
49808 - srv->srvconf.dont_daemonize = 0;
49810 - while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49813 - if (config_read(srv, optarg)) {
49814 - server_free(srv);
49819 - buffer_copy_string(srv->srvconf.modules_dir, optarg);
49821 - case 'p': print_config = 1; break;
49822 - case 't': test_config = 1; break;
49823 - case 'D': srv->srvconf.dont_daemonize = 1; break;
49824 - case 'v': show_version(); return 0;
49825 - case 'V': show_features(); return 0;
49826 - case 'h': show_help(); return 0;
49829 - server_free(srv);
49834 - if (!srv->config_storage) {
49835 - log_error_write(srv, __FILE__, __LINE__, "s",
49836 - "No configuration available. Try using -f option.");
49838 - server_free(srv);
49842 - if (print_config) {
49843 - data_unset *dc = srv->config_context->data[0];
49845 - dc->print(dc, 0);
49846 - fprintf(stderr, "\n");
49848 - /* shouldn't happend */
49849 - fprintf(stderr, "global config not found\n");
49852 +int lighty_mainloop(server *srv) {
49853 + fdevent_revents *revents = fdevent_revents_init();
49855 - if (test_config) {
49856 - printf("Syntax OK\n");
49859 + while (!srv_shutdown) {
49864 - if (test_config || print_config) {
49865 - server_free(srv);
49869 - /* close stdin and stdout, as they are not needed */
49870 - /* move stdin to /dev/null */
49871 - if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49872 - close(STDIN_FILENO);
49873 - dup2(fd, STDIN_FILENO);
49877 - /* move stdout to /dev/null */
49878 - if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49879 - close(STDOUT_FILENO);
49880 - dup2(fd, STDOUT_FILENO);
49884 - if (0 != config_set_defaults(srv)) {
49885 - log_error_write(srv, __FILE__, __LINE__, "s",
49886 - "setting default values failed");
49887 - server_free(srv);
49891 - /* UID handling */
49892 -#ifdef HAVE_GETUID
49893 - if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49894 - /* we are setuid-root */
49896 - log_error_write(srv, __FILE__, __LINE__, "s",
49897 - "Are you nuts ? Don't apply a SUID bit to this binary");
49899 - server_free(srv);
49904 - /* check document-root */
49905 - if (srv->config_storage[0]->document_root->used <= 1) {
49906 - log_error_write(srv, __FILE__, __LINE__, "s",
49907 - "document-root is not set\n");
49909 - server_free(srv);
49914 - if (plugins_load(srv)) {
49915 - log_error_write(srv, __FILE__, __LINE__, "s",
49916 - "loading plugins finally failed");
49918 - plugins_free(srv);
49919 - server_free(srv);
49924 - /* open pid file BEFORE chroot */
49925 - if (srv->srvconf.pid_file->used) {
49926 - 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))) {
49928 - if (errno != EEXIST) {
49929 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49930 - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49934 - if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49935 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49936 - "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49937 + if (handle_sig_hup) {
49940 + /* reset notification */
49941 + handle_sig_hup = 0;
49946 + /* send the old process into a graceful-shutdown and start a
49947 + * new process right away
49950 + * - if webserver is running on port < 1024 (e.g. 80, 433)
49951 + * we don't have the permissions to bind to that port anymore
49955 + if (0 == (pid = fork())) {
49956 + execve(argv[0], argv, envp);
49959 + } else if (pid == -1) {
49964 + graceful_shutdown = 1; /* shutdown without killing running connections */
49965 + graceful_restart = 1; /* don't delete pid file */
49968 - if (!S_ISREG(st.st_mode)) {
49969 - log_error_write(srv, __FILE__, __LINE__, "sb",
49970 - "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49973 + /* cycle logfiles */
49975 + switch(r = plugins_call_handle_sighup(srv)) {
49976 + case HANDLER_GO_ON:
49979 + log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
49983 - if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49984 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49985 - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49987 + if (-1 == log_error_cycle()) {
49988 + log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
49996 - if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49997 - /* select limits itself
49998 + if (handle_sig_alarm) {
49999 + /* a new second */
50002 + /* reset notification */
50003 + handle_sig_alarm = 0;
50006 + /* get current time */
50007 + min_ts = time(NULL);
50009 + if (min_ts != srv->cur_ts) {
50011 + connections *conns = srv->conns;
50014 + switch(r = plugins_call_handle_trigger(srv)) {
50015 + case HANDLER_GO_ON:
50017 + case HANDLER_ERROR:
50018 + log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50021 + log_error_write(srv, __FILE__, __LINE__, "d", r);
50025 + /* trigger waitpid */
50026 + srv->cur_ts = min_ts;
50028 + /* cleanup stat-cache */
50029 + stat_cache_trigger_cleanup(srv);
50031 + * check all connections for timeouts
50034 + for (ndx = 0; ndx < conns->used; ndx++) {
50039 + con = conns->ptr[ndx];
50041 + if (con->state == CON_STATE_READ ||
50042 + con->state == CON_STATE_READ_POST) {
50043 + if (con->request_count == 1) {
50044 + if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50047 + log_error_write(srv, __FILE__, __LINE__, "sd",
50048 + "connection closed - read-timeout:", con->fd);
50050 + connection_set_state(srv, con, CON_STATE_ERROR);
50054 + if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50057 + log_error_write(srv, __FILE__, __LINE__, "sd",
50058 + "connection closed - read-timeout:", con->fd);
50060 + connection_set_state(srv, con, CON_STATE_ERROR);
50066 + if ((con->state == CON_STATE_WRITE) &&
50067 + (con->write_request_ts != 0)) {
50069 + if (srv->cur_ts - con->write_request_ts > 60) {
50070 + log_error_write(srv, __FILE__, __LINE__, "sdd",
50071 + "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50075 + if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50078 + log_error_write(srv, __FILE__, __LINE__, "sbsosds",
50079 + "NOTE: a request for",
50080 + con->request.uri,
50081 + "timed out after writing",
50082 + con->bytes_written,
50083 + "bytes. We waited",
50084 + (int)con->conf.max_write_idle,
50085 + "seconds. If this a problem increase server.max-write-idle");
50087 + connection_set_state(srv, con, CON_STATE_ERROR);
50091 + /* we don't like div by zero */
50092 + if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50094 + if (con->traffic_limit_reached &&
50095 + (con->conf.kbytes_per_second == 0 ||
50096 + ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50097 + /* enable connection again */
50098 + con->traffic_limit_reached = 0;
50104 + connection_state_machine(srv, con);
50106 + con->bytes_written_cur_second = 0;
50107 + *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50111 + fprintf(stderr, "connection-state: ");
50115 + fprintf(stderr, "c[%d,%d]: %s ",
50118 + connection_get_state(con->state));
50122 + if (cs == 1) fprintf(stderr, "\n");
50126 + if (srv->sockets_disabled) {
50127 + /* our server sockets are disabled, why ? */
50129 + if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50130 + (srv->conns->used < srv->max_conns * 0.9) &&
50131 + (0 == graceful_shutdown)) {
50134 + for (i = 0; i < srv->srv_sockets.used; i++) {
50135 + server_socket *srv_socket = srv->srv_sockets.ptr[i];
50136 + fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
50139 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50141 + srv->sockets_disabled = 0;
50144 + if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
50145 + (srv->conns->used > srv->max_conns) || /* out of connections */
50146 + (graceful_shutdown)) { /* graceful_shutdown */
50149 + /* disable server-fds */
50151 + for (i = 0; i < srv->srv_sockets.used; i++) {
50152 + server_socket *srv_socket = srv->srv_sockets.ptr[i];
50153 + fdevent_event_del(srv->ev, srv_socket->sock);
50155 + if (graceful_shutdown) {
50156 + /* we don't want this socket anymore,
50158 + * closing it right away will make it possible for
50159 + * the next lighttpd to take over (graceful restart)
50162 + fdevent_unregister(srv->ev, srv_socket->sock);
50163 + closesocket(srv_socket->sock->fd);
50164 + srv_socket->sock->fd = -1;
50166 + /* network_close() will cleanup after us */
50170 + if (graceful_shutdown) {
50171 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
50172 + } else if (srv->conns->used > srv->max_conns) {
50173 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
50175 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
50178 + srv->sockets_disabled = 1;
50182 + if (graceful_shutdown && srv->conns->used == 0) {
50183 + /* we are in graceful shutdown phase and all connections are closed
50184 + * we are ready to terminate without harming anyone */
50185 + srv_shutdown = 1;
50188 + /* we still have some fds to share */
50189 + if (srv->want_fds) {
50190 + /* check the fdwaitqueue for waiting fds */
50191 + int free_fds = srv->max_fds - srv->cur_fds - 16;
50194 + for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
50195 + connection_state_machine(srv, con);
50201 + if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
50202 + /* n is the number of events */
50204 + fdevent_get_revents(srv->ev, n, revents);
50206 + /* handle client connections first
50208 + * this is a bit of a hack, but we have to make sure than we handle
50209 + * close-events before the connection is reused for a keep-alive
50212 + * this is mostly an issue for mod_proxy_core, but you never know
50216 + for (i = 0; i < revents->used; i++) {
50217 + fdevent_revent *revent = revents->ptr[i];
50220 + /* skip server-fds */
50221 + if (revent->handler == network_server_handle_fdevent) continue;
50223 + switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50224 + case HANDLER_FINISHED:
50225 + case HANDLER_GO_ON:
50226 + case HANDLER_WAIT_FOR_EVENT:
50227 + case HANDLER_WAIT_FOR_FD:
50229 + case HANDLER_ERROR:
50230 + /* should never happen */
50234 + log_error_write(srv, __FILE__, __LINE__, "d", r);
50239 + for (i = 0; i < revents->used; i++) {
50240 + fdevent_revent *revent = revents->ptr[i];
50243 + /* server fds only */
50244 + if (revent->handler != network_server_handle_fdevent) continue;
50246 + switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
50247 + case HANDLER_FINISHED:
50248 + case HANDLER_GO_ON:
50249 + case HANDLER_WAIT_FOR_EVENT:
50250 + case HANDLER_WAIT_FOR_FD:
50252 + case HANDLER_ERROR:
50253 + /* should never happen */
50257 + log_error_write(srv, __FILE__, __LINE__, "d", r);
50262 + } else if (n < 0 && errno != EINTR) {
50263 + log_error_write(srv, __FILE__, __LINE__, "ss",
50264 + "fdevent_poll failed:",
50265 + strerror(errno));
50268 + for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50269 + connection *con = srv->joblist->ptr[ndx];
50272 + connection_state_machine(srv, con);
50274 + switch(r = plugins_call_handle_joblist(srv, con)) {
50275 + case HANDLER_FINISHED:
50276 + case HANDLER_GO_ON:
50279 + log_error_write(srv, __FILE__, __LINE__, "d", r);
50283 + con->in_joblist = 0;
50286 + srv->joblist->used = 0;
50289 + fdevent_revents_free(revents);
50295 +int main (int argc, char **argv, char **envp) {
50296 + server *srv = NULL;
50297 + int print_config = 0;
50298 + int test_config = 0;
50301 + int num_childs = 0;
50302 + int pid_fd = -1, fd;
50305 + char *optarg = NULL;
50308 +#ifdef HAVE_SIGACTION
50309 + struct sigaction act;
50311 +#ifdef HAVE_GETRLIMIT
50312 + struct rlimit rlim;
50316 + struct itimerval interval;
50318 + interval.it_interval.tv_sec = 1;
50319 + interval.it_interval.tv_usec = 0;
50320 + interval.it_value.tv_sec = 1;
50321 + interval.it_value.tv_usec = 0;
50325 + status_counter_init();
50327 + /* for nice %b handling in strfime() */
50328 + setlocale(LC_TIME, "C");
50330 + if (NULL == (srv = server_init())) {
50331 + fprintf(stderr, "did this really happen?\n");
50335 + /* init structs done */
50337 + srv->srvconf.port = 0;
50338 +#ifdef HAVE_GETUID
50339 + i_am_root = (getuid() == 0);
50343 + srv->srvconf.dont_daemonize = 0;
50345 + while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
50349 + /* evil HACK for windows, optarg is not set */
50350 + optarg = argv[optind-1];
50352 + if (config_read(srv, optarg)) {
50353 + server_free(srv);
50359 + buffer_copy_string(srv->srvconf.modules_dir, optarg);
50361 + case 'p': print_config = 1; break;
50362 + case 't': test_config = 1; break;
50363 + case 'D': srv->srvconf.dont_daemonize = 1; break;
50364 + case 'v': show_version(); return 0;
50365 + case 'V': show_features(); return 0;
50366 + case 'h': show_help(); return 0;
50369 + server_free(srv);
50374 + if (!srv->config_storage) {
50375 + log_error_write(srv, __FILE__, __LINE__, "s",
50376 + "No configuration available. Try using -f option.");
50378 + server_free(srv);
50382 + if (print_config) {
50383 + data_unset *dc = srv->config_context->data[0];
50385 + dc->print(dc, 0);
50386 + fprintf(stderr, "\n");
50388 + /* shouldn't happend */
50389 + fprintf(stderr, "global config not found\n");
50393 + if (test_config) {
50394 + printf("Syntax OK\n");
50397 + if (test_config || print_config) {
50398 + server_free(srv);
50402 + /* close stdin and stdout, as they are not needed */
50403 + /* move stdin to /dev/null */
50404 + if (-1 != (fd = open("/dev/null", O_RDONLY))) {
50405 + close(STDIN_FILENO);
50406 + dup2(fd, STDIN_FILENO);
50410 + /* move stdout to /dev/null */
50411 + if (-1 != (fd = open("/dev/null", O_WRONLY))) {
50412 + close(STDOUT_FILENO);
50413 + dup2(fd, STDOUT_FILENO);
50417 + if (0 != config_set_defaults(srv)) {
50418 + log_error_write(srv, __FILE__, __LINE__, "s",
50419 + "setting default values failed");
50420 + server_free(srv);
50424 + /* UID handling */
50425 +#ifdef HAVE_GETUID
50426 + if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
50427 + /* we are setuid-root */
50429 + log_error_write(srv, __FILE__, __LINE__, "s",
50430 + "Are you nuts ? Don't apply a SUID bit to this binary");
50432 + server_free(srv);
50437 + /* check document-root */
50438 + if (srv->config_storage[0]->document_root->used <= 1) {
50439 + log_error_write(srv, __FILE__, __LINE__, "s",
50440 + "document-root is not set\n");
50442 + server_free(srv);
50447 + if (plugins_load(srv)) {
50448 + log_error_write(srv, __FILE__, __LINE__, "s",
50449 + "loading plugins finally failed");
50451 + plugins_free(srv);
50452 + server_free(srv);
50458 + /* open pid file BEFORE chroot */
50459 + if (srv->srvconf.pid_file->used) {
50460 + 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))) {
50462 + if (errno != EEXIST) {
50463 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50464 + "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50468 + if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
50469 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50470 + "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50473 + if (!S_ISREG(st.st_mode)) {
50474 + log_error_write(srv, __FILE__, __LINE__, "sb",
50475 + "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
50479 + if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
50480 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50481 + "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
50487 + if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50488 + /* select limits itself
50490 * as it is a hard limit and will lead to a segfault we add some safety
50492 - srv->max_fds = FD_SETSIZE - 200;
50493 + fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
50494 + srv->max_fds = FD_SETSIZE - 4;
50496 srv->max_fds = 4096;
50498 @@ -636,7 +1006,7 @@
50499 #ifdef HAVE_VALGRIND_VALGRIND_H
50500 if (RUNNING_ON_VALGRIND) use_rlimit = 0;
50504 #ifdef HAVE_GETRLIMIT
50505 if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
50506 log_error_write(srv, __FILE__, __LINE__,
50507 @@ -644,13 +1014,13 @@
50513 if (use_rlimit && srv->srvconf.max_fds) {
50517 rlim.rlim_cur = srv->srvconf.max_fds;
50518 rlim.rlim_max = srv->srvconf.max_fds;
50521 if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
50522 log_error_write(srv, __FILE__, __LINE__,
50523 "ss", "couldn't set 'max filedescriptors'",
50524 @@ -659,7 +1029,7 @@
50528 - /* #372: solaris need some fds extra for devpoll */
50529 + /* #372: solaris need some fds extra for devpoll */
50530 if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
50532 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50533 @@ -677,33 +1047,33 @@
50534 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50535 /* don't raise the limit above FD_SET_SIZE */
50536 if (srv->max_fds > FD_SETSIZE - 200) {
50537 - log_error_write(srv, __FILE__, __LINE__, "sd",
50538 + log_error_write(srv, __FILE__, __LINE__, "sd",
50539 "can't raise max filedescriptors above", FD_SETSIZE - 200,
50540 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50548 /* set user and group */
50549 if (srv->srvconf.username->used) {
50550 if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
50551 - log_error_write(srv, __FILE__, __LINE__, "sb",
50552 + log_error_write(srv, __FILE__, __LINE__, "sb",
50553 "can't find username", srv->srvconf.username);
50558 if (pwd->pw_uid == 0) {
50559 log_error_write(srv, __FILE__, __LINE__, "s",
50560 "I will not set uid to 0\n");
50566 if (srv->srvconf.groupname->used) {
50567 if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
50568 - log_error_write(srv, __FILE__, __LINE__, "sb",
50569 + log_error_write(srv, __FILE__, __LINE__, "sb",
50570 "can't find groupname", srv->srvconf.groupname);
50573 @@ -713,15 +1083,15 @@
50579 /* we need root-perms for port < 1024 */
50580 if (0 != network_init(srv)) {
50587 -#ifdef HAVE_CHROOT
50588 +#ifdef HAVE_CHROOT
50589 if (srv->srvconf.changeroot->used) {
50592 @@ -761,7 +1131,7 @@
50595 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50596 - srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50597 + srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
50599 srv->max_fds = rlim.rlim_cur;
50601 @@ -775,18 +1145,18 @@
50603 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50604 /* don't raise the limit above FD_SET_SIZE */
50605 - if (srv->max_fds > FD_SETSIZE - 200) {
50606 - log_error_write(srv, __FILE__, __LINE__, "sd",
50607 - "can't raise max filedescriptors above", FD_SETSIZE - 200,
50608 + if (srv->max_fds > FD_SETSIZE - 4) {
50609 + log_error_write(srv, __FILE__, __LINE__, "sd",
50610 + "can't raise max filedescriptors above", FD_SETSIZE - 4,
50611 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50617 if (0 != network_init(srv)) {
50625 @@ -802,25 +1172,27 @@
50626 /* or use the default */
50627 srv->max_conns = srv->max_fds;
50631 if (HANDLER_GO_ON != plugins_call_init(srv)) {
50632 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
50636 network_close(srv);
50645 /* network is up, let's deamonize ourself */
50646 if (srv->srvconf.dont_daemonize == 0) daemonize();
50650 srv->gid = getgid();
50651 srv->uid = getuid();
50655 /* write pid file */
50656 if (pid_fd != -1) {
50657 buffer_copy_long(srv->tmp_buf, getpid());
50658 @@ -829,17 +1201,17 @@
50664 if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
50665 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
50669 network_close(srv);
50677 /* dump unused config-keys */
50678 for (i = 0; i < srv->config_context->used; i++) {
50679 array *config = ((data_config *)srv->config_context->data[i])->value;
50680 @@ -847,43 +1219,42 @@
50682 for (j = 0; config && j < config->used; j++) {
50683 data_unset *du = config->data[j];
50686 /* all var.* is known as user defined variable */
50687 if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
50691 if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
50692 - log_error_write(srv, __FILE__, __LINE__, "sbs",
50693 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50694 "WARNING: unknown config-key:",
50702 if (srv->config_deprecated) {
50703 - log_error_write(srv, __FILE__, __LINE__, "s",
50704 + log_error_write(srv, __FILE__, __LINE__, "s",
50705 "Configuration contains deprecated keys. Going down.");
50709 network_close(srv);
50716 - if (-1 == log_error_open(srv)) {
50717 - log_error_write(srv, __FILE__, __LINE__, "s",
50719 + if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
50720 + log_error_write(srv, __FILE__, __LINE__, "s",
50721 "opening errorlog failed, dying");
50725 network_close(srv);
50732 #ifdef HAVE_SIGACTION
50733 memset(&act, 0, sizeof(act));
50734 act.sa_handler = SIG_IGN;
50735 @@ -903,7 +1274,7 @@
50736 sigaction(SIGHUP, &act, NULL);
50737 sigaction(SIGALRM, &act, NULL);
50738 sigaction(SIGCHLD, &act, NULL);
50741 #elif defined(HAVE_SIGNAL)
50742 /* ignore the SIGPIPE from sendfile() */
50743 signal(SIGPIPE, SIG_IGN);
50744 @@ -914,20 +1285,20 @@
50745 signal(SIGCHLD, signal_handler);
50746 signal(SIGINT, signal_handler);
50751 signal(SIGALRM, signal_handler);
50754 /* setup periodic timer (1 second) */
50755 if (setitimer(ITIMER_REAL, &interval, NULL)) {
50756 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
50761 getitimer(ITIMER_REAL, &interval);
50766 /* start watcher and workers */
50767 num_childs = srv->srvconf.max_worker;
50768 if (num_childs > 0) {
50769 @@ -957,13 +1328,13 @@
50773 - if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
50774 + if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
50775 log_error_write(srv, __FILE__, __LINE__,
50776 "s", "fdevent_init failed");
50780 - * kqueue() is called here, select resets its internals,
50782 + * kqueue() is called here, select resets its internals,
50783 * all server sockets get their handlers
50786 @@ -971,7 +1342,7 @@
50788 network_close(srv);
50795 @@ -986,17 +1357,17 @@
50797 if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
50798 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
50799 - log_error_write(srv, __FILE__, __LINE__, "s",
50800 + log_error_write(srv, __FILE__, __LINE__, "s",
50801 "could not open a fam connection, dieing.");
50804 #ifdef HAVE_FAMNOEXISTS
50805 FAMNoExists(srv->stat_cache->fam);
50807 + srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
50809 - srv->stat_cache->fam_fcce_ndx = -1;
50810 - fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
50811 - fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
50812 + fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
50813 + fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
50817 @@ -1007,330 +1378,36 @@
50819 for (i = 0; i < srv->srv_sockets.used; i++) {
50820 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50821 - if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
50822 + if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
50823 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
50829 - while (!srv_shutdown) {
50834 - if (handle_sig_hup) {
50837 - /* reset notification */
50838 - handle_sig_hup = 0;
50841 - /* cycle logfiles */
50843 - switch(r = plugins_call_handle_sighup(srv)) {
50844 - case HANDLER_GO_ON:
50847 - log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
50851 - if (-1 == log_error_cycle(srv)) {
50852 - log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
50858 - if (handle_sig_alarm) {
50859 - /* a new second */
50862 - /* reset notification */
50863 - handle_sig_alarm = 0;
50866 - /* get current time */
50867 - min_ts = time(NULL);
50869 - if (min_ts != srv->cur_ts) {
50871 - connections *conns = srv->conns;
50874 - switch(r = plugins_call_handle_trigger(srv)) {
50875 - case HANDLER_GO_ON:
50877 - case HANDLER_ERROR:
50878 - log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50881 - log_error_write(srv, __FILE__, __LINE__, "d", r);
50885 - /* trigger waitpid */
50886 - srv->cur_ts = min_ts;
50888 - /* cleanup stat-cache */
50889 - stat_cache_trigger_cleanup(srv);
50891 - * check all connections for timeouts
50894 - for (ndx = 0; ndx < conns->used; ndx++) {
50899 - con = conns->ptr[ndx];
50901 - if (con->state == CON_STATE_READ ||
50902 - con->state == CON_STATE_READ_POST) {
50903 - if (con->request_count == 1) {
50904 - if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50907 - log_error_write(srv, __FILE__, __LINE__, "sd",
50908 - "connection closed - read-timeout:", con->fd);
50910 - connection_set_state(srv, con, CON_STATE_ERROR);
50914 - if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50917 - log_error_write(srv, __FILE__, __LINE__, "sd",
50918 - "connection closed - read-timeout:", con->fd);
50920 - connection_set_state(srv, con, CON_STATE_ERROR);
50926 - if ((con->state == CON_STATE_WRITE) &&
50927 - (con->write_request_ts != 0)) {
50929 - if (srv->cur_ts - con->write_request_ts > 60) {
50930 - log_error_write(srv, __FILE__, __LINE__, "sdd",
50931 - "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50935 - if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50938 - log_error_write(srv, __FILE__, __LINE__, "sbsosds",
50939 - "NOTE: a request for",
50940 - con->request.uri,
50941 - "timed out after writing",
50942 - con->bytes_written,
50943 - "bytes. We waited",
50944 - (int)con->conf.max_write_idle,
50945 - "seconds. If this a problem increase server.max-write-idle");
50947 - connection_set_state(srv, con, CON_STATE_ERROR);
50951 - /* we don't like div by zero */
50952 - if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50954 - if (con->traffic_limit_reached &&
50955 - (con->conf.kbytes_per_second == 0 ||
50956 - ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50957 - /* enable connection again */
50958 - con->traffic_limit_reached = 0;
50964 - connection_state_machine(srv, con);
50966 - con->bytes_written_cur_second = 0;
50967 - *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50971 - fprintf(stderr, "connection-state: ");
50975 - fprintf(stderr, "c[%d,%d]: %s ",
50978 - connection_get_state(con->state));
50982 - if (cs == 1) fprintf(stderr, "\n");
50986 - if (srv->sockets_disabled) {
50987 - /* our server sockets are disabled, why ? */
50989 - if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50990 - (srv->conns->used < srv->max_conns * 0.9) &&
50991 - (0 == graceful_shutdown)) {
50992 - for (i = 0; i < srv->srv_sockets.used; i++) {
50993 - server_socket *srv_socket = srv->srv_sockets.ptr[i];
50994 - fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50997 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50999 - srv->sockets_disabled = 0;
51002 - if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
51003 - (srv->conns->used > srv->max_conns) || /* out of connections */
51004 - (graceful_shutdown)) { /* graceful_shutdown */
51006 - /* disable server-fds */
51008 - for (i = 0; i < srv->srv_sockets.used; i++) {
51009 - server_socket *srv_socket = srv->srv_sockets.ptr[i];
51010 - fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
51012 - if (graceful_shutdown) {
51013 - /* we don't want this socket anymore,
51015 - * closing it right away will make it possible for
51016 - * the next lighttpd to take over (graceful restart)
51019 - fdevent_unregister(srv->ev, srv_socket->fd);
51020 - close(srv_socket->fd);
51021 - srv_socket->fd = -1;
51023 - /* network_close() will cleanup after us */
51027 - if (graceful_shutdown) {
51028 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
51029 - } else if (srv->conns->used > srv->max_conns) {
51030 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
51032 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
51035 - srv->sockets_disabled = 1;
51038 + lighty_mainloop(srv);
51040 - if (graceful_shutdown && srv->conns->used == 0) {
51041 - /* we are in graceful shutdown phase and all connections are closed
51042 - * we are ready to terminate without harming anyone */
51043 - srv_shutdown = 1;
51046 - /* we still have some fds to share */
51047 - if (srv->want_fds) {
51048 - /* check the fdwaitqueue for waiting fds */
51049 - int free_fds = srv->max_fds - srv->cur_fds - 16;
51052 - for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
51053 - connection_state_machine(srv, con);
51058 + status_counter_free();
51060 - if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
51061 - /* n is the number of events */
51066 - log_error_write(srv, __FILE__, __LINE__, "sd",
51072 - fdevent_handler handler;
51076 - fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx);
51077 - revents = fdevent_event_get_revent (srv->ev, fd_ndx);
51078 - fd = fdevent_event_get_fd (srv->ev, fd_ndx);
51079 - handler = fdevent_get_handler(srv->ev, fd);
51080 - context = fdevent_get_context(srv->ev, fd);
51082 - /* connection_handle_fdevent needs a joblist_append */
51084 - log_error_write(srv, __FILE__, __LINE__, "sdd",
51085 - "event for", fd, revents);
51087 - switch (r = (*handler)(srv, context, revents)) {
51088 - case HANDLER_FINISHED:
51089 - case HANDLER_GO_ON:
51090 - case HANDLER_WAIT_FOR_EVENT:
51091 - case HANDLER_WAIT_FOR_FD:
51093 - case HANDLER_ERROR:
51094 - /* should never happen */
51098 - log_error_write(srv, __FILE__, __LINE__, "d", r);
51101 - } while (--n > 0);
51102 - } else if (n < 0 && errno != EINTR) {
51103 - log_error_write(srv, __FILE__, __LINE__, "ss",
51104 - "fdevent_poll failed:",
51105 - strerror(errno));
51108 - for (ndx = 0; ndx < srv->joblist->used; ndx++) {
51109 - connection *con = srv->joblist->ptr[ndx];
51112 - connection_state_machine(srv, con);
51114 - switch(r = plugins_call_handle_joblist(srv, con)) {
51115 - case HANDLER_FINISHED:
51116 - case HANDLER_GO_ON:
51119 - log_error_write(srv, __FILE__, __LINE__, "d", r);
51123 - con->in_joblist = 0;
51126 - srv->joblist->used = 0;
51129 - if (srv->srvconf.pid_file->used &&
51130 + if (0 == graceful_restart &&
51131 + srv->srvconf.pid_file->used &&
51132 srv->srvconf.changeroot->used == 0) {
51133 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
51134 if (errno != EACCES && errno != EPERM) {
51135 - log_error_write(srv, __FILE__, __LINE__, "sbds",
51136 - "unlink failed for:",
51137 + log_error_write(srv, __FILE__, __LINE__, "sbds",
51138 + "unlink failed for:",
51139 srv->srvconf.pid_file,
51148 - log_error_close(srv);
51149 network_close(srv);
51150 connections_free(srv);
51158 --- ../lighttpd-1.4.11/src/settings.h 2005-08-11 01:26:41.000000000 +0300
51159 +++ lighttpd-1.4.12/src/settings.h 2006-07-16 00:26:04.000000000 +0300
51162 * max size of a buffer which will just be reset
51163 * to ->used = 0 instead of really freeing the buffer
51166 * 64kB (no real reason, just a guess)
51168 #define BUFFER_MAX_REUSE_SIZE (4 * 1024)
51171 * max size of the HTTP request header
51174 * 32k should be enough for everything (just a guess)
51178 #define MAX_HTTP_REQUEST_HEADER (32 * 1024)
51180 -typedef enum { HANDLER_UNSET,
51182 +typedef enum { HANDLER_UNSET,
51185 - HANDLER_COMEBACK,
51186 - HANDLER_WAIT_FOR_EVENT,
51187 + HANDLER_COMEBACK,
51188 + HANDLER_WAIT_FOR_EVENT,
51190 HANDLER_WAIT_FOR_FD
51192 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
51193 +++ lighttpd-1.4.12/src/spawn-fcgi.c 2006-07-16 00:26:04.000000000 +0300
51195 #include <sys/types.h>
51196 -#include <sys/time.h>
51197 #include <sys/stat.h>
51199 #include <stdlib.h>
51200 #include <string.h>
51203 -#include <unistd.h>
51207 #ifdef HAVE_CONFIG_H
51208 #include "config.h"
51218 #include "sys-socket.h"
51219 +#include "sys-files.h"
51221 #ifdef HAVE_SYS_WAIT_H
51222 #include <sys/wait.h>
51223 @@ -45,28 +43,28 @@
51225 int socket_type, status;
51226 struct timeval tv = { 0, 100 * 1000 };
51229 struct sockaddr_un fcgi_addr_un;
51230 struct sockaddr_in fcgi_addr_in;
51231 struct sockaddr *fcgi_addr;
51237 if (child_count < 2) {
51242 if (child_count > 256) {
51250 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
51253 fcgi_addr_un.sun_family = AF_UNIX;
51254 strcpy(fcgi_addr_un.sun_path, unixsocket);
51258 servlen = SUN_LEN(&fcgi_addr_un);
51260 @@ -84,50 +82,50 @@
51262 fcgi_addr_in.sin_port = htons(port);
51263 servlen = sizeof(fcgi_addr_in);
51266 socket_type = AF_INET;
51267 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
51271 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51272 - fprintf(stderr, "%s.%d\n",
51273 + fprintf(stderr, "%s.%d\n",
51274 __FILE__, __LINE__);
51279 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
51280 /* server is not up, spawn in */
51285 if (unixsocket) unlink(unixsocket);
51291 /* reopen socket */
51292 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
51293 - fprintf(stderr, "%s.%d\n",
51294 + fprintf(stderr, "%s.%d\n",
51295 __FILE__, __LINE__);
51300 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
51301 - fprintf(stderr, "%s.%d\n",
51302 + fprintf(stderr, "%s.%d\n",
51303 __FILE__, __LINE__);
51307 /* create socket */
51308 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
51309 - fprintf(stderr, "%s.%d: bind failed: %s\n",
51310 + fprintf(stderr, "%s.%d: bind failed: %s\n",
51311 __FILE__, __LINE__,
51317 if (-1 == listen(fcgi_fd, 1024)) {
51318 - fprintf(stderr, "%s.%d: fd = -1\n",
51319 + fprintf(stderr, "%s.%d: fd = -1\n",
51320 __FILE__, __LINE__);
51323 @@ -137,42 +135,45 @@
51331 char cgi_childs[64];
51338 + /* loose control terminal */
51341 /* is save as we limit to 256 childs */
51342 sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
51345 if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
51346 close(FCGI_LISTENSOCK_FILENO);
51347 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
51352 /* we don't need the client socket */
51353 for (i = 3; i < 256; i++) {
51358 /* create environment */
51361 putenv(cgi_childs);
51364 /* fork and replace shell */
51365 b = malloc(strlen("exec ") + strlen(appPath) + 1);
51366 strcpy(b, "exec ");
51367 strcat(b, appPath);
51371 execl("/bin/sh", "sh", "-c", b, NULL);
51380 @@ -180,47 +181,47 @@
51387 select(0, NULL, NULL, NULL, &tv);
51390 switch (waitpid(child, &status, WNOHANG)) {
51392 - fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
51393 + fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
51394 __FILE__, __LINE__,
51398 /* write pid file */
51399 if (pid_fd != -1) {
51400 /* assume a 32bit pid_t */
51404 snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
51407 write(pid_fd, pidbuf, strlen(pidbuf));
51417 if (WIFEXITED(status)) {
51418 - fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
51419 + fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
51420 __FILE__, __LINE__,
51421 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
51422 } else if (WIFSIGNALED(status)) {
51423 - fprintf(stderr, "%s.%d: child signaled: %d\n",
51424 + fprintf(stderr, "%s.%d: child signaled: %d\n",
51425 __FILE__, __LINE__,
51428 - fprintf(stderr, "%s.%d: child died somehow: %d\n",
51429 + fprintf(stderr, "%s.%d: child died somehow: %d\n",
51430 __FILE__, __LINE__,
51439 @@ -228,16 +229,16 @@
51440 __FILE__, __LINE__);
51452 void show_version () {
51453 char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
51454 -" - spawns fastcgi processes\n"
51455 +" - spawns fastcgi processes\n"
51457 write(1, b, strlen(b));
51459 @@ -265,7 +266,7 @@
51462 int main(int argc, char **argv) {
51463 - char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
51464 + char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
51465 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
51467 unsigned short port = 0;
51468 @@ -273,9 +274,9 @@
51474 i_am_root = (getuid() == 0);
51477 while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
51479 case 'f': fcgi_app = optarg; break;
51480 @@ -290,137 +291,137 @@
51481 case 'P': pid_file = optarg; /* PID file */ break;
51482 case 'v': show_version(); return 0;
51483 case 'h': show_help(); return 0;
51492 if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
51498 if (unixsocket && port) {
51499 - fprintf(stderr, "%s.%d: %s\n",
51500 + fprintf(stderr, "%s.%d: %s\n",
51501 __FILE__, __LINE__,
51502 "either a unix domain socket or a tcp-port, but not both\n");
51509 if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
51510 - fprintf(stderr, "%s.%d: %s\n",
51511 + fprintf(stderr, "%s.%d: %s\n",
51512 __FILE__, __LINE__,
51513 "path of the unix socket is too long\n");
51520 if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
51521 /* we are setuid-root */
51523 - fprintf(stderr, "%s.%d: %s\n",
51525 + fprintf(stderr, "%s.%d: %s\n",
51526 __FILE__, __LINE__,
51527 "Are you nuts ? Don't apply a SUID bit to this binary\n");
51536 (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
51538 if (errno != EEXIST) {
51539 - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51540 + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51541 __FILE__, __LINE__,
51542 pid_file, strerror(errno));
51549 /* ok, file exists */
51552 if (0 != stat(pid_file, &st)) {
51553 - fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
51554 + fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
51555 __FILE__, __LINE__,
51556 pid_file, strerror(errno));
51563 /* is it a regular file ? */
51566 if (!S_ISREG(st.st_mode)) {
51567 - fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51568 + fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51569 __FILE__, __LINE__,
51577 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
51578 - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51579 + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51580 __FILE__, __LINE__,
51581 pid_file, strerror(errno));
51590 struct group *grp = NULL;
51591 struct passwd *pwd = NULL;
51594 /* set user and group */
51598 if (NULL == (pwd = getpwnam(username))) {
51599 - fprintf(stderr, "%s.%d: %s, %s\n",
51600 + fprintf(stderr, "%s.%d: %s, %s\n",
51601 __FILE__, __LINE__,
51602 "can't find username", username);
51607 if (pwd->pw_uid == 0) {
51608 - fprintf(stderr, "%s.%d: %s\n",
51609 + fprintf(stderr, "%s.%d: %s\n",
51610 __FILE__, __LINE__,
51611 "I will not set uid to 0\n");
51618 if (NULL == (grp = getgrnam(groupname))) {
51619 - fprintf(stderr, "%s.%d: %s %s\n",
51620 + fprintf(stderr, "%s.%d: %s %s\n",
51621 __FILE__, __LINE__,
51622 - "can't find groupname",
51623 + "can't find groupname",
51627 if (grp->gr_gid == 0) {
51628 - fprintf(stderr, "%s.%d: %s\n",
51629 + fprintf(stderr, "%s.%d: %s\n",
51630 __FILE__, __LINE__,
51631 "I will not set gid to 0\n");
51638 if (-1 == chroot(changeroot)) {
51639 - fprintf(stderr, "%s.%d: %s %s\n",
51640 + fprintf(stderr, "%s.%d: %s %s\n",
51641 __FILE__, __LINE__,
51642 "chroot failed: ", strerror(errno));
51645 if (-1 == chdir("/")) {
51646 - fprintf(stderr, "%s.%d: %s %s\n",
51647 + fprintf(stderr, "%s.%d: %s %s\n",
51648 __FILE__, __LINE__,
51649 "chdir failed: ", strerror(errno));
51655 /* drop root privs */
51657 setgid(grp->gr_gid);
51658 @@ -428,7 +429,7 @@
51660 if (username) setuid(pwd->pw_uid);
51664 return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
51667 --- ../lighttpd-1.4.11/src/splaytree.c 2005-09-12 21:51:28.000000000 +0300
51668 +++ lighttpd-1.4.12/src/splaytree.c 2006-07-16 00:26:03.000000000 +0300
51669 @@ -56,19 +56,19 @@
51671 #define node_size splaytree_size
51673 -/* Splay using the key i (which may or may not be in the tree.)
51674 - * The starting root is t, and the tree used is defined by rat
51675 +/* Splay using the key i (which may or may not be in the tree.)
51676 + * The starting root is t, and the tree used is defined by rat
51677 * size fields are maintained */
51678 splay_tree * splaytree_splay (splay_tree *t, int i) {
51679 splay_tree N, *l, *r, *y;
51680 int comp, root_size, l_size, r_size;
51683 if (t == NULL) return t;
51684 N.left = N.right = NULL;
51686 root_size = node_size(t);
51687 l_size = r_size = 0;
51691 comp = compare(i, t->key);
51693 @@ -120,7 +120,7 @@
51695 r_size -= 1+node_size(y->right);
51699 l->right = t->left; /* assemble */
51700 r->left = t->right;
51702 --- ../lighttpd-1.4.11/src/splaytree.h 2005-09-12 21:51:13.000000000 +0300
51703 +++ lighttpd-1.4.12/src/splaytree.h 2006-07-16 00:26:03.000000000 +0300
51705 /* This macro returns the size of a node. Unlike "x->size", */
51706 /* it works even if x=NULL. The test could be avoided by using */
51707 /* a special version of NULL which was a real node with size 0. */
51712 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
51713 +++ lighttpd-1.4.12/src/stat_cache.c 2006-07-18 13:03:40.000000000 +0300
51715 #include <stdlib.h>
51716 #include <string.h>
51718 -#include <unistd.h>
51721 #include <assert.h>
51725 #include "sys-mmap.h"
51727 -/* NetBSD 1.3.x needs it */
51728 -#ifndef MAP_FAILED
51729 -# define MAP_FAILED -1
51732 -#ifndef O_LARGEFILE
51733 -# define O_LARGEFILE 0
51736 -#ifndef HAVE_LSTAT
51737 -#define lstat stat
51739 +#include "sys-files.h"
51740 +#include "sys-strings.h"
51743 /* enables debug code for testing if all nodes in the stat-cache as accessable */
51746 * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
51748 - * if the stat()-cache is queried we check if the version id for the directory is the
51749 - * same and return immediatly.
51750 + * if the stat()-cache is queried we check if the version id for the directory is the
51751 + * same and return immediatly.
51755 @@ -62,17 +50,17 @@
51756 * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
51758 * stat <<-> directory <-> FAMRequest
51760 - * if file is deleted, directory is dirty, file is rechecked ...
51762 + * if file is deleted, directory is dirty, file is rechecked ...
51763 * if directory is deleted, directory mapping is removed
51777 @@ -83,16 +71,16 @@
51779 * - the hash-key is used as sorting criteria for a tree
51780 * - a splay-tree is used as we can use the caching effect of it
51784 /* we want to cleanup the stat-cache every few seconds, let's say 10
51786 * - remove entries which are outdated since 30s
51787 * - remove entries which are fresh but havn't been used since 60s
51788 * - if we don't have a stat-cache entry for a directory, release it from the monitor
51792 -#ifdef DEBUG_STAT_CACHE
51793 +#ifdef DEBUG_STAT_CACHE
51797 @@ -105,15 +93,16 @@
51799 stat_cache *stat_cache_init(void) {
51800 stat_cache *fc = NULL;
51803 fc = calloc(1, sizeof(*fc));
51806 fc->dir_name = buffer_init();
51808 fc->fam = calloc(1, sizeof(*fc->fam));
51809 + fc->sock = iosocket_init();
51812 -#ifdef DEBUG_STAT_CACHE
51813 +#ifdef DEBUG_STAT_CACHE
51817 @@ -122,24 +111,24 @@
51819 static stat_cache_entry * stat_cache_entry_init(void) {
51820 stat_cache_entry *sce = NULL;
51823 sce = calloc(1, sizeof(*sce));
51826 sce->name = buffer_init();
51827 sce->etag = buffer_init();
51828 sce->content_type = buffer_init();
51834 static void stat_cache_entry_free(void *data) {
51835 stat_cache_entry *sce = data;
51839 buffer_free(sce->etag);
51840 buffer_free(sce->name);
51841 buffer_free(sce->content_type);
51847 @@ -148,22 +137,22 @@
51848 fam_dir_entry *fam_dir = NULL;
51850 fam_dir = calloc(1, sizeof(*fam_dir));
51853 fam_dir->name = buffer_init();
51859 static void fam_dir_entry_free(void *data) {
51860 fam_dir_entry *fam_dir = data;
51863 if (!fam_dir) return;
51866 FAMCancelMonitor(fam_dir->fc, fam_dir->req);
51869 buffer_free(fam_dir->name);
51870 free(fam_dir->req);
51876 @@ -174,7 +163,7 @@
51877 splay_tree *node = sc->files;
51879 osize = sc->files->size;
51882 stat_cache_entry_free(node->data);
51883 sc->files = splaytree_delete(sc->files, node->key);
51885 @@ -187,12 +176,12 @@
51888 splay_tree *node = sc->dirs;
51891 osize = sc->dirs->size;
51893 fam_dir_entry_free(node->data);
51894 sc->dirs = splaytree_delete(sc->dirs, node->key);
51898 assert(NULL == sc->dirs);
51900 @@ -202,6 +191,7 @@
51904 + iosocket_free(sc->sock);
51908 @@ -212,7 +202,7 @@
51909 static int stat_cache_attr_get(buffer *buf, char *name) {
51915 buffer_prepare_copy(buf, attrlen);
51917 @@ -251,15 +241,15 @@
51920 events = FAMPending(sc->fam);
51923 for (i = 0; i < events; i++) {
51925 fam_dir_entry *fam_dir;
51930 FAMNextEvent(sc->fam, &fe);
51936 @@ -280,7 +270,7 @@
51938 sc->dirs = splaytree_splay(sc->dirs, ndx);
51942 if (node && (node->key == ndx)) {
51943 int osize = splaytree_size(sc->dirs);
51945 @@ -298,17 +288,15 @@
51947 if (revent & FDEVENT_HUP) {
51948 /* fam closed the connection */
51949 - srv->stat_cache->fam_fcce_ndx = -1;
51951 - fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
51952 - fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
51953 + fdevent_event_del(srv->ev, sc->sock);
51954 + fdevent_unregister(srv->ev, sc->sock);
51963 return HANDLER_GO_ON;
51966 @@ -332,7 +320,7 @@
51972 * - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
51973 * - HANDLER_ERROR on stat() failed -> see errno for problem
51975 @@ -348,16 +336,16 @@
51979 -#ifdef DEBUG_STAT_CACHE
51980 +#ifdef DEBUG_STAT_CACHE
51985 splay_tree *file_node = NULL;
51992 * check if the directory for this file has changed
51995 @@ -366,23 +354,23 @@
51996 file_ndx = hashme(name);
51997 sc->files = splaytree_splay(sc->files, file_ndx);
51999 -#ifdef DEBUG_STAT_CACHE
52000 +#ifdef DEBUG_STAT_CACHE
52001 for (i = 0; i < ctrl.used; i++) {
52002 if (ctrl.ptr[i] == file_ndx) break;
52006 if (sc->files && (sc->files->key == file_ndx)) {
52007 -#ifdef DEBUG_STAT_CACHE
52008 +#ifdef DEBUG_STAT_CACHE
52009 /* it was in the cache */
52010 assert(i < ctrl.used);
52013 - /* we have seen this file already and
52015 + /* we have seen this file already and
52016 * don't stat() it again in the same second */
52018 file_node = sc->files;
52021 sce = file_node->data;
52023 /* check if the name is the same, we might have a collision */
52024 @@ -390,7 +378,7 @@
52025 if (buffer_is_equal(name, sce->name)) {
52026 if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
52027 if (sce->stat_ts == srv->cur_ts) {
52030 return HANDLER_GO_ON;
52033 @@ -400,15 +388,15 @@
52034 * file_node is used by the FAM check below to see if we know this file
52035 * and if we can save a stat().
52037 - * BUT, the sce is not reset here as the entry into the cache is ok, we
52038 + * BUT, the sce is not reset here as the entry into the cache is ok, we
52039 * it is just not pointing to our requested file.
52047 -#ifdef DEBUG_STAT_CACHE
52048 +#ifdef DEBUG_STAT_CACHE
52049 if (i != ctrl.used) {
52050 fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
52052 @@ -424,23 +412,23 @@
52055 dir_ndx = hashme(sc->dir_name);
52058 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
52061 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
52062 dir_node = sc->dirs;
52066 if (dir_node && file_node) {
52067 /* we found a file */
52070 sce = file_node->data;
52071 fam_dir = dir_node->data;
52074 if (fam_dir->version == sce->dir_version) {
52075 /* the stat()-cache entry is still ok */
52080 return HANDLER_GO_ON;
52083 @@ -448,7 +436,7 @@
52089 * - open() + fstat() on a named-pipe results in a (intended) hang.
52090 * - stat() if regualar file + open() to see if we can read from it is better
52092 @@ -469,16 +457,16 @@
52099 osize = sc->files->size;
52102 sce = stat_cache_entry_init();
52103 buffer_copy_string_buffer(sce->name, name);
52105 - sc->files = splaytree_insert(sc->files, file_ndx, sce);
52106 -#ifdef DEBUG_STAT_CACHE
52108 + sc->files = splaytree_insert(sc->files, file_ndx, sce);
52109 +#ifdef DEBUG_STAT_CACHE
52110 if (ctrl.size == 0) {
52113 @@ -499,29 +487,29 @@
52115 sce->stat_ts = srv->cur_ts;
52117 - /* catch the obvious symlinks
52118 + /* catch the obvious symlinks
52120 * this is not a secure check as we still have a race-condition between
52121 - * the stat() and the open. We can only solve this by
52122 + * the stat() and the open. We can only solve this by
52123 * 1. open() the file
52124 * 2. fstat() the fd
52126 * and keeping the file open for the rest of the time. But this can
52127 * only be done at network level.
52131 if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
52132 return HANDLER_ERROR;
52135 - if (S_ISREG(st.st_mode)) {
52136 + if (S_ISREG(st.st_mode)) {
52137 /* determine mimetype */
52138 buffer_reset(sce->content_type);
52141 for (k = 0; k < con->conf.mimetypes->used; k++) {
52142 data_string *ds = (data_string *)con->conf.mimetypes->data[k];
52143 buffer *type = ds->key;
52146 if (type->used == 0) continue;
52148 /* check if the right side is the same */
52149 @@ -538,8 +526,10 @@
52150 stat_cache_attr_get(sce->content_type, name->ptr);
52153 + } else if (S_ISDIR(st.st_mode)) {
52154 + etag_create(sce->etag, &(sce->st));
52160 (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
52161 @@ -549,19 +539,19 @@
52162 fam_dir->fc = sc->fam;
52164 buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
52167 fam_dir->version = 1;
52170 fam_dir->req = calloc(1, sizeof(FAMRequest));
52172 - if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
52174 + if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
52175 fam_dir->req, fam_dir)) {
52177 - log_error_write(srv, __FILE__, __LINE__, "sbs",
52178 - "monitoring dir failed:",
52181 + log_error_write(srv, __FILE__, __LINE__, "sbs",
52182 + "monitoring dir failed:",
52184 FamErrlist[FAMErrno]);
52187 fam_dir_entry_free(fam_dir);
52190 @@ -570,7 +560,7 @@
52191 osize = sc->dirs->size;
52194 - sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
52195 + sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
52197 assert(sc->dirs->data == fam_dir);
52198 assert(osize == (sc->dirs->size - 1));
52199 @@ -578,9 +568,9 @@
52201 fam_dir = dir_node->data;
52205 /* bind the fam_fc to the stat() cache entry */
52209 sce->dir_version = fam_dir->version;
52210 sce->dir_ndx = dir_ndx;
52211 @@ -594,11 +584,11 @@
52215 - * remove stat() from cache which havn't been stat()ed for
52216 + * remove stat() from cache which havn't been stat()ed for
52217 * more than 10 seconds
52220 - * walk though the stat-cache, collect the ids which are too old
52222 + * walk though the stat-cache, collect the ids which are too old
52223 * and remove them in a second loop
52226 @@ -639,9 +629,9 @@
52227 sc->files = splaytree_splay(sc->files, ndx);
52232 if (node && (node->key == ndx)) {
52233 -#ifdef DEBUG_STAT_CACHE
52234 +#ifdef DEBUG_STAT_CACHE
52236 int osize = splaytree_size(sc->files);
52237 stat_cache_entry *sce = node->data;
52238 @@ -649,7 +639,7 @@
52239 stat_cache_entry_free(node->data);
52240 sc->files = splaytree_delete(sc->files, ndx);
52242 -#ifdef DEBUG_STAT_CACHE
52243 +#ifdef DEBUG_STAT_CACHE
52244 for (j = 0; j < ctrl.used; j++) {
52245 if (ctrl.ptr[j] == ndx) {
52246 ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
52247 --- ../lighttpd-1.4.11/src/status_counter.c 1970-01-01 03:00:00.000000000 +0300
52248 +++ lighttpd-1.4.12/src/status_counter.c 2006-07-19 20:02:55.000000000 +0300
52250 +#include <stdlib.h>
52252 +#include "status_counter.h"
52254 + * The status array can carry all the status information you want
52255 + * the key to the array is <module-prefix>.<name>
52256 + * and the values are counters
52259 + * fastcgi.backends = 10
52260 + * fastcgi.active-backends = 6
52261 + * fastcgi.backend.<key>.load = 24
52262 + * fastcgi.backend.<key>....
52264 + * fastcgi.backend.<key>.disconnects = ...
52267 +static array *counters = NULL;
52269 +void status_counter_init(void) {
52270 + counters = array_init();
52272 +void status_counter_free(void) {
52273 + array_free(counters);
52276 +array *status_counter_get_array(void) {
52280 +data_integer *status_counter_get_counter(const char *s, size_t len) {
52281 + data_integer *di;
52282 + array *status = status_counter_get_array();
52284 + if (NULL == (di = (data_integer *)array_get_element(status, s))) {
52285 + /* not found, create it */
52287 + if (NULL == (di = (data_integer *)array_get_unused_element(status, TYPE_INTEGER))) {
52288 + di = data_integer_init();
52290 + buffer_copy_string_len(di->key, s, len);
52293 + array_insert_unique(status, (data_unset *)di);
52298 +/* dummies of the statistic framework functions
52299 + * they will be moved to a statistics.c later */
52300 +int status_counter_inc(const char *s, size_t len) {
52301 + data_integer *di = status_counter_get_counter(s, len);
52308 +int status_counter_dec(const char *s, size_t len) {
52309 + data_integer *di = status_counter_get_counter(s, len);
52311 + if (di->value > 0) di->value--;
52316 +int status_counter_set(const char *s, size_t len, int val) {
52317 + data_integer *di = status_counter_get_counter(s, len);
52325 --- ../lighttpd-1.4.11/src/status_counter.h 1970-01-01 03:00:00.000000000 +0300
52326 +++ lighttpd-1.4.12/src/status_counter.h 2006-07-19 20:02:55.000000000 +0300
52328 +#ifndef _STATUS_COUNTER_H_
52329 +#define _STATUS_COUNTER_H_
52331 +#include <sys/types.h>
52333 +#include "array.h"
52335 +void status_counter_init(void);
52336 +void status_counter_free(void);
52337 +array *status_counter_get_array(void);
52338 +data_integer *status_counter_get_counter(const char *s, size_t len);
52339 +int status_counter_inc(const char *s, size_t len);
52340 +int status_counter_dec(const char *s, size_t len);
52341 +int status_counter_set(const char *s, size_t len, int val);
52344 --- ../lighttpd-1.4.11/src/stream.c 2005-09-23 21:50:15.000000000 +0300
52345 +++ lighttpd-1.4.12/src/stream.c 2006-07-16 00:26:04.000000000 +0300
52347 #include <sys/types.h>
52348 #include <sys/stat.h>
52350 -#include <unistd.h>
52353 #include "stream.h"
52357 #include "sys-mmap.h"
52358 +#include "sys-files.h"
52361 # define O_BINARY 0
52362 @@ -19,39 +19,39 @@
52366 -#elif defined __WIN32
52367 +#elif defined _WIN32
52375 if (-1 == stat(fn->ptr, &st)) {
52380 f->size = st.st_size;
52383 if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
52388 f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
52394 if (MAP_FAILED == f->start) {
52398 -#elif defined __WIN32
52399 - fh = CreateFile(fn->ptr,
52404 - FILE_ATTRIBUTE_READONLY,
52405 +#elif defined _WIN32
52406 + fh = CreateFile(fn->ptr,
52411 + FILE_ATTRIBUTE_READONLY,
52414 if (!fh) return -1;
52419 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
52420 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
52421 FORMAT_MESSAGE_FROM_SYSTEM,
52430 p = MapViewOfFile(mh,
52437 -# error no mmap found
52438 +# error no mmap found
52445 --- ../lighttpd-1.4.11/src/sys-files.h 1970-01-01 03:00:00.000000000 +0300
52446 +++ lighttpd-1.4.12/src/sys-files.h 2006-07-16 00:26:04.000000000 +0300
52448 +#ifndef _SYS_FILES_H_
52449 +#define _SYS_FILES_H_
52451 +#define DIR_SEPERATOR_UNIX '/'
52452 +#define DIR_SEPERATOR_WIN '\\'
52455 +#include <windows.h>
52456 +#include <io.h> /* open */
52457 +#include <direct.h> /* chdir */
52459 +#include "buffer.h"
52461 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
52463 +#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
52465 +#define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
52466 +#define S_ISCHR(mode) __S_ISTYPE((mode), _S_IFCHR)
52467 +#define S_ISBLK(mode) __S_ISTYPE((mode), _S_IFBLK)
52468 +#define S_ISREG(mode) __S_ISTYPE((mode), _S_IFREG)
52469 +/* we don't support symlinks */
52470 +#define S_ISLNK(mode) 0
52472 +#define lstat stat
52473 +#define mkstemp mktemp
52474 +#define mkdir(x, y) mkdir(x)
52477 + const char *d_name;
52482 + WIN32_FIND_DATA finddata;
52483 + struct dirent dent;
52486 +DIR *opendir(const char *dn);
52487 +struct dirent *readdir(DIR *d);
52488 +void closedir(DIR *d);
52490 +buffer *filename_unix2local(buffer *b);
52491 +buffer *pathname_unix2local(buffer *b);
52494 +#include <unistd.h>
52495 +#include <dirent.h>
52497 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
52499 +#define filename_unix2local(x) (x)
52500 +#define pathname_unix2local(x) (x)
52503 +#define PATHNAME_APPEND_SLASH(x) \
52504 + if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
52505 + char sl[2] = { DIR_SEPERATOR, 0 }; \
52506 + BUFFER_APPEND_STRING_CONST(x, sl); \
52509 +#ifndef O_LARGEFILE
52510 +# define O_LARGEFILE 0
52515 --- ../lighttpd-1.4.11/src/sys-mmap.h 2005-08-11 01:26:34.000000000 +0300
52516 +++ lighttpd-1.4.12/src/sys-mmap.h 2006-07-16 00:26:04.000000000 +0300
52518 #ifndef WIN32_MMAP_H
52519 #define WIN32_MMAP_H
52524 #define MAP_FAILED -1
52525 #define PROT_SHARED 0
52526 --- ../lighttpd-1.4.11/src/sys-process.h 1970-01-01 03:00:00.000000000 +0300
52527 +++ lighttpd-1.4.12/src/sys-process.h 2006-07-16 00:26:04.000000000 +0300
52529 +#ifndef _SYS_PROCESS_H_
52530 +#define _SYS_PROCESS_H_
52533 +#include <process.h>
52535 +/* win32 has no fork() */
52536 +#define kill(x, y)
52537 +#define getpid() 0
52540 +#include <sys/wait.h>
52541 +#include <unistd.h>
52546 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
52547 +++ lighttpd-1.4.12/src/sys-socket.h 2006-07-19 20:02:55.000000000 +0300
52549 #ifndef WIN32_SOCKET_H
52550 #define WIN32_SOCKET_H
52555 #include <winsock2.h>
52557 #define ECONNRESET WSAECONNRESET
52558 #define EINPROGRESS WSAEINPROGRESS
52559 #define EALREADY WSAEALREADY
52560 +#define ENOTCONN WSAENOTCONN
52561 +#define EWOULDBLOCK WSAEWOULDBLOCK
52562 #define ioctl ioctlsocket
52563 #define hstrerror(x) ""
52564 +#define STDIN_FILENO 0
52565 +#define STDOUT_FILENO 1
52566 +#define STDERR_FILENO 2
52567 +#define ssize_t int
52569 +int inet_aton(const char *cp, struct in_addr *inp);
52570 +#define HAVE_INET_ADDR
52571 +#undef HAVE_INET_ATON
52574 #include <sys/socket.h>
52575 #include <sys/ioctl.h>
52577 #include <sys/un.h>
52578 #include <arpa/inet.h>
52581 +#define SUN_LEN(su) \
52582 + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
52585 +#define closesocket(x) close(x)
52588 +#endif /* !_WIN32 */
52590 +#ifdef HAVE_INET_NTOP
52591 +# define HAVE_IPV6
52596 + struct sockaddr_in6 ipv6;
52598 + struct sockaddr_in ipv4;
52599 +#ifdef HAVE_SYS_UN_H
52600 + struct sockaddr_un un;
52602 + struct sockaddr plain;
52606 --- ../lighttpd-1.4.11/src/sys-strings.h 1970-01-01 03:00:00.000000000 +0300
52607 +++ lighttpd-1.4.12/src/sys-strings.h 2006-07-16 00:26:03.000000000 +0300
52609 +#ifndef _SYS_STRINGS_H_
52610 +#define _SYS_STRINGS_H_
52613 +#define strcasecmp stricmp
52614 +#define strncasecmp strnicmp
52615 +#define strtoll(p, e, b) _strtoi64(p, e, b)
52620 --- ../lighttpd-1.4.11/tests/LightyTest.pm 2006-01-14 20:32:31.000000000 +0200
52621 +++ lighttpd-1.4.12/tests/LightyTest.pm 2006-07-18 13:03:40.000000000 +0300
52622 @@ -87,14 +87,16 @@
52623 # pre-process configfile if necessary
52626 - unlink($self->{TESTDIR}."/tmp/cfg.file");
52627 - system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
52628 + $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
52629 + $ENV{'PORT'} = $self->{PORT};
52631 unlink($self->{LIGHTTPD_PIDFILE});
52633 - system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
52634 + if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
52635 + system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
52636 + } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
52637 + system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=valgrind ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
52639 - system("valgrind --tool=memcheck --show-reachable=yes --leak-check=yes --logfile=foo ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH}." &");
52640 + system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
52643 select(undef, undef, undef, 0.1);
52644 @@ -184,7 +186,7 @@
52645 (my $h = $1) =~ tr/[A-Z]/[a-z]/;
52647 if (defined $resp_hdr{$h}) {
52648 - diag(sprintf("header %s is duplicated: %s and %s\n",
52649 + diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
52650 $h, $resp_hdr{$h}, $2));
52652 $resp_hdr{$h} = $2;
52653 @@ -196,6 +198,9 @@
52657 + $t->{etag} = $resp_hdr{'etag'};
52658 + $t->{date} = $resp_hdr{'date'};
52661 if (defined $resp_hdr{"content-length"}) {
52662 $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
52663 --- ../lighttpd-1.4.11/tests/Makefile.am 2005-09-16 15:48:40.000000000 +0300
52664 +++ lighttpd-1.4.12/tests/Makefile.am 2006-07-16 00:26:05.000000000 +0300
52665 @@ -39,10 +39,18 @@
52680 + proxy-backend-1.conf \
52681 + proxy-backend-2.conf
52684 TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir)
52685 --- ../lighttpd-1.4.11/tests/bug-06.conf 2005-08-27 17:44:19.000000000 +0300
52686 +++ lighttpd-1.4.12/tests/bug-06.conf 2006-07-16 00:26:04.000000000 +0300
52688 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52689 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52690 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52691 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52693 ## bind to port (default: 80)
52697 ## bind to localhost (default: all interfaces)
52698 server.bind = "localhost"
52699 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52700 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52701 server.name = "www.example.org"
52702 server.tag = "Apache 1.3.29"
52705 ######################## MODULE CONFIG ############################
52708 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52709 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52711 mimetype.assign = ( ".png" => "image/png",
52712 ".jpg" => "image/jpeg",
52714 ".c" => "text/plain",
52715 ".conf" => "text/plain" )
52717 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52718 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52719 compress.filetype = ("text/plain", "text/html")
52721 setenv.add-environment = ( "TRAC_ENV" => "foo")
52723 "host" => "127.0.0.1",
52725 # "mode" => "authorizer",
52726 -# "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52727 +# "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52731 @@ -106,7 +106,7 @@
52732 ssl.pemfile = "server.pem"
52734 auth.backend = "plain"
52735 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52736 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52737 auth.backend.plain.groupfile = "lighttpd.group"
52739 auth.backend.ldap.hostname = "localhost"
52740 @@ -149,15 +149,15 @@
52741 status.config-url = "/server-config"
52743 simple-vhost.document-root = "pages"
52744 -simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
52745 +simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
52746 simple-vhost.default-host = "www.example.org"
52748 $HTTP["host"] == "vvv.example.org" {
52749 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52750 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52753 $HTTP["host"] == "zzz.example.org" {
52754 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52755 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52756 server.name = "zzz.example.org"
52759 --- ../lighttpd-1.4.11/tests/bug-12.conf 2005-08-27 17:44:19.000000000 +0300
52760 +++ lighttpd-1.4.12/tests/bug-12.conf 2006-07-16 00:26:04.000000000 +0300
52762 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52763 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52764 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52765 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52767 ## bind to port (default: 80)
52771 ## bind to localhost (default: all interfaces)
52772 server.bind = "localhost"
52773 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52774 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52775 server.name = "www.example.org"
52776 server.tag = "Apache 1.3.29"
52779 ######################## MODULE CONFIG ############################
52782 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52783 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52785 mimetype.assign = ( ".png" => "image/png",
52786 ".jpg" => "image/jpeg",
52788 ".c" => "text/plain",
52789 ".conf" => "text/plain" )
52791 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52792 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52793 compress.filetype = ("text/plain", "text/html")
52795 setenv.add-environment = ( "TRAC_ENV" => "foo")
52797 "host" => "127.0.0.1",
52799 # "mode" => "authorizer",
52800 -# "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52801 +# "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52805 @@ -108,7 +108,7 @@
52806 ssl.pemfile = "server.pem"
52808 auth.backend = "plain"
52809 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52810 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52811 auth.backend.plain.groupfile = "lighttpd.group"
52813 auth.backend.ldap.hostname = "localhost"
52814 @@ -151,15 +151,15 @@
52815 status.config-url = "/server-config"
52817 simple-vhost.document-root = "pages"
52818 -simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
52819 +simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
52820 simple-vhost.default-host = "www.example.org"
52822 $HTTP["host"] == "vvv.example.org" {
52823 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52824 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52827 $HTTP["host"] == "zzz.example.org" {
52828 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52829 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52830 server.name = "zzz.example.org"
52833 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
52834 +++ lighttpd-1.4.12/tests/cachable.t 2006-07-18 13:03:40.000000000 +0300
52836 +#!/usr/bin/env perl
52838 + # add current source dir to the include-path
52839 + # we need this for make distcheck
52840 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
52841 + unshift @INC, $srcdir;
52846 +use Test::More tests => 12;
52849 +my $tf = LightyTest->new();
52852 +$tf->{CONFIGFILE} = 'lighttpd.conf';
52854 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
52856 +## check if If-Modified-Since, If-None-Match works
52858 +$t->{REQUEST} = ( <<EOF
52860 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
52863 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52864 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
52866 +$t->{REQUEST} = ( <<EOF
52868 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52871 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
52872 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
52874 +my $now = $t->{date};
52876 +$t->{REQUEST} = ( <<EOF
52878 +If-Modified-Since: $now
52881 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52882 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
52884 +$t->{REQUEST} = ( <<EOF
52886 +If-Modified-Since: $now; foo
52889 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52890 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
52892 +$t->{REQUEST} = ( <<EOF
52894 +If-None-Match: foo
52897 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
52898 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52900 +my $etag = $t->{etag};
52902 +$t->{REQUEST} = ( <<EOF
52904 +If-None-Match: $etag
52907 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52908 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52910 +$t->{REQUEST} = ( <<EOF
52912 +If-None-Match: $etag
52913 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52916 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52917 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
52919 +$t->{REQUEST} = ( <<EOF
52921 +If-None-Match: $etag
52922 +If-Modified-Since: $now; foo
52925 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52926 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
52928 +$t->{REQUEST} = ( <<EOF
52930 +If-None-Match: Foo
52931 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52934 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52935 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
52937 +$t->{REQUEST} = ( <<EOF
52939 +If-None-Match: $etag
52940 +If-Modified-Since: $now foo
52943 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
52944 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
52946 +ok($tf->stop_proc == 0, "Stopping lighttpd");
52948 --- ../lighttpd-1.4.11/tests/condition.conf 2005-08-27 17:44:19.000000000 +0300
52949 +++ lighttpd-1.4.12/tests/condition.conf 2006-07-16 00:26:05.000000000 +0300
52951 debug.log-request-handling = "enable"
52952 debug.log-condition-handling = "enable"
52954 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52955 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52956 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52957 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52959 ## bind to port (default: 80)
52962 ## bind to localhost (default: all interfaces)
52963 server.bind = "localhost"
52964 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52965 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52966 server.name = "www.example.org"
52967 server.tag = "Apache 1.3.29"
52969 @@ -22,25 +22,25 @@
52970 ######################## MODULE CONFIG ############################
52973 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52974 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52976 mimetype.assign = ( ".html" => "text/html" )
52978 url.redirect = ("^" => "/default")
52980 $HTTP["host"] == "www.example.org" {
52981 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52982 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52983 server.name = "www.example.org"
52984 url.redirect = ("^" => "/match_1")
52986 else $HTTP["host"] == "test1.example.org" {
52987 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52988 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52989 server.name = "test1.example.org"
52990 url.redirect = ("^" => "/match_2")
52993 else $HTTP["host"] == "test2.example.org" {
52994 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52995 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52996 server.name = "test2.example.org"
52997 url.redirect = ("^" => "/match_3")
53002 else $HTTP["host"] == "test3.example.org" {
53003 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53004 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53005 server.name = "test3.example.org"
53006 url.redirect = ("^" => "/match_4")
53008 --- ../lighttpd-1.4.11/tests/core-keepalive.t 2005-11-17 15:54:19.000000000 +0200
53009 +++ lighttpd-1.4.12/tests/core-keepalive.t 2006-07-16 00:26:05.000000000 +0300
53012 GET /12345.txt HTTP/1.0
53013 Host: 123.example.org
53014 -Connection: keep-alive
53018 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53019 --- ../lighttpd-1.4.11/tests/default.conf 1970-01-01 03:00:00.000000000 +0300
53020 +++ lighttpd-1.4.12/tests/default.conf 2006-07-16 00:26:05.000000000 +0300
53022 +server.name = "www.example.org"
53024 +## bind to port (default: 80)
53025 +server.port = env.PORT
53028 +server.dir-listing = "enable"
53030 +#server.event-handler = "linux-sysepoll"
53031 +#server.event-handler = "linux-rtsig"
53033 +server.modules = (
53040 + "mod_simple_vhost",
53042 + "mod_secdownload",
53049 + "mod_accesslog" )
53051 +server.indexfiles = ( "index.php", "index.html",
53052 + "index.htm", "default.htm" )
53054 +ssi.extension = ( ".shtml" )
53056 +######################## MODULE CONFIG ############################
53059 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53060 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53062 +mimetype.assign = ( ".png" => "image/png",
53063 + ".jpg" => "image/jpeg",
53064 + ".jpeg" => "image/jpeg",
53065 + ".gif" => "image/gif",
53066 + ".html" => "text/html",
53067 + ".htm" => "text/html",
53068 + ".pdf" => "application/pdf",
53069 + ".swf" => "application/x-shockwave-flash",
53070 + ".spl" => "application/futuresplash",
53071 + ".txt" => "text/plain",
53072 + ".tar.gz" => "application/x-tgz",
53073 + ".tgz" => "application/x-tgz",
53074 + ".gz" => "application/x-gzip",
53075 + ".c" => "text/plain",
53076 + ".conf" => "text/plain" )
53078 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53079 +compress.filetype = ("text/plain", "text/html")
53081 +setenv.add-environment = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
53083 +cgi.assign = ( ".pl" => "/usr/bin/perl",
53084 + ".cgi" => "/usr/bin/perl",
53085 + ".py" => "/usr/bin/python" )
53087 +userdir.include-user = ( "jan" )
53088 +userdir.path = "/"
53090 +ssl.engine = "disable"
53091 +ssl.pemfile = "server.pem"
53093 +auth.backend = "plain"
53094 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53095 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53096 +auth.backend.plain.groupfile = "lighttpd.group"
53098 +auth.backend.ldap.hostname = "localhost"
53099 +auth.backend.ldap.base-dn = "dc=my-domain,dc=com"
53100 +auth.backend.ldap.filter = "(uid=$)"
53102 +auth.require = ( "/server-status" =>
53104 + "method" => "digest",
53105 + "realm" => "download archiv",
53106 + "require" => "valid-user"
53110 + "method" => "basic",
53111 + "realm" => "download archiv",
53112 + "require" => "user=jan"
53114 + "/server-config" =>
53116 + "method" => "basic",
53117 + "realm" => "download archiv",
53118 + "require" => "valid-user"
53122 +url.access-deny = ( "~", ".inc")
53124 +url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
53126 +url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
53127 + "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
53129 +#### status module
53130 +status.status-url = "/server-status"
53131 +status.config-url = "/server-config"
53133 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries 2006-03-09 19:21:49.000000000 +0200
53134 +++ lighttpd-1.4.12/tests/docroot/www/dummydir/.svn/entries 2006-07-20 01:14:57.000000000 +0300
53138 uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
53139 - revision="1040"/>
53140 + repos="svn://svn.lighttpd.net/lighttpd"
53141 + revision="1211"/>
53143 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf 2005-08-31 23:36:34.000000000 +0300
53144 +++ lighttpd-1.4.12/tests/fastcgi-10.conf 2006-07-16 00:26:04.000000000 +0300
53146 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53147 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53148 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53149 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53151 ## bind to port (default: 80)
53154 ## bind to localhost (default: all interfaces)
53155 server.bind = "localhost"
53156 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53157 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53158 server.name = "www.example.org"
53159 server.tag = "Apache 1.3.29"
53162 ######################## MODULE CONFIG ############################
53165 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53166 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53168 mimetype.assign = ( ".png" => "image/png",
53169 ".jpg" => "image/jpeg",
53171 ".c" => "text/plain",
53172 ".conf" => "text/plain" )
53174 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53175 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53176 compress.filetype = ("text/plain", "text/html")
53180 ssl.pemfile = "server.pem"
53182 auth.backend = "plain"
53183 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53184 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53185 auth.backend.plain.groupfile = "lighttpd.group"
53187 auth.backend.ldap.hostname = "localhost"
53188 @@ -128,11 +128,11 @@
53189 status.config-url = "/server-config"
53191 $HTTP["host"] == "vvv.example.org" {
53192 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53193 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53196 $HTTP["host"] == "zzz.example.org" {
53197 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53198 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53199 server.name = "zzz.example.org"
53202 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf 2006-01-03 12:38:17.000000000 +0200
53203 +++ lighttpd-1.4.12/tests/fastcgi-13.conf 2006-07-18 13:03:40.000000000 +0300
53205 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53206 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53207 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53208 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53210 debug.log-request-header = "enable"
53211 debug.log-response-header = "enable"
53214 ## bind to localhost (default: all interfaces)
53215 server.bind = "localhost"
53216 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53217 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53218 server.name = "www.example.org"
53219 server.tag = "Apache 1.3.29"
53222 ######################## MODULE CONFIG ############################
53225 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53226 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53228 mimetype.assign = ( ".png" => "image/png",
53229 ".jpg" => "image/jpeg",
53231 ".c" => "text/plain",
53232 ".conf" => "text/plain" )
53234 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53235 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53236 compress.filetype = ("text/plain", "text/html")
53241 "host" => "127.0.0.1",
53243 - "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
53244 + "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
53245 "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
53248 @@ -102,7 +102,7 @@
53249 ssl.pemfile = "server.pem"
53251 auth.backend = "plain"
53252 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53253 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53254 auth.backend.plain.groupfile = "lighttpd.group"
53256 auth.backend.ldap.hostname = "localhost"
53257 @@ -145,11 +145,11 @@
53258 status.config-url = "/server-config"
53260 $HTTP["host"] == "vvv.example.org" {
53261 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53262 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53265 $HTTP["host"] == "zzz.example.org" {
53266 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53267 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53268 server.name = "zzz.example.org"
53271 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf 2005-08-27 17:44:19.000000000 +0300
53272 +++ lighttpd-1.4.12/tests/fastcgi-auth.conf 2006-07-16 00:26:05.000000000 +0300
53274 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53275 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53276 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53277 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53279 debug.log-request-header = "enable"
53280 debug.log-response-header = "enable"
53283 ## bind to localhost (default: all interfaces)
53284 server.bind = "localhost"
53285 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53286 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53287 server.name = "www.example.org"
53288 server.tag = "Apache 1.3.29"
53291 ######################## MODULE CONFIG ############################
53294 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53295 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53297 mimetype.assign = ( ".png" => "image/png",
53298 ".jpg" => "image/jpeg",
53300 ".c" => "text/plain",
53301 ".conf" => "text/plain" )
53303 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53304 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53305 compress.filetype = ("text/plain", "text/html")
53310 "host" => "127.0.0.1",
53312 - "bin-path" => "@SRCDIR@/fcgi-auth",
53313 + "bin-path" => env.SRCDIR + "/fcgi-auth",
53314 "mode" => "authorizer",
53315 - "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
53316 + "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
53320 @@ -106,7 +106,7 @@
53321 ssl.pemfile = "server.pem"
53323 auth.backend = "plain"
53324 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53325 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53326 auth.backend.plain.groupfile = "lighttpd.group"
53328 auth.backend.ldap.hostname = "localhost"
53329 @@ -149,11 +149,11 @@
53330 status.config-url = "/server-config"
53332 $HTTP["host"] == "vvv.example.org" {
53333 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53334 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53337 $HTTP["host"] == "zzz.example.org" {
53338 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53339 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53340 server.name = "zzz.example.org"
53343 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf 2005-08-27 17:44:19.000000000 +0300
53344 +++ lighttpd-1.4.12/tests/fastcgi-responder.conf 2006-07-16 00:26:05.000000000 +0300
53346 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53347 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53348 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53349 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53351 #debug.log-request-header = "enable"
53352 #debug.log-response-header = "enable"
53355 ## bind to localhost (default: all interfaces)
53356 server.bind = "localhost"
53357 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53358 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53359 server.name = "www.example.org"
53360 server.tag = "Apache 1.3.29"
53363 ######################## MODULE CONFIG ############################
53366 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53367 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53369 mimetype.assign = ( ".png" => "image/png",
53370 ".jpg" => "image/jpeg",
53372 ".c" => "text/plain",
53373 ".conf" => "text/plain" )
53375 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53376 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53377 compress.filetype = ("text/plain", "text/html")
53380 @@ -90,10 +90,11 @@
53382 "host" => "127.0.0.1",
53384 - "bin-path" => "@SRCDIR@/fcgi-responder",
53385 + "bin-path" => env.SRCDIR + "/fcgi-responder",
53386 "check-local" => "disable",
53389 + "min-procs" => 1,
53390 + "allow-x-send-file" => "enable",
53394 @@ -109,7 +110,7 @@
53395 ssl.pemfile = "server.pem"
53397 auth.backend = "plain"
53398 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53399 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53400 auth.backend.plain.groupfile = "lighttpd.group"
53402 auth.backend.ldap.hostname = "localhost"
53403 @@ -152,11 +153,11 @@
53404 status.config-url = "/server-config"
53406 $HTTP["host"] == "vvv.example.org" {
53407 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53408 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53411 $HTTP["host"] == "zzz.example.org" {
53412 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53413 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53414 server.name = "zzz.example.org"
53417 --- ../lighttpd-1.4.11/tests/fcgi-responder.c 2005-08-11 01:26:55.000000000 +0300
53418 +++ lighttpd-1.4.12/tests/fcgi-responder.c 2006-07-16 00:26:05.000000000 +0300
53421 int num_requests = 2;
53423 - while (num_requests > 0 &&
53424 - FCGI_Accept() >= 0) {
53427 - if (NULL != (p = getenv("QUERY_STRING"))) {
53428 + while (num_requests > 0 && FCGI_Accept() >= 0) {
53430 + char* doc_root = NULL;
53431 + char fname[4096];
53432 + char* pfname = (char *)fname;
53434 + doc_root = getenv("DOCUMENT_ROOT");
53435 + p = getenv("QUERY_STRING");
53437 + if (NULL != p && NULL != doc_root) {
53438 + snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
53439 if (0 == strcmp(p, "lf")) {
53440 printf("Status: 200 OK\n\n");
53441 } else if (0 == strcmp(p, "crlf")) {
53443 printf("Status: 200 OK\r\n");
53446 + } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
53447 + printf("Status: 200 OK\r\n");
53448 + printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
53450 + } else if (0 == strcmp(p,"xsendfile")) {
53451 + printf("Status: 200 OK\r\n");
53452 + printf("X-Sendfile: %s\r\n", pfname);
53454 + } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
53455 + printf("Status: 200 OK\r\n");
53456 + printf("X-SeNdFiLe: %s\r\n", pfname);
53458 } else if (0 == strcmp(p, "die-at-end")) {
53459 printf("Status: 200 OK\r\n\r\n");
53461 --- ../lighttpd-1.4.11/tests/lighttpd.conf 2006-03-09 15:26:58.000000000 +0200
53462 +++ lighttpd-1.4.12/tests/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
53464 -debug.log-request-handling = "enable"
53465 -debug.log-condition-handling = "enable"
53466 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53467 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53468 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53469 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53470 +server.tag = "Apache 1.3.29"
53472 ## 64 Mbyte ... nice limit
53473 server.max-request-size = 65000
53475 -## bind to port (default: 80)
53476 -server.port = 2048
53477 +include "default.conf"
53479 -## bind to localhost (default: all interfaces)
53480 -server.bind = "localhost"
53481 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53482 -server.name = "www.example.org"
53483 -server.tag = "Apache 1.3.29"
53485 -server.dir-listing = "enable"
53487 -#server.event-handler = "linux-sysepoll"
53488 -#server.event-handler = "linux-rtsig"
53490 -#server.modules.path = ""
53491 -server.modules = (
53494 - "mod_secdownload",
53500 - "mod_simple_vhost",
53503 -# "mod_localizer",
53509 - "mod_accesslog" )
53511 -server.indexfiles = ( "index.php", "index.html",
53512 - "index.htm", "default.htm" )
53515 -######################## MODULE CONFIG ############################
53517 -ssi.extension = ( ".shtml" )
53519 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53521 -mimetype.assign = ( ".png" => "image/png",
53522 - ".jpg" => "image/jpeg",
53523 - ".jpeg" => "image/jpeg",
53524 - ".gif" => "image/gif",
53525 - ".html" => "text/html",
53526 - ".htm" => "text/html",
53527 - ".pdf" => "application/pdf",
53528 - ".swf" => "application/x-shockwave-flash",
53529 - ".spl" => "application/futuresplash",
53530 - ".txt" => "text/plain",
53531 - ".tar.gz" => "application/x-tgz",
53532 - ".tgz" => "application/x-tgz",
53533 - ".gz" => "application/x-gzip",
53534 - ".c" => "text/plain",
53535 - ".conf" => "text/plain" )
53536 +setenv.add-request-header = ( "FOO" => "foo")
53537 +setenv.add-response-header = ( "BAR" => "foo")
53539 $HTTP["host"] == "cache.example.org" {
53540 - compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
53541 + compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
53543 -compress.filetype = ("text/plain", "text/html")
53545 -setenv.add-environment = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
53546 -setenv.add-request-header = ( "FOO" => "foo")
53547 -setenv.add-response-header = ( "BAR" => "foo")
53549 $HTTP["url"] =~ "\.pdf$" {
53550 server.range-requests = "disable"
53551 @@ -85,76 +23,31 @@
53552 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53556 -cgi.assign = ( ".pl" => "/usr/bin/perl",
53557 - ".cgi" => "/usr/bin/perl",
53558 - ".py" => "/usr/bin/python" )
53560 -userdir.include-user = ( "jan" )
53561 -userdir.path = "/"
53563 -ssl.engine = "disable"
53564 -ssl.pemfile = "server.pem"
53566 $HTTP["host"] == "auth-htpasswd.example.org" {
53567 auth.backend = "htpasswd"
53570 -auth.backend = "plain"
53571 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
53573 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
53576 -auth.require = ( "/server-status" =>
53578 - "method" => "digest",
53579 - "realm" => "download archiv",
53580 - "require" => "group=www|user=jan|host=192.168.2.10"
53582 - "/server-config" =>
53584 - "method" => "basic",
53585 - "realm" => "download archiv",
53586 - "require" => "valid-user"
53590 -url.access-deny = ( "~", ".inc")
53592 -url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
53593 - "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
53595 -expire.url = ( "/expire/access" => "access 2 hours",
53596 - "/expire/modification" => "access plus 1 seconds 2 minutes")
53598 -#cache.cache-dir = "/home/weigon/wwwroot/cache/"
53600 -#### status module
53601 -status.status-url = "/server-status"
53602 -status.config-url = "/server-config"
53604 $HTTP["host"] == "vvv.example.org" {
53605 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53606 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53607 secdownload.secret = "verysecret"
53608 - secdownload.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53609 + secdownload.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53610 secdownload.uri-prefix = "/sec/"
53611 secdownload.timeout = 120
53614 $HTTP["host"] == "zzz.example.org" {
53615 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53616 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53617 server.name = "zzz.example.org"
53620 $HTTP["host"] == "no-simple.example.org" {
53621 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
53622 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
53623 server.name = "zzz.example.org"
53626 $HTTP["host"] !~ "(no-simple\.example\.org)" {
53627 simple-vhost.document-root = "pages"
53628 - simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
53629 + simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
53630 simple-vhost.default-host = "www.example.org"
53633 --- ../lighttpd-1.4.11/tests/lowercase.conf 1970-01-01 03:00:00.000000000 +0300
53634 +++ lighttpd-1.4.12/tests/lowercase.conf 2006-07-16 00:26:05.000000000 +0300
53636 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53637 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53639 +## bind to port (default: 80)
53640 +server.port = 2048
53642 +## bind to localhost (default: all interfaces)
53643 +server.bind = "localhost"
53644 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53646 +server.force-lowercase-filenames = "enable"
53648 +server.dir-listing = "enable"
53650 +server.modules = (
53653 + "mod_secdownload",
53662 +server.indexfiles = ( "index.php", "index.html",
53663 + "index.htm", "default.htm" )
53666 +######################## MODULE CONFIG ############################
53668 +mimetype.assign = ( ".png" => "image/png",
53669 + ".jpg" => "image/jpeg",
53670 + ".jpeg" => "image/jpeg",
53671 + ".gif" => "image/gif",
53672 + ".html" => "text/html",
53673 + ".htm" => "text/html",
53674 + ".pdf" => "application/pdf",
53675 + ".swf" => "application/x-shockwave-flash",
53676 + ".spl" => "application/futuresplash",
53677 + ".txt" => "text/plain",
53678 + ".tar.gz" => "application/x-tgz",
53679 + ".tgz" => "application/x-tgz",
53680 + ".gz" => "application/x-gzip",
53681 + ".c" => "text/plain",
53682 + ".conf" => "text/plain" )
53685 +fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
53686 + "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53690 +cgi.assign = ( ".pl" => "/usr/bin/perl",
53691 + ".cgi" => "/usr/bin/perl",
53692 + ".py" => "/usr/bin/python" )
53694 +auth.backend = "plain"
53695 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53697 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53699 +$HTTP["host"] == "lowercase-auth" {
53700 + auth.require = ( "/image.jpg" =>
53702 + "method" => "digest",
53703 + "realm" => "download archiv",
53704 + "require" => "valid-user"
53709 +$HTTP["host"] == "lowercase-deny" {
53710 + url.access-deny = ( ".jpg")
53713 +$HTTP["host"] == "lowercase-exclude" {
53714 + static-file.exclude-extensions = ( ".jpg" )
53716 --- ../lighttpd-1.4.11/tests/lowercase.t 1970-01-01 03:00:00.000000000 +0300
53717 +++ lighttpd-1.4.12/tests/lowercase.t 2006-07-16 00:26:05.000000000 +0300
53719 +#!/usr/bin/env perl
53721 + # add current source dir to the include-path
53722 + # we need this for make distcheck
53723 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
53724 + unshift @INC, $srcdir;
53729 +use Test::More tests => 10;
53732 +my $tf = LightyTest->new();
53735 +$tf->{CONFIGFILE} = 'lowercase.conf';
53737 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
53739 +## check if lower-casing works
53741 +$t->{REQUEST} = ( <<EOF
53742 +GET /image.JPG HTTP/1.0
53745 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53746 +ok($tf->handle_http($t) == 0, 'uppercase access');
53748 +$t->{REQUEST} = ( <<EOF
53749 +GET /image.jpg HTTP/1.0
53752 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53753 +ok($tf->handle_http($t) == 0, 'lowercase access');
53755 +## check that mod-auth works
53757 +$t->{REQUEST} = ( <<EOF
53758 +GET /image.JPG HTTP/1.0
53759 +Host: lowercase-auth
53762 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53763 +ok($tf->handle_http($t) == 0, 'uppercase access');
53765 +$t->{REQUEST} = ( <<EOF
53766 +GET /image.jpg HTTP/1.0
53767 +Host: lowercase-auth
53770 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53771 +ok($tf->handle_http($t) == 0, 'lowercase access');
53774 +## check that mod-staticfile exclude works
53775 +$t->{REQUEST} = ( <<EOF
53776 +GET /image.JPG HTTP/1.0
53777 +Host: lowercase-exclude
53780 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53781 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
53783 +$t->{REQUEST} = ( <<EOF
53784 +GET /image.jpg HTTP/1.0
53785 +Host: lowercase-exclude
53788 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53789 +ok($tf->handle_http($t) == 0, 'lowercase access');
53792 +## check that mod-access exclude works
53793 +$t->{REQUEST} = ( <<EOF
53794 +GET /image.JPG HTTP/1.0
53795 +Host: lowercase-deny
53798 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53799 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
53801 +$t->{REQUEST} = ( <<EOF
53802 +GET /image.jpg HTTP/1.0
53803 +Host: lowercase-deny
53806 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53807 +ok($tf->handle_http($t) == 0, 'lowercase access');
53811 +ok($tf->stop_proc == 0, "Stopping lighttpd");
53813 --- ../lighttpd-1.4.11/tests/mod-cgi.t 2005-09-01 14:43:05.000000000 +0300
53814 +++ lighttpd-1.4.12/tests/mod-cgi.t 2006-07-18 13:03:40.000000000 +0300
53816 GET /nph-status.pl HTTP/1.0
53819 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53820 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
53821 ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
53823 $t->{REQUEST} = ( <<EOF
53824 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t 2006-03-09 15:30:45.000000000 +0200
53825 +++ lighttpd-1.4.12/tests/mod-fastcgi.t 2006-07-18 13:03:40.000000000 +0300
53830 -use Test::More tests => 47;
53831 +use Test::More tests => 49;
53834 my $tf = LightyTest->new();
53839 - skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
53840 + skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
53842 ok($tf->start_proc == 0, "Starting lighttpd") or die();
53844 @@ -223,7 +223,7 @@
53848 - skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php";
53849 + skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
53850 $tf->{CONFIGFILE} = 'fastcgi-13.conf';
53851 ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
53852 $t->{REQUEST} = ( <<EOF
53853 @@ -285,6 +285,34 @@
53854 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
53855 ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
53857 + # X-LIGHTTPD-send-file
53858 + $t->{REQUEST} = ( <<EOF
53859 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
53860 +Host: www.example.org
53863 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53865 + ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
53867 + $t->{REQUEST} = ( <<EOF
53868 +GET /index.fcgi?xsendfile HTTP/1.0
53869 +Host: www.example.org
53872 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53874 + ok($tf->handle_http($t) == 0, 'X-Sendfile');
53876 + $t->{REQUEST} = ( <<EOF
53877 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
53878 +Host: www.example.org
53881 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53883 + ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
53885 $t->{REQUEST} = ( <<EOF
53886 GET /index.fcgi?die-at-end HTTP/1.0
53887 Host: www.example.org
53888 --- ../lighttpd-1.4.11/tests/mod-proxy.t 1970-01-01 03:00:00.000000000 +0300
53889 +++ lighttpd-1.4.12/tests/mod-proxy.t 2006-07-18 13:03:40.000000000 +0300
53891 +#!/usr/bin/env perl
53893 + # add current source dir to the include-path
53894 + # we need this for make distcheck
53895 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
53896 + unshift @INC, $srcdir;
53901 +use Test::More tests => 21;
53904 +my $tf_proxy = LightyTest->new();
53905 +my $tf_backend1 = LightyTest->new();
53906 +my $tf_backend2 = LightyTest->new();
53910 +## we need two procs
53911 +## 1. the real webserver
53912 +## 2. the proxy server
53915 + skip "disabled for now", 21;
53916 +$tf_proxy->{PORT} = 2048;
53917 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
53918 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
53920 +$tf_backend1->{PORT} = 2050;
53921 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
53922 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
53924 +$tf_backend2->{PORT} = 2051;
53925 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
53926 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
53929 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
53931 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
53935 +$t->{REQUEST} = ( <<EOF
53936 +GET /index.html HTTP/1.0
53937 +Host: www.example.org
53940 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53941 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
53943 +$t->{REQUEST} = ( <<EOF
53944 +GET /index.html HTTP/1.0
53945 +Host: www.example.org
53948 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
53949 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
53951 +$t->{REQUEST} = ( <<EOF
53952 +GET /balance-rr/foo HTTP/1.0
53953 +Host: www.example.org
53956 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53957 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
53959 +$t->{REQUEST} = ( <<EOF
53960 +GET /balance-rr/foo HTTP/1.0
53961 +Host: www.example.org
53964 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53965 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
53967 +$t->{REQUEST} = ( <<EOF
53968 +GET /balance-fair/foo HTTP/1.0
53969 +Host: www.example.org
53972 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53973 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
53975 +## backend 2 starting
53976 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
53978 +$t->{REQUEST} = ( <<EOF
53979 +GET /balance-rr/foo HTTP/1.0
53980 +Host: www.example.org
53983 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53984 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
53986 +$t->{REQUEST} = ( <<EOF
53987 +GET /balance-rr/foo HTTP/1.0
53988 +Host: www.example.org
53991 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53992 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
53994 +$t->{REQUEST} = ( <<EOF
53995 +GET /balance-hash/foo HTTP/1.0
53996 +Host: www.example.org
53999 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
54000 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
54002 +$t->{REQUEST} = ( <<EOF
54003 +GET /balance-hash/foo HTTP/1.0
54004 +Host: www.example.org
54007 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
54008 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
54010 +$t->{REQUEST} = ( <<EOF
54011 +GET /balance-hash/bar HTTP/1.0
54012 +Host: www.example.org
54015 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54016 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
54018 +$t->{REQUEST} = ( <<EOF
54019 +GET /balance-hash/bar HTTP/1.0
54020 +Host: www.example.org
54023 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54024 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
54026 +## backend 1 stopping, failover
54027 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
54029 +$t->{REQUEST} = ( <<EOF
54030 +GET /balance-hash/foo HTTP/1.0
54031 +Host: www.example.org
54034 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54035 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
54037 +$t->{REQUEST} = ( <<EOF
54038 +GET /balance-hash/bar HTTP/1.0
54039 +Host: www.example.org
54042 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54043 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
54045 +$t->{REQUEST} = ( <<EOF
54046 +GET /balance-rr/foo HTTP/1.0
54047 +Host: www.example.org
54050 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54051 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
54053 +$t->{REQUEST} = ( <<EOF
54054 +GET /balance-fair/foo HTTP/1.0
54055 +Host: www.example.org
54058 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
54059 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
54062 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
54064 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
54066 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf 1970-01-01 03:00:00.000000000 +0300
54067 +++ lighttpd-1.4.12/tests/proxy-backend-1.conf 2006-07-16 00:26:05.000000000 +0300
54069 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54070 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
54072 +include "default.conf"
54075 +server.tag = "proxy-backend-1"
54076 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf 1970-01-01 03:00:00.000000000 +0300
54077 +++ lighttpd-1.4.12/tests/proxy-backend-2.conf 2006-07-16 00:26:04.000000000 +0300
54079 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54080 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
54082 +include "default.conf"
54085 +server.tag = "proxy-backend-2"
54086 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
54087 +++ lighttpd-1.4.12/tests/proxy.conf 2006-07-16 00:26:05.000000000 +0300
54089 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54090 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
54091 +server.tag = "proxy"
54093 +include "default.conf"
54095 +## 127.0.0.1 and 127.0.0.2 are the same host
54097 + "" => (( "host" => "127.0.0.1",
54098 + "port" => 2050 ),
54099 + ( "host" => "127.0.0.2",
54103 +$HTTP["url"] =~ "^/balance-rr/" {
54104 + proxy.balance = "round-robin"
54107 +$HTTP["url"] =~ "^/balance-hash/" {
54108 + proxy.balance = "hash"
54111 +$HTTP["url"] =~ "^/balance-fair/" {
54112 + proxy.balance = "fair"
54115 --- ../lighttpd-1.4.11/tests/var-include.conf 2005-08-27 17:44:19.000000000 +0300
54116 +++ lighttpd-1.4.12/tests/var-include.conf 2006-07-16 00:26:05.000000000 +0300
54118 debug.log-request-handling = "enable"
54119 debug.log-condition-handling = "enable"
54121 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54122 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
54123 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54124 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
54126 ## bind to port (default: 80)
54129 ## bind to localhost (default: all interfaces)
54130 server.bind = "localhost"
54131 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
54132 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
54133 server.name = "www.example.org"
54134 server.tag = "Apache 1.3.29"
54136 @@ -21,19 +21,19 @@
54137 ######################## MODULE CONFIG ############################
54140 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
54141 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
54143 mimetype.assign = ( ".html" => "text/html" )
54145 url.redirect = ("^" => "/default")
54147 $HTTP["host"] == "www.example.org" {
54148 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54149 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54150 server.name = "www.example.org"
54151 url.redirect = ("^" => "/redirect")
54153 $HTTP["host"] == "test.example.org" {
54154 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
54155 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
54156 server.name = "test.example.org"