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-16 00:26:05.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 + strdup strerror strstr strtol sendfile getopt socket lstat \
110 gethostbyname poll sigtimedwait epoll_ctl getrlimit chroot \
111 getuid select signal pathconf madvise posix_fadvise posix_madvise \
112 writev sigaction sendfile64 send_file kqueue port_create localtime_r])
117 -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"
118 +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"
120 plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl"
121 features="regex-conditionals"
123 disable_feature="$disable_feature $features"
126 +features="webdav-locks"
127 +if test "x$UUID_LIB" \!= x; then
128 + enable_feature="$enable_feature $features"
130 + disable_feature="$disable_feature $features"
137 --- ../lighttpd-1.4.11/cygwin/lighttpd.README 2006-03-07 14:22:19.000000000 +0200
138 +++ lighttpd-1.4.12/cygwin/lighttpd.README 2006-07-17 22:02:18.000000000 +0300
141 -------------------------------------------
\r
142 -A fast, secure and flexible webserver
\r
144 -Runtime requirements:
\r
145 - cygwin-1.5.10 or newer
\r
146 - crypt-1.1 or newer
\r
147 - libbz2_1-1.0.2 or newer
\r
148 - libpcre0-4.5 or newer
\r
149 - openssl-0.9.7d or newer
\r
150 - zlib-1.2.1 or newer
\r
152 -Build requirements:
\r
153 - cygwin-1.5.10 or newer
\r
154 - gcc-3.3.1-3 or newer
\r
155 - binutils-20030901-1 or newer
\r
164 -Canonical homepage:
\r
165 - http://jan.kneschke.de/projects/lighttpd/
\r
167 -Canonical download:
\r
168 - http://jan.kneschke.de/projects/lighttpd/download
\r
170 -------------------------------------
\r
172 -Build instructions:
\r
173 - unpack lighttpd-1.4.11-<REL>-src.tar.bz2
\r
174 - if you use setup to install this src package, it will be
\r
175 - unpacked under /usr/src automatically
\r
177 - ./lighttpd-1.4.11-<REL>.sh all
\r
180 - /usr/src/lighttpd-1.4.11-<REL>.tar.bz2
\r
181 - /usr/src/lighttpd-1.4.11-<REL>-src.tar.bz2
\r
183 -Or use './lighttpd-1.4.11-<REL>.sh prep' to get a patched source directory
\r
185 --------------------------------------------
\r
187 -Files included in the binary distribution:
\r
189 - /etc/lighttpd/lighttpd.conf.default
\r
190 - /usr/lib/cyglightcomp.dll
\r
191 - /usr/lib/lighttpd/mod_access.dll
\r
192 - /usr/lib/lighttpd/mod_accesslog.dll
\r
193 - /usr/lib/lighttpd/mod_auth.dll
\r
194 - /usr/lib/lighttpd/mod_cgi.dll
\r
195 - /usr/lib/lighttpd/mod_compress.dll
\r
196 - /usr/lib/lighttpd/mod_evhost.dll
\r
197 - /usr/lib/lighttpd/mod_expire.dll
\r
198 - /usr/lib/lighttpd/mod_fastcgi.dll
\r
199 - /usr/lib/lighttpd/mod_httptls.dll
\r
200 - /usr/lib/lighttpd/mod_maps.dll
\r
201 - /usr/lib/lighttpd/mod_proxy.dll
\r
202 - /usr/lib/lighttpd/mod_redirect.dll
\r
203 - /usr/lib/lighttpd/mod_rewrite.dll
\r
204 - /usr/lib/lighttpd/mod_rrdtool.dll
\r
205 - /usr/lib/lighttpd/mod_secdownload.dll
\r
206 - /usr/lib/lighttpd/mod_simple_vhost.dll
\r
207 - /usr/lib/lighttpd/mod_ssi.dll
\r
208 - /usr/lib/lighttpd/mod_status.dll
\r
209 - /usr/lib/lighttpd/mod_usertrack.dll
\r
210 - /usr/sbin/lighttpd.exe
\r
211 - /usr/share/doc/Cygwin/lighttpd-1.3.0.README
\r
212 - /usr/share/doc/lighttpd-1.3.0/accesslog.txt
\r
213 - /usr/share/doc/lighttpd-1.3.0/authentification.txt
\r
214 - /usr/share/doc/lighttpd-1.3.0/AUTHORS
\r
215 - /usr/share/doc/lighttpd-1.3.0/cgi.txt
\r
216 - /usr/share/doc/lighttpd-1.3.0/ChangeLog
\r
217 - /usr/share/doc/lighttpd-1.3.0/compress.txt
\r
218 - /usr/share/doc/lighttpd-1.3.0/configuration.txt
\r
219 - /usr/share/doc/lighttpd-1.3.0/COPYING
\r
220 - /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
\r
221 - /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
\r
222 - /usr/share/doc/lighttpd-1.3.0/features.txt
\r
223 - /usr/share/doc/lighttpd-1.3.0/INSTALL
\r
224 - /usr/share/doc/lighttpd-1.3.0/NEWS
\r
225 - /usr/share/doc/lighttpd-1.3.0/performance.txt
\r
226 - /usr/share/doc/lighttpd-1.3.0/plugins.txt
\r
227 - /usr/share/doc/lighttpd-1.3.0/proxy.txt
\r
228 - /usr/share/doc/lighttpd-1.3.0/README
\r
229 - /usr/share/doc/lighttpd-1.3.0/redirect.txt
\r
230 - /usr/share/doc/lighttpd-1.3.0/rewrite.txt
\r
231 - /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
\r
232 - /usr/share/doc/lighttpd-1.3.0/secdownload.txt
\r
233 - /usr/share/doc/lighttpd-1.3.0/security.txt
\r
234 - /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
\r
235 - /usr/share/doc/lighttpd-1.3.0/skeleton.txt
\r
236 - /usr/share/doc/lighttpd-1.3.0/ssi.txt
\r
237 - /usr/share/doc/lighttpd-1.3.0/state.txt
\r
238 - /usr/share/man/man1/lighttpd.1.gz
\r
240 -------------------
\r
244 ----------- lighttpd-1.3.1-1 -----------
\r
248 ----------- lighttpd-1.3.0-1 -----------
\r
251 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
\r
252 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
\r
255 +------------------------------------------
256 +A fast, secure and flexible webserver
258 +Runtime requirements:
259 + cygwin-1.5.10 or newer
261 + libbz2_1-1.0.2 or newer
262 + libpcre0-4.5 or newer
263 + openssl-0.9.7d or newer
264 + zlib-1.2.1 or newer
267 + cygwin-1.5.10 or newer
268 + gcc-3.3.1-3 or newer
269 + binutils-20030901-1 or newer
279 + http://jan.kneschke.de/projects/lighttpd/
282 + http://jan.kneschke.de/projects/lighttpd/download
284 +------------------------------------
287 + unpack lighttpd-1.4.12-<REL>-src.tar.bz2
288 + if you use setup to install this src package, it will be
289 + unpacked under /usr/src automatically
291 + ./lighttpd-1.4.12-<REL>.sh all
294 + /usr/src/lighttpd-1.4.12-<REL>.tar.bz2
295 + /usr/src/lighttpd-1.4.12-<REL>-src.tar.bz2
297 +Or use './lighttpd-1.4.12-<REL>.sh prep' to get a patched source directory
299 +-------------------------------------------
301 +Files included in the binary distribution:
303 + /etc/lighttpd/lighttpd.conf.default
304 + /usr/lib/cyglightcomp.dll
305 + /usr/lib/lighttpd/mod_access.dll
306 + /usr/lib/lighttpd/mod_accesslog.dll
307 + /usr/lib/lighttpd/mod_auth.dll
308 + /usr/lib/lighttpd/mod_cgi.dll
309 + /usr/lib/lighttpd/mod_compress.dll
310 + /usr/lib/lighttpd/mod_evhost.dll
311 + /usr/lib/lighttpd/mod_expire.dll
312 + /usr/lib/lighttpd/mod_fastcgi.dll
313 + /usr/lib/lighttpd/mod_httptls.dll
314 + /usr/lib/lighttpd/mod_maps.dll
315 + /usr/lib/lighttpd/mod_proxy.dll
316 + /usr/lib/lighttpd/mod_redirect.dll
317 + /usr/lib/lighttpd/mod_rewrite.dll
318 + /usr/lib/lighttpd/mod_rrdtool.dll
319 + /usr/lib/lighttpd/mod_secdownload.dll
320 + /usr/lib/lighttpd/mod_simple_vhost.dll
321 + /usr/lib/lighttpd/mod_ssi.dll
322 + /usr/lib/lighttpd/mod_status.dll
323 + /usr/lib/lighttpd/mod_usertrack.dll
324 + /usr/sbin/lighttpd.exe
325 + /usr/share/doc/Cygwin/lighttpd-1.3.0.README
326 + /usr/share/doc/lighttpd-1.3.0/accesslog.txt
327 + /usr/share/doc/lighttpd-1.3.0/authentification.txt
328 + /usr/share/doc/lighttpd-1.3.0/AUTHORS
329 + /usr/share/doc/lighttpd-1.3.0/cgi.txt
330 + /usr/share/doc/lighttpd-1.3.0/ChangeLog
331 + /usr/share/doc/lighttpd-1.3.0/compress.txt
332 + /usr/share/doc/lighttpd-1.3.0/configuration.txt
333 + /usr/share/doc/lighttpd-1.3.0/COPYING
334 + /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
335 + /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
336 + /usr/share/doc/lighttpd-1.3.0/features.txt
337 + /usr/share/doc/lighttpd-1.3.0/INSTALL
338 + /usr/share/doc/lighttpd-1.3.0/NEWS
339 + /usr/share/doc/lighttpd-1.3.0/performance.txt
340 + /usr/share/doc/lighttpd-1.3.0/plugins.txt
341 + /usr/share/doc/lighttpd-1.3.0/proxy.txt
342 + /usr/share/doc/lighttpd-1.3.0/README
343 + /usr/share/doc/lighttpd-1.3.0/redirect.txt
344 + /usr/share/doc/lighttpd-1.3.0/rewrite.txt
345 + /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
346 + /usr/share/doc/lighttpd-1.3.0/secdownload.txt
347 + /usr/share/doc/lighttpd-1.3.0/security.txt
348 + /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
349 + /usr/share/doc/lighttpd-1.3.0/skeleton.txt
350 + /usr/share/doc/lighttpd-1.3.0/ssi.txt
351 + /usr/share/doc/lighttpd-1.3.0/state.txt
352 + /usr/share/man/man1/lighttpd.1.gz
358 +---------- lighttpd-1.3.1-1 -----------
362 +---------- lighttpd-1.3.0-1 -----------
365 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
366 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
368 --- ../lighttpd-1.4.11/cygwin/lighttpd.README.in 2005-08-11 01:26:59.000000000 +0300
369 +++ lighttpd-1.4.12/cygwin/lighttpd.README.in 2006-07-16 00:26:04.000000000 +0300
372 -------------------------------------------
\r
373 -A fast, secure and flexible webserver
\r
375 -Runtime requirements:
\r
376 - cygwin-1.5.10 or newer
\r
377 - crypt-1.1 or newer
\r
378 - libbz2_1-1.0.2 or newer
\r
379 - libpcre0-4.5 or newer
\r
380 - openssl-0.9.7d or newer
\r
381 - zlib-1.2.1 or newer
\r
383 -Build requirements:
\r
384 - cygwin-1.5.10 or newer
\r
385 - gcc-3.3.1-3 or newer
\r
386 - binutils-20030901-1 or newer
\r
395 -Canonical homepage:
\r
396 - http://jan.kneschke.de/projects/lighttpd/
\r
398 -Canonical download:
\r
399 - http://jan.kneschke.de/projects/lighttpd/download
\r
401 -------------------------------------
\r
403 -Build instructions:
\r
404 - unpack lighttpd-@VERSION@-<REL>-src.tar.bz2
\r
405 - if you use setup to install this src package, it will be
\r
406 - unpacked under /usr/src automatically
\r
408 - ./lighttpd-@VERSION@-<REL>.sh all
\r
411 - /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
\r
412 - /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
\r
414 -Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
\r
416 --------------------------------------------
\r
418 -Files included in the binary distribution:
\r
420 - /etc/lighttpd/lighttpd.conf.default
\r
421 - /usr/lib/cyglightcomp.dll
\r
422 - /usr/lib/lighttpd/mod_access.dll
\r
423 - /usr/lib/lighttpd/mod_accesslog.dll
\r
424 - /usr/lib/lighttpd/mod_auth.dll
\r
425 - /usr/lib/lighttpd/mod_cgi.dll
\r
426 - /usr/lib/lighttpd/mod_compress.dll
\r
427 - /usr/lib/lighttpd/mod_evhost.dll
\r
428 - /usr/lib/lighttpd/mod_expire.dll
\r
429 - /usr/lib/lighttpd/mod_fastcgi.dll
\r
430 - /usr/lib/lighttpd/mod_httptls.dll
\r
431 - /usr/lib/lighttpd/mod_maps.dll
\r
432 - /usr/lib/lighttpd/mod_proxy.dll
\r
433 - /usr/lib/lighttpd/mod_redirect.dll
\r
434 - /usr/lib/lighttpd/mod_rewrite.dll
\r
435 - /usr/lib/lighttpd/mod_rrdtool.dll
\r
436 - /usr/lib/lighttpd/mod_secdownload.dll
\r
437 - /usr/lib/lighttpd/mod_simple_vhost.dll
\r
438 - /usr/lib/lighttpd/mod_ssi.dll
\r
439 - /usr/lib/lighttpd/mod_status.dll
\r
440 - /usr/lib/lighttpd/mod_usertrack.dll
\r
441 - /usr/sbin/lighttpd.exe
\r
442 - /usr/share/doc/Cygwin/lighttpd-1.3.0.README
\r
443 - /usr/share/doc/lighttpd-1.3.0/accesslog.txt
\r
444 - /usr/share/doc/lighttpd-1.3.0/authentification.txt
\r
445 - /usr/share/doc/lighttpd-1.3.0/AUTHORS
\r
446 - /usr/share/doc/lighttpd-1.3.0/cgi.txt
\r
447 - /usr/share/doc/lighttpd-1.3.0/ChangeLog
\r
448 - /usr/share/doc/lighttpd-1.3.0/compress.txt
\r
449 - /usr/share/doc/lighttpd-1.3.0/configuration.txt
\r
450 - /usr/share/doc/lighttpd-1.3.0/COPYING
\r
451 - /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
\r
452 - /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
\r
453 - /usr/share/doc/lighttpd-1.3.0/features.txt
\r
454 - /usr/share/doc/lighttpd-1.3.0/INSTALL
\r
455 - /usr/share/doc/lighttpd-1.3.0/NEWS
\r
456 - /usr/share/doc/lighttpd-1.3.0/performance.txt
\r
457 - /usr/share/doc/lighttpd-1.3.0/plugins.txt
\r
458 - /usr/share/doc/lighttpd-1.3.0/proxy.txt
\r
459 - /usr/share/doc/lighttpd-1.3.0/README
\r
460 - /usr/share/doc/lighttpd-1.3.0/redirect.txt
\r
461 - /usr/share/doc/lighttpd-1.3.0/rewrite.txt
\r
462 - /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
\r
463 - /usr/share/doc/lighttpd-1.3.0/secdownload.txt
\r
464 - /usr/share/doc/lighttpd-1.3.0/security.txt
\r
465 - /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
\r
466 - /usr/share/doc/lighttpd-1.3.0/skeleton.txt
\r
467 - /usr/share/doc/lighttpd-1.3.0/ssi.txt
\r
468 - /usr/share/doc/lighttpd-1.3.0/state.txt
\r
469 - /usr/share/man/man1/lighttpd.1.gz
\r
471 -------------------
\r
475 ----------- lighttpd-1.3.1-1 -----------
\r
479 ----------- lighttpd-1.3.0-1 -----------
\r
482 -Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
\r
483 -Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
\r
486 +------------------------------------------
487 +A fast, secure and flexible webserver
489 +Runtime requirements:
490 + cygwin-1.5.10 or newer
492 + libbz2_1-1.0.2 or newer
493 + libpcre0-4.5 or newer
494 + openssl-0.9.7d or newer
495 + zlib-1.2.1 or newer
498 + cygwin-1.5.10 or newer
499 + gcc-3.3.1-3 or newer
500 + binutils-20030901-1 or newer
510 + http://jan.kneschke.de/projects/lighttpd/
513 + http://jan.kneschke.de/projects/lighttpd/download
515 +------------------------------------
518 + unpack lighttpd-@VERSION@-<REL>-src.tar.bz2
519 + if you use setup to install this src package, it will be
520 + unpacked under /usr/src automatically
522 + ./lighttpd-@VERSION@-<REL>.sh all
525 + /usr/src/lighttpd-@VERSION@-<REL>.tar.bz2
526 + /usr/src/lighttpd-@VERSION@-<REL>-src.tar.bz2
528 +Or use './lighttpd-@VERSION@-<REL>.sh prep' to get a patched source directory
530 +-------------------------------------------
532 +Files included in the binary distribution:
534 + /etc/lighttpd/lighttpd.conf.default
535 + /usr/lib/cyglightcomp.dll
536 + /usr/lib/lighttpd/mod_access.dll
537 + /usr/lib/lighttpd/mod_accesslog.dll
538 + /usr/lib/lighttpd/mod_auth.dll
539 + /usr/lib/lighttpd/mod_cgi.dll
540 + /usr/lib/lighttpd/mod_compress.dll
541 + /usr/lib/lighttpd/mod_evhost.dll
542 + /usr/lib/lighttpd/mod_expire.dll
543 + /usr/lib/lighttpd/mod_fastcgi.dll
544 + /usr/lib/lighttpd/mod_httptls.dll
545 + /usr/lib/lighttpd/mod_maps.dll
546 + /usr/lib/lighttpd/mod_proxy.dll
547 + /usr/lib/lighttpd/mod_redirect.dll
548 + /usr/lib/lighttpd/mod_rewrite.dll
549 + /usr/lib/lighttpd/mod_rrdtool.dll
550 + /usr/lib/lighttpd/mod_secdownload.dll
551 + /usr/lib/lighttpd/mod_simple_vhost.dll
552 + /usr/lib/lighttpd/mod_ssi.dll
553 + /usr/lib/lighttpd/mod_status.dll
554 + /usr/lib/lighttpd/mod_usertrack.dll
555 + /usr/sbin/lighttpd.exe
556 + /usr/share/doc/Cygwin/lighttpd-1.3.0.README
557 + /usr/share/doc/lighttpd-1.3.0/accesslog.txt
558 + /usr/share/doc/lighttpd-1.3.0/authentification.txt
559 + /usr/share/doc/lighttpd-1.3.0/AUTHORS
560 + /usr/share/doc/lighttpd-1.3.0/cgi.txt
561 + /usr/share/doc/lighttpd-1.3.0/ChangeLog
562 + /usr/share/doc/lighttpd-1.3.0/compress.txt
563 + /usr/share/doc/lighttpd-1.3.0/configuration.txt
564 + /usr/share/doc/lighttpd-1.3.0/COPYING
565 + /usr/share/doc/lighttpd-1.3.0/fastcgi-state.txt
566 + /usr/share/doc/lighttpd-1.3.0/fastcgi.txt
567 + /usr/share/doc/lighttpd-1.3.0/features.txt
568 + /usr/share/doc/lighttpd-1.3.0/INSTALL
569 + /usr/share/doc/lighttpd-1.3.0/NEWS
570 + /usr/share/doc/lighttpd-1.3.0/performance.txt
571 + /usr/share/doc/lighttpd-1.3.0/plugins.txt
572 + /usr/share/doc/lighttpd-1.3.0/proxy.txt
573 + /usr/share/doc/lighttpd-1.3.0/README
574 + /usr/share/doc/lighttpd-1.3.0/redirect.txt
575 + /usr/share/doc/lighttpd-1.3.0/rewrite.txt
576 + /usr/share/doc/lighttpd-1.3.0/rrdtool.txt
577 + /usr/share/doc/lighttpd-1.3.0/secdownload.txt
578 + /usr/share/doc/lighttpd-1.3.0/security.txt
579 + /usr/share/doc/lighttpd-1.3.0/simple-vhost.txt
580 + /usr/share/doc/lighttpd-1.3.0/skeleton.txt
581 + /usr/share/doc/lighttpd-1.3.0/ssi.txt
582 + /usr/share/doc/lighttpd-1.3.0/state.txt
583 + /usr/share/man/man1/lighttpd.1.gz
589 +---------- lighttpd-1.3.1-1 -----------
593 +---------- lighttpd-1.3.0-1 -----------
596 +Cygwin port maintained by: Jan Kneschke <jan@kneschke.de>
597 +Please address all questions to the Cygwin mailing list at <cygwin@cygwin.com>
599 --- ../lighttpd-1.4.11/doc/authentication.txt 2006-01-12 20:34:26.000000000 +0200
600 +++ lighttpd-1.4.12/doc/authentication.txt 2006-07-16 00:26:05.000000000 +0300
604 :Author: Jan Kneschke
606 -:Revision: $Revision$
608 +:Revision: $Revision$
611 The auth module provides ...
612 --- ../lighttpd-1.4.11/doc/compress.txt 2005-08-11 01:26:16.000000000 +0300
613 +++ lighttpd-1.4.12/doc/compress.txt 2006-07-16 00:26:05.000000000 +0300
617 Output compression reduces the network load and can improve the overall
618 -throughput of the webserver.
619 +throughput of the webserver. All major http-clients support compression by
620 +announcing it in the Accept-Encoding header. This is used to negotiate the
621 +most suitable compression method. We support deflate, gzip and bzip2.
623 -Only static content is supported up to now.
624 +deflate (RFC1950, RFC1951) and gzip (RFC1952) depend on zlib while bzip2
625 +depends on libbzip2. bzip2 is only supported by lynx and some other console
628 -The server negotiates automaticly which compression method is used.
629 -Supported are gzip, deflate, bzip.
630 +Currently we limit to compression support to static files.
635 +mod_compress can stored compressed files on disk to optimized the compression
636 +on a second request away. As soon as compress.cache-dir is set the files are
639 +The names of the cache files are made of the filename, the compression method
640 +and the etag associated to the file.
642 +Cleaning the cache is left to the user. A cron job deleting files older than
643 +10 days should do fine.
648 +The module limits the compression of files to files larger than 128 Byte and
649 +smaller than 128 MByte.
651 +The lower limit is set as small files tend to become larger by compressing due
652 +to the compression headers, the upper limit is set to work sensable with
653 +memory and cpu-time.
658 Default: not set, compress the file for every request
661 - mimetypes where might get compressed
662 + mimetypes which might get compressed
666 compress.filetype = ("text/plain", "text/html")
668 + Keep in mind that compressed JavaScript and CSS files are broken in some
673 +compress.max-file-size
674 + maximum size of the original file to be compressed kBytes.
676 + This is meant to protect the server against DoSing as compressing large
677 + (let's say 1Gbyte) takes a lot of time and would delay the whole operation
680 + There is a hard upper limit of 128Mbyte.
682 + Default: unlimited (== hard-limit of 128MByte)
684 Compressing Dynamic Content
685 ===========================
687 --- ../lighttpd-1.4.11/doc/configuration.txt 2006-03-09 02:10:40.000000000 +0200
688 +++ lighttpd-1.4.12/doc/configuration.txt 2006-07-16 00:26:05.000000000 +0300
692 :Author: Jan Kneschke
694 -:Revision: $Revision$
696 +:Revision: $Revision$
699 the layout of the configuration file
702 debug.log-request-handling
705 +debug.log-condition-handling
708 +debug.log-condition-cache-handling
709 + for developers only
711 --- ../lighttpd-1.4.11/doc/fastcgi.txt 2006-02-16 17:03:52.000000000 +0200
712 +++ lighttpd-1.4.12/doc/fastcgi.txt 2006-07-16 00:26:05.000000000 +0300
714 PHP can extract PATH_INFO from it (default: disabled)
715 :"disable-time": time to wait before a disabled backend is checked
717 - :"allow-x-send-file": controls if X-LIGHTTPD-send-file headers
719 + :"allow-x-send-file": controls if X-LIGHTTPD-send-file and X-Sendfile
720 + headers are allowed
724 --- ../lighttpd-1.4.11/doc/lighttpd.conf 2006-03-04 14:41:12.000000000 +0200
725 +++ lighttpd-1.4.12/doc/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
726 @@ -172,10 +172,11 @@
727 #dir-listing.activate = "enable"
730 -#debug.log-request-header = "enable"
731 -#debug.log-response-header = "enable"
732 -#debug.log-request-handling = "enable"
733 -#debug.log-file-not-found = "enable"
734 +#debug.log-request-header = "enable"
735 +#debug.log-response-header = "enable"
736 +#debug.log-request-handling = "enable"
737 +#debug.log-file-not-found = "enable"
738 +#debug.log-condition-handling = "enable"
740 ### only root can use these options
742 --- ../lighttpd-1.4.11/doc/performance.txt 2006-02-02 13:01:08.000000000 +0200
743 +++ lighttpd-1.4.12/doc/performance.txt 2006-07-16 00:26:05.000000000 +0300
746 server.stat-cache-engine = "fam" # either fam, simple or disabled
748 +See http://oss.sgi.com/projects/fam/faq.html for information about FAM.
749 +See http://www.gnome.org/~veillard/gamin/overview.html for information about gamin.
751 Platform-Specific Notes
752 =======================
753 --- ../lighttpd-1.4.11/doc/secdownload.txt 2005-12-20 15:58:58.000000000 +0200
754 +++ lighttpd-1.4.12/doc/secdownload.txt 2006-07-16 00:26:05.000000000 +0300
756 $secret = "verysecret";
757 $uri_prefix = "/dl/";
760 + # filename, make sure it's started with a "/" or you'll get 404 in the browser
761 $f = "/secret-file.txt";
764 --- ../lighttpd-1.4.11/lighttpd.spec 2006-03-07 14:22:18.000000000 +0200
765 +++ lighttpd-1.4.12/lighttpd.spec 2006-07-17 22:02:18.000000000 +0300
767 Summary: A fast webserver with minimal memory-footprint (lighttpd)
772 Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-%version.tar.gz
773 Packager: Jan Kneschke <jan@kneschke.de>
774 --- ../lighttpd-1.4.11/openwrt/control 2006-03-07 14:22:19.000000000 +0200
775 +++ lighttpd-1.4.12/openwrt/control 2006-07-17 22:02:18.000000000 +0300
781 Maintainer: Jan Kneschke <jan@kneschke.de>
782 -Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.11.tar.gz
783 +Source: http://jan.kneschke.de/projects/lighttpd/download/lighttpd-1.4.12.tar.gz
787 --- ../lighttpd-1.4.11/openwrt/lighttpd.mk 2006-03-07 14:22:19.000000000 +0200
788 +++ lighttpd-1.4.12/openwrt/lighttpd.mk 2006-07-17 22:02:18.000000000 +0300
791 # For this example we'll use a fairly simple package that compiles easily
792 # and has sources available for download at sourceforge
793 -LIGHTTPD=lighttpd-1.4.11
794 +LIGHTTPD=lighttpd-1.4.12
795 LIGHTTPD_TARGET=.built
796 LIGHTTPD_DIR=$(BUILD_DIR)/$(LIGHTTPD)
797 LIGHTTPD_IPK=$(BUILD_DIR)/$(LIGHTTPD)_mipsel.ipk
798 --- ../lighttpd-1.4.11/src/Makefile.am 2006-03-07 14:20:20.000000000 +0200
799 +++ lighttpd-1.4.12/src/Makefile.am 2006-07-18 13:03:40.000000000 +0300
802 configparser.y: lemon
803 mod_ssi_exprparser.y: lemon
804 +http_resp_parser.y: lemon
806 configparser.c configparser.h: configparser.y
808 - $(LEMON) -q $(srcdir)/configparser.y $(srcdir)/lempar.c
809 + $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
811 +http_resp_parser.c http_resp_parser.h: http_resp_parser.y
812 + rm -f http_resp_parser.h
813 + $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
815 mod_ssi_exprparser.c mod_ssi_exprparser.h: mod_ssi_exprparser.y
816 rm -f mod_ssi_exprparser.h
817 - $(LEMON) -q $(srcdir)/mod_ssi_exprparser.y $(srcdir)/lempar.c
818 + $(LEMON) -q $(srcdir)/$< $(srcdir)/lempar.c
821 configfile.c: configparser.h
822 mod_ssi_expr.c: mod_ssi_exprparser.h
823 +http_resp.c: http_resp_parser.h
825 common_src=buffer.c log.c \
828 fdevent_solaris_devpoll.c fdevent_freebsd_kqueue.c \
829 data_config.c bitset.c \
830 inet_ntop_cache.c crc32.c \
831 - connections-glue.c \
832 + connections-glue.c iosocket.c \
835 network_write.c network_linux_sendfile.c \
836 network_freebsd_sendfile.c network_writev.c \
837 network_solaris_sendfilev.c network_openssl.c \
839 + splaytree.c http_resp.c http_resp_parser.c
841 src = server.c response.c connections.c network.c \
842 configfile.c configparser.c request.c proc_open.c
845 lib_LTLIBRARIES += mod_webdav.la
846 mod_webdav_la_SOURCES = mod_webdav.c
847 -mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
848 +mod_webdav_la_CFLAGS = $(AM_CFLAGS) $(XML_CFLAGS) $(SQLITE_CFLAGS)
849 mod_webdav_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
850 -mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS)
851 +mod_webdav_la_LIBADD = $(common_libadd) $(XML_LIBS) $(SQLITE_LIBS) $(UUID_LIB)
853 lib_LTLIBRARIES += mod_cml.la
854 mod_cml_la_SOURCES = mod_cml.c mod_cml_lua.c mod_cml_funcs.c
856 mod_mysql_vhost_la_LIBADD = $(MYSQL_LIBS) $(common_libadd)
857 mod_mysql_vhost_la_CPPFLAGS = $(MYSQL_INCLUDE)
859 +lib_LTLIBRARIES += mod_sql_vhost_core.la
860 +mod_sql_vhost_core_la_SOURCES = mod_sql_vhost_core.c
861 +mod_sql_vhost_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
862 +mod_sql_vhost_core_la_LIBADD = $(common_libadd)
864 lib_LTLIBRARIES += mod_cgi.la
865 mod_cgi_la_SOURCES = mod_cgi.c
866 mod_cgi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
868 mod_proxy_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
869 mod_proxy_la_LIBADD = $(common_libadd)
871 +lib_LTLIBRARIES += mod_proxy_core.la
872 +mod_proxy_core_la_SOURCES = mod_proxy_core.c mod_proxy_core_pool.c \
873 + mod_proxy_core_backend.c mod_proxy_core_address.c mod_proxy_core_backlog.c
874 +mod_proxy_core_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
875 +mod_proxy_core_la_LIBADD = $(common_libadd)
878 lib_LTLIBRARIES += mod_ssi.la
879 mod_ssi_la_SOURCES = mod_ssi_exprparser.c mod_ssi_expr.c mod_ssi.c
880 mod_ssi_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined
882 mod_ssi.h mod_ssi_expr.h inet_ntop_cache.h \
883 configparser.h mod_ssi_exprparser.h \
884 sys-mmap.h sys-socket.h mod_cml.h mod_cml_funcs.h \
885 - splaytree.h proc_open.h
886 + splaytree.h proc_open.h http_resp.h mod_sql_vhost_core.h \
887 + sys-files.h sys-process.h sys-strings.h http_resp_parser.h \
888 + iosocket.h array-static.h \
889 + mod_proxy_core_address.h mod_proxy_core_backend.h \
890 + mod_proxy_core_backlog.h mod_proxy_core.h \
891 + mod_proxy_core_pool.h
893 DEFS= @DEFS@ -DLIBRARY_DIR="\"$(libdir)\""
898 noinst_HEADERS = $(hdr)
899 -EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c
900 +EXTRA_DIST = mod_skeleton.c configparser.y mod_ssi_exprparser.y lempar.c http_resp_parser.y
901 --- ../lighttpd-1.4.11/src/array-static.h 1970-01-01 03:00:00.000000000 +0300
902 +++ lighttpd-1.4.12/src/array-static.h 2006-07-18 13:03:40.000000000 +0300
904 +#ifndef _ARRAY_STATIC_H_
905 +#define _ARRAY_STATIC_H_
907 +/* define a generic array of <type>
910 +#define ARRAY_STATIC_DEF(name, type, extra) \
918 +/* all append operations need a 'resize' for the +1 */
920 +#define ARRAY_STATIC_PREPARE_APPEND(a) \
921 + if (a->size == 0) { \
923 + a->ptr = malloc(a->size * sizeof(*(a->ptr))); \
924 + } else if (a->size == a->used) { \
926 + a->ptr = realloc(a->ptr, a->size * sizeof(*(a->ptr))); \
929 +#define FOREACH(array, element, func) \
930 +do { size_t _i; for (_i = 0; _i < array->used; _i++) { void *element = array->ptr[_i]; func; } } while(0);
932 +#define STRUCT_INIT(type, var) \
934 + var = calloc(1, sizeof(*var))
937 --- ../lighttpd-1.4.11/src/array.c 2005-11-18 13:58:32.000000000 +0200
938 +++ lighttpd-1.4.12/src/array.c 2006-07-16 00:26:03.000000000 +0300
941 array *array_init(void) {
945 a = calloc(1, sizeof(*a));
949 a->next_power_of_2 = 1;
956 void array_free(array *a) {
961 if (!a->is_weakref) {
962 for (i = 0; i < a->size; i++) {
963 if (a->data[i]) a->data[i]->free(a->data[i]);
968 if (a->data) free(a->data);
969 if (a->sorted) free(a->sorted);
975 void array_reset(array *a) {
980 if (!a->is_weakref) {
981 for (i = 0; i < a->used; i++) {
982 a->data[i]->reset(a->data[i]);
991 static int array_get_index(array *a, const char *key, size_t keylen, int *rndx) {
996 if (key == NULL) return -1;
999 /* try to find the string */
1000 for (i = pos = a->next_power_of_2 / 2; ; i >>= 1) {
1006 } else if (pos >= (int)a->used) {
1009 cmp = buffer_caseless_compare(key, keylen, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used);
1014 ndx = a->sorted[pos];
1015 @@ -110,46 +110,46 @@
1021 if (rndx) *rndx = pos;
1027 data_unset *array_get_element(array *a, const char *key) {
1031 if (-1 != (ndx = array_get_index(a, key, strlen(key) + 1, NULL))) {
1032 /* found, leave here */
1035 return a->data[ndx];
1043 data_unset *array_get_unused_element(array *a, data_type_t t) {
1044 data_unset *ds = NULL;
1049 if (a->size == 0) return NULL;
1052 if (a->used == a->size) return NULL;
1054 if (a->data[a->used]) {
1055 ds = a->data[a->used];
1058 a->data[a->used] = NULL;
1065 /* replace or insert data, return the old one with the same key */
1066 data_unset *array_replace(array *a, data_unset *du) {
1070 if (-1 == (ndx = array_get_index(a, du->key->ptr, du->key->used, NULL))) {
1071 array_insert_unique(a, du);
1073 @@ -164,13 +164,13 @@
1078 - /* generate unique index if neccesary */
1080 + /* generate unique index if necessary */
1081 if (str->key->used == 0 || str->is_index_key) {
1082 buffer_copy_long(str->key, a->unique_ndx++);
1083 str->is_index_key = 1;
1087 /* try to find the string */
1088 if (-1 != (ndx = array_get_index(a, str->key->ptr, str->key->used, &pos))) {
1089 /* found, leave here */
1090 @@ -181,14 +181,14 @@
1099 if (a->used+1 > INT_MAX) {
1100 /* we can't handle more then INT_MAX entries: see array_get_index() */
1107 a->data = malloc(sizeof(*a->data) * a->size);
1108 @@ -204,27 +204,27 @@
1110 for (j = a->used; j < a->size; j++) a->data[j] = NULL;
1114 ndx = (int) a->used;
1117 a->data[a->used++] = str;
1123 buffer_caseless_compare(str->key->ptr, str->key->used, a->data[a->sorted[pos]]->key->ptr, a->data[a->sorted[pos]]->key->used) > 0)) {
1127 - /* move everything on step to the right */
1130 + /* move everything one step to the right */
1132 memmove(a->sorted + (pos + 1), a->sorted + (pos), (ndx - pos) * sizeof(*a->sorted));
1137 a->sorted[pos] = ndx;
1140 if (a->next_power_of_2 == (size_t)ndx) a->next_power_of_2 <<= 1;
1157 array_print_indent(depth);
1158 fprintf(stderr, ")");
1164 @@ -323,47 +323,47 @@
1176 ds = data_string_init();
1177 buffer_copy_string(ds->key, "abc");
1178 buffer_copy_string(ds->value, "alfrag");
1181 array_insert_unique(a, (data_unset *)ds);
1184 ds = data_string_init();
1185 buffer_copy_string(ds->key, "abc");
1186 buffer_copy_string(ds->value, "hameplman");
1189 array_insert_unique(a, (data_unset *)ds);
1192 ds = data_string_init();
1193 buffer_copy_string(ds->key, "123");
1194 buffer_copy_string(ds->value, "alfrag");
1197 array_insert_unique(a, (data_unset *)ds);
1200 dc = data_count_init();
1201 buffer_copy_string(dc->key, "def");
1204 array_insert_unique(a, (data_unset *)dc);
1207 dc = data_count_init();
1208 buffer_copy_string(dc->key, "def");
1211 array_insert_unique(a, (data_unset *)dc);
1220 fprintf(stderr, "%d\n",
1221 buffer_caseless_compare(CONST_STR_LEN("Content-Type"), CONST_STR_LEN("Content-type")));
1227 --- ../lighttpd-1.4.11/src/array.h 2005-09-23 21:24:18.000000000 +0300
1228 +++ lighttpd-1.4.12/src/array.h 2006-07-16 00:26:03.000000000 +0300
1230 #define DATA_UNSET \
1233 - int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
1234 + int is_index_key; /* 1 if key is an array index (auto-generated keys) */ \
1235 struct data_unset *(*copy)(const struct data_unset *src); \
1236 void (* free)(struct data_unset *p); \
1237 void (* reset)(struct data_unset *p); \
1254 size_t next_power_of_2;
1255 int is_weakref; /* data is weakref, don't bother the data */
1284 COMP_SERVER_SOCKET, COMP_HTTP_URL, COMP_HTTP_HOST, COMP_HTTP_REFERER, COMP_HTTP_USERAGENT, COMP_HTTP_COOKIE, COMP_HTTP_REMOTEIP
1287 -/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
1288 +/* $HTTP["host"] == "incremental.home.kneschke.de" { ... }
1289 * for print: comp_key op string
1290 * for compare: comp cond string/regex
1293 typedef struct _data_config data_config;
1294 struct _data_config {
1309 int context_ndx; /* more or less like an id */
1313 /* for chaining only */
1330 @@ -120,13 +120,13 @@
1336 unsigned short port;
1343 int usage; /* fair-balancing needs the no. of connections active on this host */
1344 int last_used_ndx; /* round robin */
1346 --- ../lighttpd-1.4.11/src/base.h 2006-01-11 16:51:04.000000000 +0200
1347 +++ lighttpd-1.4.12/src/base.h 2006-07-18 13:03:40.000000000 +0300
1351 #include <sys/types.h>
1352 -#include <sys/time.h>
1353 #include <sys/stat.h>
1355 #ifdef HAVE_CONFIG_H
1357 #include "sys-socket.h"
1358 #include "splaytree.h"
1361 #if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
1362 # define USE_OPENSSL
1363 -# include <openssl/ssl.h>
1364 +# include <openssl/ssl.h>
1372 -#ifndef O_LARGEFILE
1373 -# define O_LARGEFILE 0
1378 # define SIZE_MAX SIZE_T_MAX
1381 /* solaris and NetBSD 1.3.x again */
1382 #if (!defined(HAVE_STDINT_H)) && (!defined(HAVE_INTTYPES_H)) && (!defined(uint32_t))
1383 -# define uint32_t u_int32_t
1384 +/* # define uint32_t u_int32_t */
1385 +typedef unsigned __int32 uint32_t;
1391 #include "settings.h"
1393 -typedef enum { T_CONFIG_UNSET,
1399 +typedef enum { T_CONFIG_UNSET,
1406 } config_values_type_t;
1408 -typedef enum { T_CONFIG_SCOPE_UNSET,
1409 - T_CONFIG_SCOPE_SERVER,
1410 +typedef enum { T_CONFIG_SCOPE_UNSET,
1411 + T_CONFIG_SCOPE_SERVER,
1412 T_CONFIG_SCOPE_CONNECTION
1413 } config_scope_type_t;
1420 config_values_type_t type;
1421 config_scope_type_t scope;
1423 @@ -118,18 +113,6 @@
1430 - struct sockaddr_in6 ipv6;
1432 - struct sockaddr_in ipv4;
1433 -#ifdef HAVE_SYS_UN_H
1434 - struct sockaddr_un un;
1436 - struct sockaddr plain;
1439 /* fcgi_response_header contains ... */
1440 #define HTTP_STATUS BV(0)
1441 #define HTTP_CONNECTION BV(1)
1442 @@ -142,40 +125,40 @@
1443 /* the request-line */
1451 http_method_t http_method;
1452 http_version_t http_version;
1455 buffer *request_line;
1458 /* strings to the header */
1459 buffer *http_host; /* not alloced */
1460 const char *http_range;
1461 const char *http_content_type;
1462 const char *http_if_modified_since;
1463 const char *http_if_none_match;
1470 size_t content_length; /* returned by strtoul() */
1473 /* internal representation */
1474 int accept_encoding;
1482 off_t content_length;
1483 - int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say the subrequest was keep-alive or not */
1485 + int keep_alive; /* used by the subrequests in proxy, cgi and fcgi to say whether the subrequest was keep-alive or not */
1492 HTTP_TRANSFER_ENCODING_IDENTITY, HTTP_TRANSFER_ENCODING_CHUNKED
1493 } transfer_encoding;
1495 @@ -191,21 +174,21 @@
1498 buffer *basedir; /* path = "(basedir)(.*)" */
1501 buffer *doc_root; /* path = doc_root + rel_path */
1522 @@ -215,20 +198,20 @@
1526 - splay_tree *files; /* the nodes of the tree are stat_cache_entry's */
1528 + splay_tree *files; /* the nodes of the tree are stat_cache_entries */
1530 buffer *dir_name; /* for building the dirname from the filename */
1532 splay_tree *dirs; /* the nodes of the tree are fam_dir_entry */
1544 /* virtual-servers */
1545 buffer *document_root;
1546 buffer *server_name;
1549 buffer *dirlist_encoding;
1550 buffer *errorfile_prefix;
1553 unsigned short max_keep_alive_requests;
1554 unsigned short max_keep_alive_idle;
1555 unsigned short max_read_idle;
1556 @@ -244,16 +227,17 @@
1557 unsigned short use_xattr;
1558 unsigned short follow_symlink;
1559 unsigned short range_requests;
1565 unsigned short log_file_not_found;
1566 unsigned short log_request_header;
1567 unsigned short log_request_handling;
1568 unsigned short log_response_header;
1569 unsigned short log_condition_handling;
1572 + unsigned short log_condition_cache_handling;
1576 buffer *ssl_pemfile;
1577 buffer *ssl_ca_file;
1578 @@ -268,22 +252,22 @@
1580 unsigned short global_kbytes_per_second; /* */
1582 - off_t global_bytes_per_second_cnt;
1583 + off_t global_bytes_per_second_cnt;
1584 /* server-wide traffic-shaper
1587 * each context has the counter which is inited once
1588 - * a second by the global_kbytes_per_second config-var
1589 + * per second by the global_kbytes_per_second config-var
1591 * as soon as global_kbytes_per_second gets below 0
1592 * the connected conns are "offline" a little bit
1595 - * we somehow have to loose our "we are writable" signal
1596 + * we somehow have to lose our "we are writable" signal
1601 off_t *global_bytes_per_second_cnt_ptr; /* */
1607 @@ -291,18 +275,18 @@
1609 /* the order of the items should be the same as they are processed
1610 * read before write as we use this later */
1612 - CON_STATE_CONNECT,
1613 - CON_STATE_REQUEST_START,
1615 - CON_STATE_REQUEST_END,
1616 - CON_STATE_READ_POST,
1617 - CON_STATE_HANDLE_REQUEST,
1618 - CON_STATE_RESPONSE_START,
1620 - CON_STATE_RESPONSE_END,
1624 + CON_STATE_CONNECT,
1625 + CON_STATE_REQUEST_START,
1627 + CON_STATE_REQUEST_END,
1628 + CON_STATE_READ_POST,
1629 + CON_STATE_HANDLE_REQUEST,
1630 + CON_STATE_RESPONSE_START,
1632 + CON_STATE_RESPONSE_END,
1635 } connection_state_t;
1637 typedef enum { COND_RESULT_UNSET, COND_RESULT_FALSE, COND_RESULT_TRUE } cond_result_t;
1638 @@ -315,91 +299,86 @@
1641 connection_state_t state;
1645 time_t read_idle_ts;
1646 time_t close_timeout_ts;
1647 time_t write_request_ts;
1650 time_t connection_start;
1651 time_t request_start;
1654 struct timeval start_tv;
1657 size_t request_count; /* number of requests handled in this connection */
1658 size_t loops_per_request; /* to catch endless loops in a single request
1661 * used by mod_rewrite, mod_fastcgi, ... and others
1662 * this is self-protection
1665 - int fd; /* the FD for this connection */
1666 - int fde_ndx; /* index for the fdevent-handler */
1669 int ndx; /* reverse mapping to server->connection[ndx] */
1676 - int keep_alive; /* only request.c can enable it, all other just disable */
1679 + int keep_alive; /* only request.c can enable it, all others just disable */
1685 chunkqueue *write_queue; /* a large queue for low-level write ( HTTP response ) [ file, mem ] */
1686 chunkqueue *read_queue; /* a small queue for low-level read ( HTTP request ) [ mem ] */
1687 chunkqueue *request_content_queue; /* takes request-content into tempfile if necessary [ tempfile, mem ]*/
1690 int traffic_limit_reached;
1693 off_t bytes_written; /* used by mod_accesslog, mod_rrd */
1694 off_t bytes_written_cur_second; /* used by mod_accesslog, mod_rrd */
1695 off_t bytes_read; /* used by mod_accesslog, mod_rrd */
1703 buffer *dst_addr_buf;
1706 buffer *parse_request;
1707 unsigned int parsed_response; /* bitfield which contains the important header-fields of the parsed response header */
1712 - physical physical;
1713 + physical physical;
1720 buffer *authed_user;
1721 array *environment; /* used to pass lighttpd internal stuff to the FastCGI/CGI apps, setenv does that */
1731 connection_type mode;
1734 void **plugin_ctx; /* plugin connection specific config */
1737 specific_config conf; /* global connection specific config */
1738 cond_cache_t *cond_cache;
1741 buffer *server_name;
1745 buffer *error_handler;
1746 int error_handler_saved_status;
1747 int in_error_handler;
1750 void *srv_socket; /* reference to the server-socket (typecast to server_socket) */
1758 @@ -439,55 +418,63 @@
1763 + NETWORK_STATUS_UNSET,
1764 + NETWORK_STATUS_SUCCESS,
1765 + NETWORK_STATUS_FATAL_ERROR,
1766 + NETWORK_STATUS_CONNECTION_CLOSE,
1767 + NETWORK_STATUS_WAIT_FOR_EVENT,
1768 + NETWORK_STATUS_INTERRUPTED
1769 +} network_status_t;
1772 unsigned short port;
1775 - buffer *errorlog_file;
1776 - unsigned short errorlog_use_syslog;
1779 unsigned short dont_daemonize;
1788 buffer *event_handler;
1791 buffer *modules_dir;
1792 buffer *network_backend;
1794 array *upload_tempdirs;
1797 unsigned short max_worker;
1798 unsigned short max_fds;
1799 unsigned short max_conns;
1800 unsigned short max_request_size;
1803 unsigned short log_request_header_on_error;
1804 unsigned short log_state_handling;
1806 - enum { STAT_CACHE_ENGINE_UNSET,
1807 - STAT_CACHE_ENGINE_NONE,
1808 - STAT_CACHE_ENGINE_SIMPLE,
1809 - STAT_CACHE_ENGINE_FAM
1811 + enum { STAT_CACHE_ENGINE_UNSET,
1812 + STAT_CACHE_ENGINE_NONE,
1813 + STAT_CACHE_ENGINE_SIMPLE,
1814 + STAT_CACHE_ENGINE_FAM
1815 } stat_cache_engine;
1816 unsigned short enable_cores;
1818 + buffer *errorlog_file;
1819 + unsigned short errorlog_use_syslog;
1829 buffer *ssl_pemfile;
1830 buffer *ssl_ca_file;
1831 unsigned short use_ipv6;
1832 unsigned short is_ssl;
1841 @@ -495,37 +482,32 @@
1844 server_socket **ptr;
1849 } server_socket_array;
1851 typedef struct server {
1852 server_socket_array srv_sockets;
1854 - /* the errorlog */
1856 - enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } errorlog_mode;
1857 - buffer *errorlog_buf;
1860 fdevents *ev, *ev_ins;
1863 buffer_plugin plugins;
1877 int max_fds; /* max possible fds */
1878 int cur_fds; /* currently used fds */
1879 int want_fds; /* waiting fds */
1880 int sockets_disabled;
1886 @@ -533,13 +515,13 @@
1887 buffer *response_header;
1888 buffer *response_range;
1892 buffer *tmp_chunk_len;
1895 buffer *empty_string; /* is necessary for cond_match */
1897 buffer *cond_check_buf;
1902 inet_ntop_cache_type inet_ntop_cache[INET_NTOP_CACHE_MAX];
1903 @@ -547,31 +529,31 @@
1904 mtime_cache_type mtime_cache[FILE_CACHE_MAX];
1911 time_t last_generated_date_ts;
1912 time_t last_generated_debug_ts;
1916 buffer *ts_debug_str;
1917 buffer *ts_date_str;
1922 array *config_touched;
1925 array *config_context;
1926 specific_config **config_storage;
1929 server_config srvconf;
1932 int config_deprecated;
1936 connections *joblist;
1937 connections *fdwaitqueue;
1940 stat_cache *stat_cache;
1943 @@ -588,18 +570,20 @@
1944 * fastcgi.backend.<key>.disconnects = ...
1949 fdevent_handler_t event_handler;
1951 - int (* network_backend_write)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1952 - int (* network_backend_read)(struct server *srv, connection *con, int fd, chunkqueue *cq);
1953 + network_status_t (* network_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1954 + network_status_t (* network_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1956 - int (* network_ssl_backend_write)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1957 - int (* network_ssl_backend_read)(struct server *srv, connection *con, SSL *ssl, chunkqueue *cq);
1958 + network_status_t (* network_ssl_backend_write)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1959 + network_status_t (* network_ssl_backend_read)(struct server *srv, connection *con, iosocket *sock, chunkqueue *cq);
1969 --- ../lighttpd-1.4.11/src/bitset.c 2005-08-22 01:54:12.000000000 +0300
1970 +++ lighttpd-1.4.12/src/bitset.c 2006-07-18 13:03:40.000000000 +0300
1977 #define BITSET_BITS \
1978 ( CHAR_BIT * sizeof(size_t) )
1979 --- ../lighttpd-1.4.11/src/buffer.c 2006-01-13 00:00:45.000000000 +0200
1980 +++ lighttpd-1.4.12/src/buffer.c 2006-07-18 13:03:40.000000000 +0300
1991 buffer* buffer_init(void) {
1995 b = malloc(sizeof(*b));
2017 void buffer_free(buffer *b) {
2020 void buffer_reset(buffer *b) {
2024 /* limit don't reuse buffer larger than ... bytes */
2025 if (b->size > BUFFER_MAX_REUSE_SIZE) {
2038 - * allocate (if neccessary) enough space for 'size' bytes and
2040 + * allocate (if necessary) enough space for 'size' bytes and
2041 * set the 'used' counter to 0
2046 #define BUFFER_PIECE_SIZE 64
2048 int buffer_prepare_copy(buffer *b, size_t size) {
2051 - if ((0 == b->size) ||
2053 + if ((0 == b->size) ||
2055 if (b->size) free(b->ptr);
2060 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2062 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2063 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2066 b->ptr = malloc(b->size);
2074 - * increase the internal buffer (if neccessary) to append another 'size' byte
2076 + * increase the internal buffer (if necessary) to append another 'size' byte
2077 * ->used isn't changed
2082 int buffer_prepare_append(buffer *b, size_t size) {
2089 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2091 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2092 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2095 b->ptr = malloc(b->size);
2098 } else if (b->used + size > b->size) {
2101 - /* always allocate a multiply of BUFFER_PIECE_SIZE */
2103 + /* always allocate a multiple of BUFFER_PIECE_SIZE */
2104 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);
2107 b->ptr = realloc(b->ptr, b->size);
2112 int buffer_copy_string(buffer *b, const char *s) {
2116 if (!s || !b) return -1;
2118 s_len = strlen(s) + 1;
2119 @@ -136,26 +136,26 @@
2121 int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
2122 if (!s || !b) return -1;
2124 - /* removed optimization as we have to keep the empty string
2126 + /* removed optimization as we have to keep the empty string
2127 * in some cases for the config handling
2130 * url.access-deny = ( "" )
2132 if (s_len == 0) return 0;
2135 buffer_prepare_copy(b, s_len + 1);
2138 memcpy(b->ptr, s, s_len);
2139 b->ptr[s_len] = '\0';
2140 b->used = s_len + 1;
2146 int buffer_copy_string_buffer(buffer *b, const buffer *src) {
2147 if (!src) return -1;
2150 if (src->used == 0) {
2153 @@ -201,10 +201,10 @@
2156 * append a string to the end of the buffer
2158 - * the resulting buffer is terminated with a '\0'
2159 - * s is treated as a un-terminated string (a \0 is handled a normal character)
2162 + * the resulting buffer is terminated with a '\0'
2163 + * s is treated as an un-terminated string (a \0 is handled as a normal character)
2166 * @param s the string
2167 * @param s_len size of the string (without the terminating \0)
2169 int buffer_append_string_buffer(buffer *b, const buffer *src) {
2170 if (!src) return -1;
2171 if (src->used == 0) return 0;
2174 return buffer_append_string_len(b, src->ptr, src->used - 1);
2179 int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {
2180 if (!s || !b) return -1;
2186 return buffer_append_memory(b, s, s_len);
2189 @@ -402,46 +402,115 @@
2195 + * init the ptr buffer
2198 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer)
2200 + buffer_ptr *l = calloc(1, sizeof(buffer_ptr));
2207 + * free the buffer_array
2210 +void buffer_ptr_free(buffer_ptr *l)
2213 + buffer_ptr_clear(l);
2218 +void buffer_ptr_clear(buffer_ptr *l)
2220 + assert(NULL != l);
2222 + if (l->free && l->used) {
2224 + for (i = 0; i < l->used; i ++) {
2225 + l->free(l->ptr[i]);
2237 +void buffer_ptr_append(buffer_ptr* l, void *item)
2239 + assert(NULL != l);
2240 + if (l->ptr == NULL) {
2242 + l->ptr = (void **)malloc(sizeof(void *) * l->size);
2244 + else if (l->used == l->size) {
2246 + l->ptr = realloc(l->ptr, sizeof(void *) * l->size);
2248 + l->ptr[l->used++] = item;
2251 +void *buffer_ptr_pop(buffer_ptr* l)
2253 + assert(NULL != l && l->used > 0);
2254 + return l->ptr[--l->used];
2257 +void *buffer_ptr_top(buffer_ptr* l)
2259 + assert(NULL != l && l->used > 0);
2260 + return l->ptr[l->used-1];
2268 buffer_array* buffer_array_init(void) {
2272 b = malloc(sizeof(*b));
2284 void buffer_array_reset(buffer_array *b) {
2291 /* if they are too large, reduce them */
2292 for (i = 0; i < b->used; i++) {
2293 buffer_reset(b->ptr[i]);
2302 - * free the buffer_array
2304 + * free the buffer_array
2308 void buffer_array_free(buffer_array *b) {
2313 for (i = 0; i < b->size; i++) {
2314 if (b->ptr[i]) buffer_free(b->ptr[i]);
2318 buffer *buffer_array_append_get_buffer(buffer_array *b) {
2324 b->ptr = malloc(sizeof(*b->ptr) * b->size);
2325 @@ -467,13 +536,13 @@
2331 if (b->ptr[b->used] == NULL) {
2332 b->ptr[b->used] = buffer_init();
2336 b->ptr[b->used]->used = 0;
2339 return b->ptr[b->used++];
2342 @@ -482,23 +551,23 @@
2344 if (len == 0) return NULL;
2345 if (needle == NULL) return NULL;
2348 if (b->used < len) return NULL;
2351 for(i = 0; i < b->used - len; i++) {
2352 if (0 == memcmp(b->ptr + i, needle, len)) {
2361 buffer *buffer_init_string(const char *str) {
2362 buffer *b = buffer_init();
2365 buffer_copy_string(b, str);
2375 - * check if two buffer contain the same data
2377 + * check if two buffers contain the same data
2379 * HISTORY: this function was pretty much optimized, but didn't handled
2380 * alignment properly.
2382 @@ -517,105 +586,105 @@
2383 if (a->used != b->used) return 0;
2384 if (a->used == 0) return 1;
2386 - return (0 == strcmp(a->ptr, b->ptr));
2387 + return (0 == strncmp(a->ptr, b->ptr, a->used - 1));
2390 int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {
2398 return buffer_is_equal(a, &b);
2401 /* simple-assumption:
2403 - * most parts are equal and doing a case conversion needs time
2406 + * most parts are equal and doing a case conversion takes time
2409 int buffer_caseless_compare(const char *a, size_t a_len, const char *b, size_t b_len) {
2410 size_t ndx = 0, max_ndx;
2412 size_t mask = sizeof(*al) - 1;
2418 - /* is the alignment correct ? */
2420 + /* is the alignment correct? */
2421 if ( ((size_t)al & mask) == 0 &&
2422 ((size_t)bl & mask) == 0 ) {
2425 max_ndx = ((a_len < b_len) ? a_len : b_len) & ~mask;
2428 for (; ndx < max_ndx; ndx += sizeof(*al)) {
2429 if (*al != *bl) break;
2443 max_ndx = ((a_len < b_len) ? a_len : b_len);
2446 for (; ndx < max_ndx; ndx++) {
2447 char a1 = *a++, b1 = *b++;
2451 if ((a1 >= 'A' && a1 <= 'Z') && (b1 >= 'a' && b1 <= 'z'))
2453 else if ((a1 >= 'a' && a1 <= 'z') && (b1 >= 'A' && b1 <= 'Z'))
2455 if ((a1 - b1) != 0) return (a1 - b1);
2467 * check if the rightmost bytes of the string are equal.
2474 int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) {
2475 /* no, len -> equal */
2476 if (len == 0) return 1;
2479 /* len > 0, but empty buffers -> not equal */
2480 if (b1->used == 0 || b2->used == 0) return 0;
2483 /* buffers too small -> not equal */
2484 - if (b1->used - 1 < len || b1->used - 1 < len) return 0;
2486 - if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2487 + if (b1->used - 1 < len || b2->used - 1 < len) return 0;
2489 + if (0 == strncmp(b1->ptr + b1->used - 1 - len,
2490 b2->ptr + b2->used - 1 - len, len)) {
2498 int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
2503 if (in_len * 2 < in_len) return -1;
2506 buffer_prepare_copy(b, in_len * 2 + 1);
2509 for (i = 0; i < in_len; i++) {
2510 b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F];
2511 b->ptr[b->used++] = hex_chars[in[i] & 0x0F];
2513 b->ptr[b->used++] = '\0';
2520 0 1 2 3 4 5 6 7 8 9 A B C D E F
2522 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2523 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2524 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2525 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, /* 20 - 2F space " # $ % & ' + , / */
2526 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
2527 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2529 0 1 2 3 4 5 6 7 8 9 A B C D E F
2531 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2532 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2533 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2534 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, /* 20 - 2F space " # $ % & ' + , / */
2535 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 30 - 3F : ; = ? @ < > */
2536 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2538 0 1 2 3 4 5 6 7 8 9 A B C D E F
2540 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2541 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2542 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2543 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
2544 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
2545 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2547 0 1 2 3 4 5 6 7 8 9 A B C D E F
2549 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2550 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2551 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2552 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 2F & */
2553 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, /* 30 - 3F < > */
2554 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 4F */
2555 @@ -712,12 +781,12 @@
2556 0 1 2 3 4 5 6 7 8 9 A B C D E F
2558 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 - 0F control chars */
2559 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2560 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
2561 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
2562 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
2563 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
2564 - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
2565 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 - 1F */
2566 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 - 2F */
2567 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 - 3F */
2568 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 - 4F */
2569 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 - 5F */
2570 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 - 6F */
2571 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 - 7F */
2572 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 - 8F */
2573 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 - 9F */
2574 @@ -734,13 +803,12 @@
2575 unsigned char *ds, *d;
2577 const char *map = NULL;
2580 if (!s || !b) return -1;
2582 - if (b->ptr[b->used - 1] != '\0') {
2586 + if (b->used == 0) return -1;
2588 + if (b->ptr[b->used - 1] != '\0') return -1;
2590 if (s_len == 0) return 0;
2593 @@ -760,12 +828,12 @@
2594 map = encoded_chars_hex;
2596 case ENCODING_UNSET:
2598 + return buffer_append_string_len(b, s, s_len);
2601 assert(map != NULL);
2603 - /* count to-be-encoded-characters */
2605 + /* count to-be-encoded characters */
2606 for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2615 buffer_prepare_append(b, d_len);
2618 for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
2621 @@ -820,16 +888,16 @@
2625 - /* terminate buffer and calculate new length */
2626 + /* terminate buffer and calculate new length */
2627 b->ptr[b->used + d_len - 1] = '\0';
2636 -/* decodes url-special-chars inplace.
2637 +/* decodes url-special chars in-place.
2638 * replaces non-printable characters with '_'
2641 @@ -854,10 +922,10 @@
2642 low = hex2int(*(src + 2));
2644 high = (high << 4) | low;
2646 - /* map control-characters out */
2648 + /* map out control characters */
2649 if (high < 32 || high == 127) high = '_';
2656 * /abc/./xyz gets /abc/xyz
2657 * /abc//xyz gets /abc/xyz
2659 - * NOTE: src and dest can point to the same buffer, in which case,
2660 + * NOTE: src and dest can point to the same buffer, in which case
2661 * the operation is performed in-place.
2664 @@ -979,7 +1047,7 @@
2666 int light_isxdigit(int c) {
2667 if (light_isdigit(c)) return 1;
2671 return (c >= 'a' && c <= 'f');
2673 @@ -993,31 +1061,56 @@
2674 return light_isdigit(c) || light_isalpha(c);
2677 +#undef BUFFER_CTYPE_FUNC
2678 +#define BUFFER_CTYPE_FUNC(type) \
2679 + int buffer_is##type(buffer *b) { \
2681 + if (b->used < 2) return 0; \
2683 + len = b->used - 1; \
2684 + /* c-string only */ \
2685 + if (b->ptr[len] != '\0') { \
2688 + /* check on the whole string */ \
2689 + for (i = 0; i < len; i ++) { \
2690 + if (!light_is##type(b->ptr[i])) { \
2697 +BUFFER_CTYPE_FUNC(digit)
2698 +BUFFER_CTYPE_FUNC(xdigit)
2699 +BUFFER_CTYPE_FUNC(alpha)
2700 +BUFFER_CTYPE_FUNC(alnum)
2702 int buffer_to_lower(buffer *b) {
2706 if (b->used == 0) return 0;
2709 for (c = b->ptr; *c; c++) {
2710 if (*c >= 'A' && *c <= 'Z') {
2720 int buffer_to_upper(buffer *b) {
2724 if (b->used == 0) return 0;
2727 for (c = b->ptr; *c; c++) {
2728 if (*c >= 'a' && *c <= 'z') {
2736 --- ../lighttpd-1.4.11/src/buffer.h 2006-01-13 00:00:45.000000000 +0200
2737 +++ lighttpd-1.4.12/src/buffer.h 2006-07-18 13:03:40.000000000 +0300
2748 +typedef void (*buffer_ptr_free_t)(void *p);
2754 + buffer_ptr_free_t free;
2768 - size_t offset; /* input-pointer */
2770 - size_t used; /* output-pointer */
2772 + size_t offset; /* input pointer */
2774 + size_t used; /* output pointer */
2778 +buffer_ptr *buffer_ptr_init(buffer_ptr_free_t freer);
2779 +void buffer_ptr_free(buffer_ptr *b);
2780 +void buffer_ptr_clear(buffer_ptr *b);
2781 +void buffer_ptr_append(buffer_ptr *b, void *item);
2782 +void *buffer_ptr_pop(buffer_ptr *b);
2783 +void *buffer_ptr_top(buffer_ptr *b);
2785 buffer_array* buffer_array_init(void);
2786 void buffer_array_free(buffer_array *b);
2787 void buffer_array_reset(buffer_array *b);
2789 buffer* buffer_init_string(const char *str);
2790 void buffer_free(buffer *b);
2791 void buffer_reset(buffer *b);
2794 int buffer_prepare_copy(buffer *b, size_t size);
2795 int buffer_prepare_append(buffer *b, size_t size);
2801 - ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of a href */
2802 - ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus coding / too as %2F */
2803 - ENCODING_HTML, /* & becomes & and so on */
2804 + ENCODING_REL_URI, /* for coding a rel-uri (/with space/and%percent) nicely as part of an href */
2805 + ENCODING_REL_URI_PART, /* same as ENC_REL_URL plus encoding "/" as "%2F" */
2806 + ENCODING_HTML, /* "&" becomes "&" and so on */
2807 ENCODING_MINIMAL_XML, /* minimal encoding for xml */
2808 ENCODING_HEX /* encode string as hex */
2809 } buffer_encoding_t;
2810 @@ -111,20 +127,23 @@
2811 int light_isalpha(int c);
2812 int light_isalnum(int c);
2814 +#define BUFFER_CTYPE_FUNC(type) int buffer_is##type(buffer *b);
2815 +BUFFER_CTYPE_FUNC(digit)
2816 +BUFFER_CTYPE_FUNC(xdigit)
2817 +BUFFER_CTYPE_FUNC(alpha)
2818 +BUFFER_CTYPE_FUNC(alnum)
2820 +#define BUF_STR(x) x->ptr
2821 #define BUFFER_APPEND_STRING_CONST(x, y) \
2822 buffer_append_string_len(x, y, sizeof(y) - 1)
2824 #define BUFFER_COPY_STRING_CONST(x, y) \
2825 buffer_copy_string_len(x, y, sizeof(y) - 1)
2827 -#define BUFFER_APPEND_SLASH(x) \
2828 - if (x->used > 1 && x->ptr[x->used - 2] != '/') { BUFFER_APPEND_STRING_CONST(x, "/"); }
2830 #define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
2831 -#define CONST_BUF_LEN(x) x->ptr, x->used ? x->used - 1 : 0
2832 +#define CONST_BUF_LEN(x) BUF_STR(x), x->used ? x->used - 1 : 0
2835 -#define SEGFAULT() do { fprintf(stderr, "%s.%d: aborted\n", __FILE__, __LINE__); abort(); } while(0)
2837 #define UNUSED(x) ( (void)(x) )
2840 --- ../lighttpd-1.4.11/src/chunk.c 2005-11-18 15:18:19.000000000 +0200
2841 +++ lighttpd-1.4.12/src/chunk.c 2006-07-18 13:03:40.000000000 +0300
2844 * the network chunk-API
2851 #include <sys/types.h>
2852 #include <sys/stat.h>
2853 -#include <sys/mman.h>
2857 -#include <unistd.h>
2865 +#include "sys-mmap.h"
2866 +#include "sys-files.h"
2868 chunkqueue *chunkqueue_init(void) {
2872 cq = calloc(1, sizeof(*cq));
2885 static chunk *chunk_init(void) {
2889 c = calloc(1, sizeof(*c));
2892 c->mem = buffer_init();
2893 c->file.name = buffer_init();
2895 c->file.mmap.start = MAP_FAILED;
2902 static void chunk_free(chunk *c) {
2906 buffer_free(c->mem);
2907 buffer_free(c->file.name);
2911 static void chunk_reset(chunk *c) {
2915 buffer_reset(c->mem);
2917 if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
2918 unlink(c->file.name->ptr);
2922 buffer_reset(c->file.name);
2924 if (c->file.fd != -1) {
2927 void chunkqueue_free(chunkqueue *cq) {
2934 for (c = cq->first; c; ) {
2941 for (c = cq->unused; c; ) {
2951 static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
2954 - /* check if we have a unused chunk */
2956 + /* check if we have an unused chunk */
2960 @@ -109,18 +110,18 @@
2962 cq->unused_chunks--;
2969 static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
2970 c->next = cq->first;
2974 if (cq->last == NULL) {
2982 @@ -129,19 +130,19 @@
2988 if (cq->first == NULL) {
2996 void chunkqueue_reset(chunkqueue *cq) {
2998 /* move everything to the unused queue */
3000 - /* mark all read written */
3002 + /* mark all read written */
3003 for (c = cq->first; c; c = c->next) {
3008 c->offset = c->file.length;
3015 @@ -162,93 +163,93 @@
3017 int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
3021 if (len == 0) return 0;
3024 c = chunkqueue_get_unused_chunk(cq);
3027 c->type = FILE_CHUNK;
3030 buffer_copy_string_buffer(c->file.name, fn);
3031 c->file.start = offset;
3032 c->file.length = len;
3036 chunkqueue_append_chunk(cq, c);
3042 int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
3046 if (mem->used == 0) return 0;
3049 c = chunkqueue_get_unused_chunk(cq);
3050 c->type = MEM_CHUNK;
3052 buffer_copy_string_buffer(c->mem, mem);
3055 chunkqueue_append_chunk(cq, c);
3061 int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
3065 if (mem->used == 0) return 0;
3068 c = chunkqueue_get_unused_chunk(cq);
3069 c->type = MEM_CHUNK;
3071 buffer_copy_string_buffer(c->mem, mem);
3074 chunkqueue_prepend_chunk(cq, c);
3080 int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
3084 if (len == 0) return 0;
3087 c = chunkqueue_get_unused_chunk(cq);
3088 c->type = MEM_CHUNK;
3090 buffer_copy_string_len(c->mem, mem, len - 1);
3093 chunkqueue_append_chunk(cq, c);
3099 buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
3103 c = chunkqueue_get_unused_chunk(cq);
3106 c->type = MEM_CHUNK;
3108 buffer_reset(c->mem);
3111 chunkqueue_prepend_chunk(cq, c);
3117 buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
3121 c = chunkqueue_get_unused_chunk(cq);
3124 c->type = MEM_CHUNK;
3126 buffer_reset(c->mem);
3129 chunkqueue_append_chunk(cq, c);
3136 chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
3138 buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
3141 c = chunkqueue_get_unused_chunk(cq);
3143 c->type = FILE_CHUNK;
3144 @@ -273,12 +274,12 @@
3147 /* we have several tempdirs, only if all of them fail we jump out */
3150 for (i = 0; i < cq->tempdirs->used; i++) {
3151 data_string *ds = (data_string *)cq->tempdirs->data[i];
3153 buffer_copy_string_buffer(template, ds->value);
3154 - BUFFER_APPEND_SLASH(template);
3155 + PATHNAME_APPEND_SLASH(template);
3156 BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX");
3158 if (-1 != (c->file.fd = mkstemp(template->ptr))) {
3160 chunkqueue_append_chunk(cq, c);
3162 buffer_free(template);
3169 off_t chunkqueue_length(chunkqueue *cq) {
3174 for (c = cq->first; c; c = c->next) {
3177 @@ -321,14 +322,14 @@
3186 off_t chunkqueue_written(chunkqueue *cq) {
3191 for (c = cq->first; c; c = c->next) {
3203 @@ -355,12 +356,13 @@
3207 + if (c->mem->used == 0) is_finished = 1;
3208 if (c->offset == (off_t)c->mem->used - 1) is_finished = 1;
3211 - if (c->offset == c->file.length) is_finished = 1;
3212 + if (c->offset == c->file.length) is_finished = 1;
3219 @@ -383,3 +385,50 @@
3224 +void chunkqueue_print(chunkqueue *cq) {
3227 + for (c = cq->first; c; c = c->next) {
3228 + fprintf(stderr, "(mem) %s", c->mem->ptr + c->offset);
3230 + fprintf(stderr, "\r\n");
3235 + * remove the last chunk if it is empty
3238 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq) {
3240 + if (!cq->last) return;
3241 + if (!cq->first) return;
3243 + if (cq->first == cq->last) {
3246 + if (c->type != MEM_CHUNK) return;
3247 + if (c->mem->used == 0) {
3249 + cq->first = cq->last = NULL;
3254 + for (c = cq->first; c->next; c = c->next) {
3255 + if (c->type != MEM_CHUNK) continue;
3256 + if (c->mem->used != 0) continue;
3258 + if (c->next == cq->last) {
3261 + chunk_free(c->next);
3270 --- ../lighttpd-1.4.11/src/chunk.h 2005-11-01 09:32:21.000000000 +0200
3271 +++ lighttpd-1.4.12/src/chunk.h 2006-07-18 13:03:40.000000000 +0300
3274 typedef struct chunk {
3275 enum { UNUSED_CHUNK, MEM_CHUNK, FILE_CHUNK } type;
3278 buffer *mem; /* either the storage of the mem-chunk or the read-ahead buffer */
3282 off_t length; /* octets to send from the starting offset */
3287 char *start; /* the start pointer of the mmap'ed area */
3288 size_t length; /* size of the mmap'ed area */
3289 - off_t offset; /* start is <n> octet away from the start of the file */
3290 + off_t offset; /* start is <n> octets away from the start of the file */
3293 - int is_temp; /* file is temporary and will be deleted if on cleanup */
3294 + int is_temp; /* file is temporary and will be deleted on cleanup */
3297 - off_t offset; /* octets sent from this chunk
3298 - the size of the chunk is either
3300 + off_t offset; /* octets sent from this chunk
3301 + the size of the chunk is either
3302 - mem-chunk: mem->used - 1
3303 - file-chunk: file.length
3316 size_t unused_chunks;
3319 buffer * chunkqueue_get_append_buffer(chunkqueue *c);
3320 buffer * chunkqueue_get_prepend_buffer(chunkqueue *c);
3321 chunk * chunkqueue_get_append_tempfile(chunkqueue *cq);
3322 +void chunkqueue_remove_empty_last_chunk(chunkqueue *cq);
3324 int chunkqueue_remove_finished_chunks(chunkqueue *cq);
3328 int chunkqueue_is_empty(chunkqueue *c);
3330 +void chunkqueue_print(chunkqueue *cq);
3333 --- ../lighttpd-1.4.11/src/configfile-glue.c 2006-03-03 20:14:56.000000000 +0200
3334 +++ lighttpd-1.4.12/src/configfile-glue.c 2006-07-16 00:26:03.000000000 +0300
3342 * are the external interface of lighttpd. The functions
3343 * are used by the server itself and the plugins.
3345 - * The main-goal is to have a small library in the end
3346 - * which is linked against both and which will define
3347 + * The main-goal is to have a small library in the end
3348 + * which is linked against both and which will define
3349 * the interface itself in the end.
3356 int config_insert_values_internal(server *srv, array *ca, const config_values_t cv[]) {
3361 for (i = 0; cv[i].key; i++) {
3364 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3372 switch (cv[i].type) {
3373 case T_CONFIG_ARRAY:
3374 if (du->type == TYPE_ARRAY) {
3376 data_array *da = (data_array *)du;
3379 for (j = 0; j < da->value->used; j++) {
3380 if (da->value->data[j]->type == TYPE_STRING) {
3381 data_string *ds = data_string_init();
3384 buffer_copy_string_buffer(ds->value, ((data_string *)(da->value->data[j]))->value);
3385 if (!da->is_index_key) {
3386 /* the id's were generated automaticly, as we copy now we might have to renumber them
3387 - * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3388 + * this is used to prepend server.modules by mod_indexfiles as it has to be loaded
3389 * before mod_fastcgi and friends */
3390 buffer_copy_string_buffer(ds->key, ((data_string *)(da->value->data[j]))->key);
3394 array_insert_unique(cv[i].destination, (data_unset *)ds);
3396 - log_error_write(srv, __FILE__, __LINE__, "sssd",
3397 - "the key of and array can only be a string or a integer, variable:",
3398 - cv[i].key, "type:", da->value->data[j]->type);
3400 + log_error_write(srv, __FILE__, __LINE__, "sssd",
3401 + "the key of and array can only be a string or a integer, variable:",
3402 + cv[i].key, "type:", da->value->data[j]->type);
3408 log_error_write(srv, __FILE__, __LINE__, "sss", "unexpected type for key: ", cv[i].key, "array of strings");
3414 case T_CONFIG_STRING:
3415 if (du->type == TYPE_STRING) {
3416 data_string *ds = (data_string *)du;
3419 buffer_copy_string_buffer(cv[i].destination, ds->value);
3420 + } else if (du->type == TYPE_INTEGER) {
3421 + data_integer *di = (data_integer *)du;
3423 + buffer_copy_long(cv[i].destination, di->value);
3425 log_error_write(srv, __FILE__, __LINE__, "ssss", "unexpected type for key: ", cv[i].key, "(string)", "\"...\"");
3433 case TYPE_INTEGER: {
3434 data_integer *di = (data_integer *)du;
3437 *((unsigned short *)(cv[i].destination)) = di->value;
3441 data_string *ds = (data_string *)du;
3444 + if (buffer_isdigit(ds->value)) {
3445 + *((unsigned short *)(cv[i].destination)) = strtol(ds->value->ptr, NULL, 10);
3449 log_error_write(srv, __FILE__, __LINE__, "ssb", "get a string but expected a short:", cv[i].key, ds->value);
3455 @@ -100,19 +110,19 @@
3456 case T_CONFIG_BOOLEAN:
3457 if (du->type == TYPE_STRING) {
3458 data_string *ds = (data_string *)du;
3461 if (buffer_is_equal_string(ds->value, CONST_STR_LEN("enable"))) {
3462 *((unsigned short *)(cv[i].destination)) = 1;
3463 } else if (buffer_is_equal_string(ds->value, CONST_STR_LEN("disable"))) {
3464 *((unsigned short *)(cv[i].destination)) = 0;
3466 log_error_write(srv, __FILE__, __LINE__, "ssbs", "ERROR: unexpected value for key:", cv[i].key, ds->value, "(enable|disable)");
3472 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: unexpected type for key:", cv[i].key, "(string)", "\"(enable|disable)\"");
3480 case T_CONFIG_DEPRECATED:
3481 log_error_write(srv, __FILE__, __LINE__, "ssss", "ERROR: found deprecated key:", cv[i].key, "-", (char *)(cv[i].destination));
3484 srv->config_deprecated = 1;
3490 @@ -133,25 +143,25 @@
3491 int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
3496 for (i = 0; cv[i].key; i++) {
3497 data_string *touched;
3500 if (NULL == (du = array_get_element(ca, cv[i].key))) {
3509 touched = data_string_init();
3512 buffer_copy_string(touched->value, "");
3513 buffer_copy_string_buffer(touched->key, du->key);
3516 array_insert_unique(srv->config_touched, (data_unset *)touched);
3520 return config_insert_values_internal(srv, ca, cv);
3523 @@ -191,25 +201,25 @@
3526 /* pass the rules */
3530 case COMP_HTTP_HOST: {
3531 char *ck_colon = NULL, *val_colon = NULL;
3534 if (!buffer_is_empty(con->uri.authority)) {
3539 * append server-port to the HTTP_POST if necessary
3543 l = con->uri.authority;
3547 case CONFIG_COND_NE:
3548 case CONFIG_COND_EQ:
3549 ck_colon = strchr(dc->string->ptr, ':');
3550 val_colon = strchr(l->ptr, ':');
3553 if (ck_colon == val_colon) {
3554 /* nothing to do with it */
3556 @@ -230,21 +240,21 @@
3561 + l = srv->empty_string;
3565 case COMP_HTTP_REMOTEIP: {
3567 - /* handle remoteip limitations
3569 + /* handle remoteip limitations
3571 * "10.0.0.1" is provided for all comparisions
3574 * only for == and != we support
3581 if ((dc->cond == CONFIG_COND_EQ ||
3582 dc->cond == CONFIG_COND_NE) &&
3583 (con->dst_addr.plain.sa_family == AF_INET) &&
3584 @@ -253,41 +263,48 @@
3587 struct in_addr val_inp;
3590 + if (con->conf.log_condition_handling) {
3591 + l = srv->empty_string;
3593 + log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
3594 + "(", l, ") compare to", dc->string);
3597 if (*(nm_slash+1) == '\0') {
3598 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);
3601 return COND_RESULT_FALSE;
3605 nm_bits = strtol(nm_slash + 1, &err, 10);
3609 log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, *err);
3612 return COND_RESULT_FALSE;
3616 /* take IP convert to the native */
3617 buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
3620 if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
3621 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3624 return COND_RESULT_FALSE;
3628 if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
3629 log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);
3632 return COND_RESULT_FALSE;
3638 nm = htonl(~((1 << (32 - nm_bits)) - 1));
3641 if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
3642 return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
3646 case COMP_HTTP_REFERER: {
3650 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
3655 return COND_RESULT_FALSE;
3660 if (con->conf.log_condition_handling) {
3661 log_error_write(srv, __FILE__, __LINE__, "bsbs", dc->comp_key,
3662 @@ -346,10 +363,10 @@
3664 return COND_RESULT_FALSE;
3668 if (con->conf.log_condition_handling) {
3669 log_error_write(srv, __FILE__, __LINE__, "bsbsb", dc->comp_key,
3670 - "(", l, ") compare to ", dc->string);
3671 + "(", l, ") compare to", dc->string);
3674 case CONFIG_COND_NE:
3675 @@ -365,13 +382,13 @@
3676 case CONFIG_COND_MATCH: {
3677 cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
3682 #define elementsof(x) (sizeof(x) / sizeof(x[0]))
3684 n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
3685 cache->matches, elementsof(cache->matches));
3688 cache->patterncount = n;
3690 cache->comp_value = l;
3697 return COND_RESULT_FALSE;
3701 cond_cache_t *caches = con->cond_cache;
3703 if (COND_RESULT_UNSET == caches[dc->context_ndx].result) {
3704 + if (con->conf.log_condition_handling) {
3705 + log_error_write(srv, __FILE__, __LINE__, "sds", "=== start of", dc->context_ndx, "condition block ===");
3707 if (COND_RESULT_TRUE == (caches[dc->context_ndx].result = config_check_cond_nocache(srv, con, dc))) {
3710 @@ -409,11 +429,11 @@
3712 if (con->conf.log_condition_handling) {
3713 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3714 - "(uncached) result:",
3716 caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3719 - if (con->conf.log_condition_handling) {
3720 + if (con->conf.log_condition_cache_handling) {
3721 log_error_write(srv, __FILE__, __LINE__, "dss", dc->context_ndx,
3723 caches[dc->context_ndx].result == COND_RESULT_TRUE ? "true" : "false");
3727 int config_check_cond(server *srv, connection *con, data_config *dc) {
3728 - if (con->conf.log_condition_handling) {
3729 - log_error_write(srv, __FILE__, __LINE__, "s", "=== start of condition block ===");
3731 return (config_check_cond_cached(srv, con, dc) == COND_RESULT_TRUE);
3734 @@ -443,3 +460,85 @@
3738 +/* return <0 on error
3739 + * return 0-x if matched (and replaced)
3741 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result)
3745 + pcre_extra *extra;
3746 + const char *pattern;
3747 + size_t pattern_len;
3750 + pcre_keyvalue *kv;
3754 + for (i = 0; i < kvb->used; i++) {
3758 + extra = kv->key_extra;
3759 + pattern = kv->value->ptr;
3760 + pattern_len = kv->value->used - 1;
3762 + if ((n = pcre_exec(match, extra, match_buf->ptr, match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
3763 + if (n != PCRE_ERROR_NOMATCH) {
3767 + const char **list;
3768 + size_t start, end;
3772 + pcre_get_substring_list(match_buf->ptr, ovec, n, &list);
3774 + /* search for $[0-9] */
3776 + buffer_reset(result);
3778 + start = 0; end = pattern_len;
3779 + for (k = 0; k < pattern_len; k++) {
3780 + if ((pattern[k] == '$' || pattern[k] == '%') &&
3781 + isdigit((unsigned char)pattern[k + 1])) {
3784 + size_t num = pattern[k + 1] - '0';
3788 + buffer_append_string_len(result, pattern + start, end - start);
3790 + if (pattern[k] == '$') {
3791 + /* n is always > 0 */
3792 + if (num < (size_t)n) {
3793 + buffer_append_string(result, list[num]);
3796 + config_append_cond_match_buffer(con, context, result, num);
3804 + buffer_append_string_len(result, pattern + start, pattern_len - start);
3812 + return PCRE_ERROR_NOMATCH;
3820 --- ../lighttpd-1.4.11/src/configfile.c 2006-02-15 14:26:42.000000000 +0200
3821 +++ lighttpd-1.4.12/src/configfile.c 2006-07-18 13:03:40.000000000 +0300
3826 -#include <unistd.h>
3835 -#include "license.h"
3838 #include "configparser.h"
3839 #include "configfile.h"
3840 #include "proc_open.h"
3842 +#include "sys-files.h"
3843 +#include "sys-process.h"
3847 +#define PATH_MAX 64
3850 static int config_insert(server *srv) {
3853 buffer *stat_cache_string;
3855 - config_values_t cv[] = {
3857 + config_values_t cv[] = {
3858 { "server.bind", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 */
3859 { "server.errorlog", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 */
3860 { "server.errorfile-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 */
3862 { "server.tag", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
3863 { "server.use-ipv6", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
3864 { "server.modules", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_SERVER }, /* 9 */
3867 { "server.event-handler", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 */
3868 { "server.pid-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 */
3869 { "server.max-request-size", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
3871 { "server.max-keep-alive-requests", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 17 */
3872 { "server.name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 18 */
3873 { "server.max-keep-alive-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 19 */
3876 { "server.max-read-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 20 */
3877 { "server.max-write-idle", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 21 */
3878 { "server.error-handler-404", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 22 */
3880 { "mimetype.use-xattr", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 27 */
3881 { "mimetype.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 28 */
3882 { "ssl.pemfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 29 */
3885 { "ssl.engine", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 30 */
3888 { "debug.log-file-not-found", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 31 */
3889 { "debug.log-request-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 32 */
3890 { "debug.log-response-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 33 */
3891 { "debug.log-request-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 34 */
3894 { "server.protocol-http11", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 35 */
3895 { "debug.log-request-header-on-error", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 36 */
3896 { "debug.log-state-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 37 */
3897 { "ssl.ca-file", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 38 */
3900 { "server.errorlog-use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 39 */
3901 { "server.range-requests", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 40 */
3902 { "server.stat-cache-engine", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 41 */
3904 { "server.network-backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 43 */
3905 { "server.upload-dirs", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 44 */
3906 { "server.core-files", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 45 */
3908 + { "debug.log-condition-cache-handling", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_SERVER }, /* 46 */
3910 { "server.host", "use server.bind instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3911 { "server.docroot", "use server.document-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3912 { "server.virtual-root", "load mod_simple_vhost and use simple-vhost.server-root instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3914 { "server.groupid", "use server.groupname instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3915 { "server.use-keep-alive", "use server.max-keep-alive-requests = 0 instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3916 { "server.force-lower-case-files", "use server.force-lowercase-filenames instead", T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_UNSET },
3919 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
3925 cv[0].destination = srv->srvconf.bindhost;
3926 cv[1].destination = srv->srvconf.errorlog_file;
3927 @@ -102,33 +105,33 @@
3928 cv[4].destination = srv->srvconf.username;
3929 cv[5].destination = srv->srvconf.groupname;
3930 cv[6].destination = &(srv->srvconf.port);
3933 cv[9].destination = srv->srvconf.modules;
3934 cv[10].destination = srv->srvconf.event_handler;
3935 cv[11].destination = srv->srvconf.pid_file;
3938 cv[13].destination = &(srv->srvconf.max_worker);
3939 cv[23].destination = &(srv->srvconf.max_fds);
3940 cv[36].destination = &(srv->srvconf.log_request_header_on_error);
3941 cv[37].destination = &(srv->srvconf.log_state_handling);
3944 cv[39].destination = &(srv->srvconf.errorlog_use_syslog);
3947 stat_cache_string = buffer_init();
3948 cv[41].destination = stat_cache_string;
3949 cv[43].destination = srv->srvconf.network_backend;
3950 cv[44].destination = srv->srvconf.upload_tempdirs;
3951 cv[45].destination = &(srv->srvconf.enable_cores);
3954 cv[42].destination = &(srv->srvconf.max_conns);
3955 cv[12].destination = &(srv->srvconf.max_request_size);
3956 srv->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
3958 assert(srv->config_storage);
3961 for (i = 0; i < srv->config_context->used; i++) {
3965 s = calloc(1, sizeof(specific_config));
3967 s->document_root = buffer_init();
3968 @@ -154,17 +157,18 @@
3969 s->global_kbytes_per_second = 0;
3970 s->global_bytes_per_second_cnt = 0;
3971 s->global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
3974 cv[2].destination = s->errorfile_prefix;
3977 cv[7].destination = s->server_tag;
3978 cv[8].destination = &(s->use_ipv6);
3984 cv[14].destination = s->document_root;
3985 cv[15].destination = &(s->force_lowercase_filenames);
3986 cv[16].destination = &(s->log_condition_handling);
3987 + cv[46].destination = &(s->log_condition_cache_handling);
3988 cv[17].destination = &(s->max_keep_alive_requests);
3989 cv[18].destination = s->server_name;
3990 cv[19].destination = &(s->max_keep_alive_idle);
3991 @@ -179,23 +183,23 @@
3992 cv[28].destination = s->mimetypes;
3993 cv[29].destination = s->ssl_pemfile;
3994 cv[30].destination = &(s->is_ssl);
3997 cv[31].destination = &(s->log_file_not_found);
3998 cv[32].destination = &(s->log_request_handling);
3999 cv[33].destination = &(s->log_response_header);
4000 cv[34].destination = &(s->log_request_header);
4003 cv[35].destination = &(s->allow_http11);
4004 cv[38].destination = s->ssl_ca_file;
4005 cv[40].destination = &(s->range_requests);
4008 srv->config_storage[i] = s;
4011 if (0 != (ret = config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv))) {
4017 if (buffer_is_empty(stat_cache_string)) {
4018 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_SIMPLE;
4019 } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("simple"))) {
4020 @@ -205,22 +209,22 @@
4021 } else if (buffer_is_equal_string(stat_cache_string, CONST_STR_LEN("disable"))) {
4022 srv->srvconf.stat_cache_engine = STAT_CACHE_ENGINE_NONE;
4024 - log_error_write(srv, __FILE__, __LINE__, "sb",
4025 + log_error_write(srv, __FILE__, __LINE__, "sb",
4026 "server.stat-cache-engine can be one of \"disable\", \"simple\", \"fam\", but not:", stat_cache_string);
4027 ret = HANDLER_ERROR;
4031 buffer_free(stat_cache_string);
4040 -#define PATCH(x) con->conf.x = s->x
4042 + con->conf.x = s->x
4043 int config_setup_connection(server *srv, connection *con) {
4044 specific_config *s = srv->config_storage[0];
4047 PATCH(allow_http11);
4049 PATCH(document_root);
4050 @@ -236,20 +240,21 @@
4051 PATCH(kbytes_per_second);
4052 PATCH(global_kbytes_per_second);
4053 PATCH(global_bytes_per_second_cnt);
4056 con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
4057 buffer_copy_string_buffer(con->server_name, s->server_name);
4060 PATCH(log_request_header);
4061 PATCH(log_response_header);
4062 PATCH(log_request_handling);
4063 PATCH(log_condition_handling);
4064 + PATCH(log_condition_cache_handling);
4065 PATCH(log_file_not_found);
4068 PATCH(range_requests);
4069 PATCH(force_lowercase_filenames);
4076 @@ -257,22 +262,22 @@
4078 int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
4082 /* skip the first, the global context */
4083 for (i = 1; i < srv->config_context->used; i++) {
4084 data_config *dc = (data_config *)srv->config_context->data[i];
4085 specific_config *s = srv->config_storage[i];
4089 if (comp != dc->comp) continue;
4092 /* condition didn't match */
4093 if (!config_check_cond(srv, con, dc)) continue;
4097 for (j = 0; j < dc->value->used; j++) {
4098 data_unset *du = dc->value->data[j];
4101 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
4102 PATCH(document_root);
4103 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.range-requests"))) {
4104 @@ -315,11 +320,13 @@
4105 PATCH(log_response_header);
4106 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-handling"))) {
4107 PATCH(log_condition_handling);
4108 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-condition-cache-handling"))) {
4109 + PATCH(log_condition_cache_handling);
4110 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("debug.log-file-not-found"))) {
4111 PATCH(log_file_not_found);
4112 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.protocol-http11"))) {
4113 PATCH(allow_http11);
4114 - } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4115 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.force-lowercase-filenames"))) {
4116 PATCH(force_lowercase_filenames);
4117 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
4118 PATCH(global_kbytes_per_second);
4128 @@ -336,15 +343,15 @@
4134 const buffer *source;
4150 if (0 != stream_open(&(t->s), t->file)) {
4151 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4152 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4153 "opening configfile ", t->file, "failed:", strerror(errno));
4154 buffer_free(t->file);
4157 t->size = t->s.size;
4166 static int config_skip_comment(tokenizer_t *t) {
4168 assert(t->input[t->offset] == '#');
4169 - for (i = 1; t->input[t->offset + i] &&
4170 + for (i = 1; t->input[t->offset + i] &&
4171 (t->input[t->offset + i] != '\n' && t->input[t->offset + i] != '\r');
4174 @@ -411,44 +418,44 @@
4175 static int config_tokenizer(server *srv, tokenizer_t *t, int *token_id, buffer *token) {
4180 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
4181 char c = t->input[t->offset];
4182 const char *start = NULL;
4189 if (t->input[t->offset + 1] == '>') {
4193 buffer_copy_string(token, "=>");
4196 tid = TK_ARRAY_ASSIGN;
4198 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4199 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4200 "source:", t->source,
4201 - "line:", t->line, "pos:", t->line_pos,
4202 + "line:", t->line, "pos:", t->line_pos,
4203 "use => for assignments in arrays");
4206 } else if (t->in_cond) {
4207 if (t->input[t->offset + 1] == '=') {
4211 buffer_copy_string(token, "==");
4215 } else if (t->input[t->offset + 1] == '~') {
4219 buffer_copy_string(token, "=~");
4224 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4225 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4226 "source:", t->source,
4227 - "line:", t->line, "pos:", t->line_pos,
4228 + "line:", t->line, "pos:", t->line_pos,
4229 "only =~ and == are allowed in the condition");
4232 @@ -456,51 +463,51 @@
4234 } else if (t->in_key) {
4238 buffer_copy_string_len(token, t->input + t->offset, 1);
4244 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4245 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4246 "source:", t->source,
4247 - "line:", t->line, "pos:", t->line_pos,
4248 + "line:", t->line, "pos:", t->line_pos,
4249 "unexpected equal-sign: =");
4258 if (t->input[t->offset + 1] == '=') {
4262 buffer_copy_string(token, "!=");
4266 } else if (t->input[t->offset + 1] == '~') {
4270 buffer_copy_string(token, "!~");
4275 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4276 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4277 "source:", t->source,
4278 - "line:", t->line, "pos:", t->line_pos,
4279 + "line:", t->line, "pos:", t->line_pos,
4280 "only !~ and != are allowed in the condition");
4286 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4287 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4288 "source:", t->source,
4289 - "line:", t->line, "pos:", t->line_pos,
4290 + "line:", t->line, "pos:", t->line_pos,
4291 "unexpected exclamation-marks: !");
4299 @@ -546,10 +553,10 @@
4301 if (t->in_brace > 0) {
4305 buffer_copy_string(token, "(COMMA)");
4312 @@ -557,70 +564,70 @@
4313 /* search for the terminating " */
4314 start = t->input + t->offset + 1;
4315 buffer_copy_string(token, "");
4318 for (i = 1; t->input[t->offset + i]; i++) {
4319 if (t->input[t->offset + i] == '\\' &&
4320 t->input[t->offset + i + 1] == '"') {
4323 buffer_append_string_len(token, start, t->input + t->offset + i - start);
4326 start = t->input + t->offset + i + 1;
4337 if (t->input[t->offset + i] == '"') {
4341 buffer_append_string_len(token, start, t->input + t->offset + i - start);
4348 if (t->input[t->offset + i] == '\0') {
4351 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4353 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4354 "source:", t->source,
4355 - "line:", t->line, "pos:", t->line_pos,
4356 + "line:", t->line, "pos:", t->line_pos,
4357 "missing closing quote");
4365 t->line_pos += i + 1;
4377 buffer_copy_string(token, "(");
4387 buffer_copy_string(token, ")");
4398 buffer_copy_string(token, "$");
4404 @@ -637,115 +644,107 @@
4413 buffer_copy_string(token, "{");
4426 buffer_copy_string(token, "}");
4438 buffer_copy_string(token, "[");
4451 buffer_copy_string(token, "]");
4456 t->line_pos += config_skip_comment(t);
4462 - for (i = 0; t->input[t->offset + i] &&
4463 + for (i = 0; t->input[t->offset + i] &&
4464 (isalpha((unsigned char)t->input[t->offset + i])
4468 if (i && t->input[t->offset + i]) {
4469 tid = TK_SRVVARNAME;
4470 buffer_copy_string_len(token, t->input + t->offset, i);
4477 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4478 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4479 "source:", t->source,
4480 - "line:", t->line, "pos:", t->line_pos,
4481 + "line:", t->line, "pos:", t->line_pos,
4482 "invalid character in condition");
4485 } else if (isdigit((unsigned char)c)) {
4486 /* take all digits */
4487 for (i = 0; t->input[t->offset + i] && isdigit((unsigned char)t->input[t->offset + i]); i++);
4490 /* was there it least a digit ? */
4491 - if (i && t->input[t->offset + i]) {
4496 buffer_copy_string_len(token, t->input + t->offset, i);
4503 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4504 - "source:", t->source,
4505 - "line:", t->line, "pos:", t->line_pos,
4506 - "unexpected EOF");
4511 /* the key might consist of [-.0-9a-z] */
4512 - for (i = 0; t->input[t->offset + i] &&
4513 - (isalnum((unsigned char)t->input[t->offset + i]) ||
4514 + for (i = 0; t->input[t->offset + i] &&
4515 + (isalnum((unsigned char)t->input[t->offset + i]) ||
4516 t->input[t->offset + i] == '.' ||
4517 t->input[t->offset + i] == '_' || /* for env.* */
4518 t->input[t->offset + i] == '-'
4522 if (i && t->input[t->offset + i]) {
4523 buffer_copy_string_len(token, t->input + t->offset, i);
4525 - if (strcmp(token->ptr, "include") == 0) {
4527 + if (buffer_is_equal_string(token, CONST_STR_LEN("include"))) {
4529 - } else if (strcmp(token->ptr, "include_shell") == 0) {
4530 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("include_shell"))) {
4531 tid = TK_INCLUDE_SHELL;
4532 - } else if (strcmp(token->ptr, "global") == 0) {
4533 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("global"))) {
4535 - } else if (strcmp(token->ptr, "else") == 0) {
4536 + } else if (buffer_is_equal_string(token, CONST_STR_LEN("else"))) {
4547 - log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4548 + log_error_write(srv, __FILE__, __LINE__, "sbsdsds",
4549 "source:", t->source,
4550 - "line:", t->line, "pos:", t->line_pos,
4551 + "line:", t->line, "pos:", t->line_pos,
4552 "invalid character in variable name");
4555 @@ -753,16 +752,16 @@
4564 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4565 + log_error_write(srv, __FILE__, __LINE__, "sbsdsdbdd",
4566 "source:", t->source,
4567 "line:", t->line, "pos:", t->line_pos,
4568 token, token->used - 1, tid);
4573 } else if (t->offset < t->size) {
4574 fprintf(stderr, "%s.%d: %d, %s\n",
4575 @@ -781,10 +780,11 @@
4576 pParser = configparserAlloc( malloc );
4577 lasttoken = buffer_init();
4578 token = buffer_init();
4580 while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
4581 buffer_copy_string_buffer(lasttoken, token);
4582 configparser(pParser, token_id, token, context);
4585 token = buffer_init();
4588 @@ -797,14 +797,14 @@
4591 configparserFree(pParser, free);
4595 - log_error_write(srv, __FILE__, __LINE__, "sb",
4596 + log_error_write(srv, __FILE__, __LINE__, "sb",
4597 "configfile parser failed:", lasttoken);
4598 } else if (context->ok == 0) {
4599 - log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4600 + log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
4601 "source:", t->source,
4602 - "line:", t->line, "pos:", t->line_pos,
4603 + "line:", t->line, "pos:", t->line_pos,
4604 "parser failed somehow near here:", lasttoken);
4619 if (0 != stream_open(&s, filename)) {
4620 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4621 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4622 "opening configfile ", filename, "failed:", strerror(errno));
4626 char oldpwd[PATH_MAX];
4628 if (NULL == getcwd(oldpwd, sizeof(oldpwd))) {
4629 - log_error_write(srv, __FILE__, __LINE__, "s",
4630 + log_error_write(srv, __FILE__, __LINE__, "s",
4631 "cannot get cwd", strerror(errno));
4637 if (0 != proc_open_buffer(&proc, cmd, NULL, out, NULL)) {
4638 - log_error_write(srv, __FILE__, __LINE__, "sbss",
4639 + log_error_write(srv, __FILE__, __LINE__, "sbss",
4640 "opening", source, "failed:", strerror(errno));
4643 @@ -896,13 +896,12 @@
4644 static void context_init(server *srv, config_t *context) {
4647 - context->configs_stack = array_init();
4648 - context->configs_stack->is_weakref = 1;
4649 + context->configs_stack = buffer_ptr_init(NULL);
4650 context->basedir = buffer_init();
4653 static void context_free(config_t *context) {
4654 - array_free(context->configs_stack);
4655 + buffer_ptr_free(context->configs_stack);
4656 buffer_free(context->basedir);
4659 @@ -918,18 +917,15 @@
4660 context_init(srv, &context);
4661 context.all_configs = srv->config_context;
4670 + /* use the current dir as basedir for all other includes
4672 + pos = strrchr(fn, DIR_SEPERATOR);
4675 buffer_copy_string_len(context.basedir, fn, pos - fn + 1);
4680 dc = data_config_init();
4681 buffer_copy_string(dc->key, "global");
4684 dpid->value = getpid();
4685 buffer_copy_string(dpid->key, "var.PID");
4686 array_insert_unique(srv->config, (data_unset *)dpid);
4689 dcwd = data_string_init();
4690 buffer_prepare_copy(dcwd->value, 1024);
4691 if (NULL != getcwd(dcwd->value->ptr, dcwd->value->size - 1)) {
4698 if (NULL != (modules = (data_array *)array_get_element(srv->config, "server.modules"))) {
4700 data_array *prepends;
4701 @@ -1026,22 +1022,23 @@
4702 buffer_copy_string(modules->key, "server.modules");
4703 array_insert_unique(srv->config, (data_unset *)modules);
4708 if (0 != config_insert(srv)) {
4717 int config_set_defaults(server *srv) {
4719 specific_config *s = srv->config_storage[0];
4720 struct stat st1, st2;
4722 - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4725 + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
4727 /* - poll is most reliable
4728 * - select works everywhere
4729 * - linux-* are experimental
4730 @@ -1067,20 +1064,21 @@
4732 { FDEVENT_HANDLER_UNSET, NULL }
4736 - if (buffer_is_empty(s->document_root)) {
4737 - log_error_write(srv, __FILE__, __LINE__, "s",
4738 - "a default document-root has to be set");
4744 + if (buffer_is_empty(s->document_root)) {
4745 + log_error_write(srv, __FILE__, __LINE__, "s",
4746 + "a default document-root has to be set");
4751 if (buffer_is_empty(srv->srvconf.changeroot)) {
4752 - if (-1 == stat(s->document_root->ptr, &st1)) {
4753 - log_error_write(srv, __FILE__, __LINE__, "sb",
4754 + pathname_unix2local(s->document_root);
4755 + if (-1 == stat(s->document_root->ptr, &st1)) {
4756 + log_error_write(srv, __FILE__, __LINE__, "sbs",
4757 "base-docroot doesn't exist:",
4758 - s->document_root);
4759 + s->document_root, strerror(errno));
4763 @@ -1088,18 +1086,18 @@
4764 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
4765 buffer_append_string_buffer(srv->tmp_buf, s->document_root);
4767 - if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4768 - log_error_write(srv, __FILE__, __LINE__, "sb",
4769 + if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
4770 + log_error_write(srv, __FILE__, __LINE__, "sb",
4771 "base-docroot doesn't exist:",
4780 - buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4782 - buffer_to_lower(srv->tmp_buf);
4783 + buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4785 + buffer_to_lower(srv->tmp_buf);
4787 if (0 == stat(srv->tmp_buf->ptr, &st1)) {
4789 @@ -1107,68 +1105,68 @@
4790 is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);
4792 /* lower-case existed, check upper-case */
4793 - buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4794 + buffer_copy_string_buffer(srv->tmp_buf, s->document_root);
4796 - buffer_to_upper(srv->tmp_buf);
4797 + buffer_to_upper(srv->tmp_buf);
4799 /* we have to handle the special case that upper and lower-casing results in the same filename
4800 * as in server.document-root = "/" or "/12345/" */
4802 if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
4803 - /* lower-casing and upper-casing didn't result in
4804 - * an other filename, no need to stat(),
4805 + /* lower-casing and upper-casing didn't result in
4806 + * an other filename, no need to stat(),
4807 * just assume it is case-sensitive. */
4809 s->force_lowercase_filenames = 0;
4810 - } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4811 + } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {
4813 + /* upper case exists too, doesn't the FS handle this ? */
4815 + /* upper and lower have the same inode -> case-insensitve FS */
4817 + if (st1.st_ino == st2.st_ino) {
4818 + /* upper and lower have the same inode -> case-insensitve FS */
4820 + s->force_lowercase_filenames = 1;
4825 - /* upper case exists too, doesn't the FS handle this ? */
4827 - /* upper and lower have the same inode -> case-insensitve FS */
4829 - if (st1.st_ino == st2.st_ino) {
4830 - /* upper and lower have the same inode -> case-insensitve FS */
4832 - s->force_lowercase_filenames = 1;
4837 if (srv->srvconf.port == 0) {
4838 srv->srvconf.port = s->is_ssl ? 443 : 80;
4842 if (srv->srvconf.event_handler->used == 0) {
4843 /* choose a good default
4845 - * the event_handler list is sorted by 'goodness'
4847 + * the event_handler list is sorted by 'goodness'
4848 * taking the first available should be the best solution
4850 srv->event_handler = event_handlers[0].et;
4853 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4854 - log_error_write(srv, __FILE__, __LINE__, "s",
4855 + log_error_write(srv, __FILE__, __LINE__, "s",
4856 "sorry, there is no event handler for this system");
4867 for (i = 0; event_handlers[i].name; i++) {
4868 if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
4869 srv->event_handler = event_handlers[i].et;
4875 if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
4876 - log_error_write(srv, __FILE__, __LINE__, "sb",
4877 - "the selected event-handler in unknown or not supported:",
4878 + log_error_write(srv, __FILE__, __LINE__, "sb",
4879 + "the selected event-handler in unknown or not supported:",
4880 srv->srvconf.event_handler );
4886 @@ -1176,19 +1174,19 @@
4888 if (buffer_is_empty(s->ssl_pemfile)) {
4889 /* PEM file is require */
4891 - log_error_write(srv, __FILE__, __LINE__, "s",
4893 + log_error_write(srv, __FILE__, __LINE__, "s",
4894 "ssl.pemfile has to be set");
4900 - log_error_write(srv, __FILE__, __LINE__, "s",
4901 + log_error_write(srv, __FILE__, __LINE__, "s",
4902 "ssl support is missing, recompile with --with-openssl");
4912 --- ../lighttpd-1.4.11/src/configfile.h 2005-08-23 17:36:12.000000000 +0300
4913 +++ lighttpd-1.4.12/src/configfile.h 2006-07-16 00:26:03.000000000 +0300
4918 - array *configs_stack; /* to parse nested block */
4919 + buffer_ptr *configs_stack; /* to parse nested block */
4920 data_config *current; /* current started with { */
4923 --- ../lighttpd-1.4.11/src/configparser.c 2006-02-01 19:51:15.000000000 +0200
4924 +++ lighttpd-1.4.12/src/configparser.c 2006-07-17 22:02:23.000000000 +0300
4926 dc->parent = ctx->current;
4927 array_insert_unique(dc->parent->childs, (data_unset *)dc);
4929 - array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
4930 + buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
4934 static data_config *configparser_pop(config_t *ctx) {
4935 data_config *old = ctx->current;
4936 - ctx->current = (data_config *) array_pop(ctx->configs_stack);
4937 + ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
4941 /* return a copied variable */
4942 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
4943 - if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
4946 - if (NULL != (env = getenv(key->ptr + 4))) {
4948 - ds = data_string_init();
4949 - buffer_append_string(ds->value, env);
4950 - return (data_unset *)ds;
4953 - fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
4964 - fprintf(stderr, "get var %s\n", key->ptr);
4965 + fprintf(stderr, "get var %s\n", key->ptr);
4967 - for (dc = ctx->current; dc; dc = dc->parent) {
4968 + for (dc = ctx->current; dc; dc = dc->parent) {
4970 - fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4971 - array_print(dc->value, 0);
4972 + fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
4973 + array_print(dc->value, 0);
4975 - if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4976 - return du->copy(du);
4978 + if (NULL != (du = array_get_element(dc->value, key->ptr))) {
4979 + return du->copy(du);
4981 - fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
4988 /* op1 is to be eat/return by this function, op1->key is not cared
4989 @@ -124,14 +106,14 @@
4993 -#line 128 "configparser.c"
4994 +#line 110 "configparser.c"
4995 /* Next is all token values, in a form suitable for use by makeheaders.
4996 ** This section will be null unless lemon is run with the -m switch.
5000 ** These constants (all generated automatically by the parser generator)
5001 ** specify the various kinds of tokens (terminals) that the parser
5005 ** Each symbol here is a terminal symbol in the grammar.
5008 ** and nonterminals. "int" is used otherwise.
5009 ** YYNOCODE is a number of type YYCODETYPE which corresponds
5010 ** to no legal terminal or nonterminal number. This
5011 -** number is used to fill in empty slots of the hash
5012 +** number is used to fill in empty slots of the hash
5014 ** YYFALLBACK If defined, this indicates that one or more tokens
5015 ** have fall-back values which should be used if the
5017 ** and nonterminal numbers. "unsigned char" is
5018 ** used if there are fewer than 250 rules and
5019 ** states combined. "int" is used otherwise.
5020 -** configparserTOKENTYPE is the data type used for minor tokens given
5021 +** configparserTOKENTYPE is the data type used for minor tokens given
5022 ** directly to the parser from the tokenizer.
5023 ** YYMINORTYPE is the data type used for all minor tokens.
5024 ** This is typically a union of many types, one of
5026 #define configparserARG_PDECL ,config_t *ctx
5027 #define configparserARG_FETCH config_t *ctx = yypParser->ctx
5028 #define configparserARG_STORE yypParser->ctx = ctx
5029 -#define YYNSTATE 62
5031 +#define YYNSTATE 63
5033 #define YYERRORSYMBOL 26
5034 #define YYERRSYMDT yy95
5035 #define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
5037 /* Next are that tables used to determine what action to take based on the
5038 ** current state and lookahead token. These tables are used to implement
5039 ** functions that take a state number and lookahead value and return an
5043 ** Suppose the action integer is N. Then the action is determined as
5046 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
5047 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
5048 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
5049 -** and that yy_default[S] should be used instead.
5050 +** and that yy_default[S] should be used instead.
5052 ** The formula above is for computing the action when the lookahead is
5053 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
5054 @@ -248,67 +230,69 @@
5055 ** yy_default[] Default action for each state.
5057 static YYACTIONTYPE yy_action[] = {
5058 - /* 0 */ 2, 3, 4, 5, 13, 14, 62, 15, 7, 44,
5059 - /* 10 */ 20, 86, 16, 45, 28, 48, 40, 10, 39, 25,
5060 - /* 20 */ 22, 49, 45, 8, 15, 102, 1, 20, 28, 18,
5061 - /* 30 */ 57, 59, 19, 25, 22, 39, 19, 61, 98, 45,
5062 - /* 40 */ 20, 6, 23, 24, 26, 28, 35, 57, 59, 12,
5063 - /* 50 */ 25, 22, 28, 27, 36, 87, 29, 25, 22, 33,
5064 - /* 60 */ 15, 30, 31, 20, 28, 38, 9, 17, 37, 25,
5065 - /* 70 */ 22, 39, 42, 43, 10, 45, 11, 53, 54, 55,
5066 - /* 80 */ 56, 28, 52, 57, 59, 34, 25, 22, 28, 27,
5067 - /* 90 */ 32, 88, 41, 25, 22, 33, 28, 48, 46, 28,
5068 - /* 100 */ 48, 25, 22, 58, 25, 22, 60, 21, 19, 47,
5069 - /* 110 */ 51, 50, 25, 22, 88, 88, 93,
5070 + /* 0 */ 2, 3, 4, 5, 13, 14, 63, 15, 7, 45,
5071 + /* 10 */ 20, 88, 16, 46, 28, 49, 41, 10, 40, 25,
5072 + /* 20 */ 22, 50, 46, 8, 15, 104, 1, 20, 28, 18,
5073 + /* 30 */ 58, 60, 6, 25, 22, 40, 47, 62, 11, 46,
5074 + /* 40 */ 20, 9, 23, 24, 26, 29, 89, 58, 60, 10,
5075 + /* 50 */ 17, 38, 28, 27, 37, 19, 30, 25, 22, 34,
5076 + /* 60 */ 15, 100, 20, 20, 23, 24, 26, 12, 19, 31,
5077 + /* 70 */ 32, 40, 19, 44, 43, 46, 95, 35, 90, 89,
5078 + /* 80 */ 28, 49, 42, 58, 60, 25, 22, 59, 28, 27,
5079 + /* 90 */ 33, 48, 52, 25, 22, 34, 28, 49, 51, 28,
5080 + /* 100 */ 36, 25, 22, 61, 25, 22, 89, 28, 39, 89,
5081 + /* 110 */ 89, 89, 25, 22, 54, 55, 56, 57, 89, 28,
5082 + /* 120 */ 53, 21, 89, 89, 25, 22, 25, 22,
5084 static YYCODETYPE yy_lookahead[] = {
5085 /* 0 */ 29, 30, 31, 32, 33, 34, 0, 1, 44, 38,
5086 /* 10 */ 4, 15, 41, 16, 35, 36, 45, 46, 12, 40,
5087 /* 20 */ 41, 42, 16, 15, 1, 27, 28, 4, 35, 36,
5088 - /* 30 */ 24, 25, 5, 40, 41, 12, 5, 14, 11, 16,
5089 - /* 40 */ 4, 1, 6, 7, 8, 35, 36, 24, 25, 28,
5090 - /* 50 */ 40, 41, 35, 36, 37, 15, 39, 40, 41, 42,
5091 - /* 60 */ 1, 9, 10, 4, 35, 36, 38, 2, 3, 40,
5092 - /* 70 */ 41, 12, 28, 14, 46, 16, 13, 20, 21, 22,
5093 - /* 80 */ 23, 35, 36, 24, 25, 11, 40, 41, 35, 36,
5094 - /* 90 */ 37, 13, 13, 40, 41, 42, 35, 36, 17, 35,
5095 - /* 100 */ 36, 40, 41, 42, 40, 41, 42, 35, 5, 18,
5096 - /* 110 */ 43, 19, 40, 41, 47, 47, 13,
5097 + /* 30 */ 24, 25, 1, 40, 41, 12, 17, 14, 13, 16,
5098 + /* 40 */ 4, 38, 6, 7, 8, 9, 15, 24, 25, 46,
5099 + /* 50 */ 2, 3, 35, 36, 37, 5, 39, 40, 41, 42,
5100 + /* 60 */ 1, 11, 4, 4, 6, 7, 8, 28, 5, 9,
5101 + /* 70 */ 10, 12, 5, 14, 28, 16, 13, 11, 13, 47,
5102 + /* 80 */ 35, 36, 13, 24, 25, 40, 41, 42, 35, 36,
5103 + /* 90 */ 37, 18, 43, 40, 41, 42, 35, 36, 19, 35,
5104 + /* 100 */ 36, 40, 41, 42, 40, 41, 47, 35, 36, 47,
5105 + /* 110 */ 47, 47, 40, 41, 20, 21, 22, 23, 47, 35,
5106 + /* 120 */ 36, 35, 47, 47, 40, 41, 40, 41,
5108 #define YY_SHIFT_USE_DFLT (-5)
5109 static signed char yy_shift_ofst[] = {
5110 - /* 0 */ -5, 6, -5, -5, -5, 40, -4, 8, -3, -5,
5111 - /* 10 */ 63, -5, 23, -5, -5, -5, 65, 36, 31, 36,
5112 - /* 20 */ -5, -5, -5, -5, -5, -5, 36, 27, -5, 52,
5113 - /* 30 */ -5, 36, -5, 74, 36, 31, -5, 36, 31, 78,
5114 - /* 40 */ 79, -5, 59, -5, -5, 81, 91, 36, 31, 92,
5115 - /* 50 */ 57, 36, 103, -5, -5, -5, -5, 36, -5, 36,
5117 + /* 0 */ -5, 6, -5, -5, -5, 31, -4, 8, -3, -5,
5118 + /* 10 */ 25, -5, 23, -5, -5, -5, 48, 58, 67, 58,
5119 + /* 20 */ -5, -5, -5, -5, -5, -5, 36, 50, -5, -5,
5120 + /* 30 */ 60, -5, 58, -5, 66, 58, 67, -5, 58, 67,
5121 + /* 40 */ 65, 69, -5, 59, -5, -5, 19, 73, 58, 67,
5122 + /* 50 */ 79, 94, 58, 63, -5, -5, -5, -5, 58, -5,
5123 + /* 60 */ 58, -5, -5,
5125 #define YY_REDUCE_USE_DFLT (-37)
5126 static signed char yy_reduce_ofst[] = {
5127 - /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 28, -37,
5128 - /* 10 */ -37, 21, -29, -37, -37, -37, -37, -7, -37, 72,
5129 + /* 0 */ -2, -29, -37, -37, -37, -36, -37, -37, 3, -37,
5130 + /* 10 */ -37, 39, -29, -37, -37, -37, -37, -7, -37, 86,
5131 /* 20 */ -37, -37, -37, -37, -37, -37, 17, -37, -37, -37,
5132 - /* 30 */ -37, 53, -37, -37, 10, -37, -37, 29, -37, -37,
5133 - /* 40 */ -37, 44, -29, -37, -37, -37, -37, -21, -37, -37,
5134 - /* 50 */ 67, 46, -37, -37, -37, -37, -37, 61, -37, 64,
5135 - /* 60 */ -37, -37,
5136 + /* 30 */ -37, -37, 53, -37, -37, 64, -37, -37, 72, -37,
5137 + /* 40 */ -37, -37, 46, -29, -37, -37, -37, -37, -21, -37,
5138 + /* 50 */ -37, 49, 84, -37, -37, -37, -37, -37, 45, -37,
5139 + /* 60 */ 61, -37, -37,
5141 static YYACTIONTYPE yy_default[] = {
5142 - /* 0 */ 64, 101, 63, 65, 66, 101, 67, 101, 101, 90,
5143 - /* 10 */ 101, 64, 101, 68, 69, 70, 101, 101, 71, 101,
5144 - /* 20 */ 73, 74, 76, 77, 78, 79, 101, 84, 75, 101,
5145 - /* 30 */ 80, 82, 81, 101, 101, 85, 83, 101, 72, 101,
5146 - /* 40 */ 101, 64, 101, 89, 91, 101, 101, 101, 98, 101,
5147 - /* 50 */ 101, 101, 101, 94, 95, 96, 97, 101, 99, 101,
5149 + /* 0 */ 65, 103, 64, 66, 67, 103, 68, 103, 103, 92,
5150 + /* 10 */ 103, 65, 103, 69, 70, 71, 103, 103, 72, 103,
5151 + /* 20 */ 74, 75, 77, 78, 79, 80, 103, 86, 76, 81,
5152 + /* 30 */ 103, 82, 84, 83, 103, 103, 87, 85, 103, 73,
5153 + /* 40 */ 103, 103, 65, 103, 91, 93, 103, 103, 103, 100,
5154 + /* 50 */ 103, 103, 103, 103, 96, 97, 98, 99, 103, 101,
5155 + /* 60 */ 103, 102, 94,
5157 #define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
5159 /* The next table maps tokens into fallback tokens. If a construct
5160 ** like the following:
5163 ** %fallback ID X Y Z.
5165 ** appears in the grammer, then ID becomes a fallback token for X, Y,
5166 @@ -359,10 +343,10 @@
5172 ** Turn parser tracing on by giving a stream to which to write the trace
5173 ** and a prompt to preface each trace message. Tracing is turned off
5174 -** by making either argument NULL
5175 +** by making either argument NULL
5181 /* For tracing shifts, the names of all terminals and nonterminals
5182 ** are required. The following table supplies these names */
5183 -static const char *yyTokenName[] = {
5184 +static const char *yyTokenName[] = {
5185 "$", "EOL", "ASSIGN", "APPEND",
5186 "LKEY", "PLUS", "STRING", "INTEGER",
5187 "LPARAN", "RPARAN", "COMMA", "ARRAY_ASSIGN",
5188 @@ -425,27 +409,28 @@
5189 /* 15 */ "value ::= STRING",
5190 /* 16 */ "value ::= INTEGER",
5191 /* 17 */ "value ::= array",
5192 - /* 18 */ "array ::= LPARAN aelements RPARAN",
5193 - /* 19 */ "aelements ::= aelements COMMA aelement",
5194 - /* 20 */ "aelements ::= aelements COMMA",
5195 - /* 21 */ "aelements ::= aelement",
5196 - /* 22 */ "aelement ::= expression",
5197 - /* 23 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5198 - /* 24 */ "eols ::= EOL",
5199 - /* 25 */ "eols ::=",
5200 - /* 26 */ "globalstart ::= GLOBAL",
5201 - /* 27 */ "global ::= globalstart LCURLY metalines RCURLY",
5202 - /* 28 */ "condlines ::= condlines eols ELSE condline",
5203 - /* 29 */ "condlines ::= condline",
5204 - /* 30 */ "condline ::= context LCURLY metalines RCURLY",
5205 - /* 31 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5206 - /* 32 */ "cond ::= EQ",
5207 - /* 33 */ "cond ::= MATCH",
5208 - /* 34 */ "cond ::= NE",
5209 - /* 35 */ "cond ::= NOMATCH",
5210 - /* 36 */ "stringop ::= expression",
5211 - /* 37 */ "include ::= INCLUDE stringop",
5212 - /* 38 */ "include_shell ::= INCLUDE_SHELL stringop",
5213 + /* 18 */ "array ::= LPARAN RPARAN",
5214 + /* 19 */ "array ::= LPARAN aelements RPARAN",
5215 + /* 20 */ "aelements ::= aelements COMMA aelement",
5216 + /* 21 */ "aelements ::= aelements COMMA",
5217 + /* 22 */ "aelements ::= aelement",
5218 + /* 23 */ "aelement ::= expression",
5219 + /* 24 */ "aelement ::= stringop ARRAY_ASSIGN expression",
5220 + /* 25 */ "eols ::= EOL",
5221 + /* 26 */ "eols ::=",
5222 + /* 27 */ "globalstart ::= GLOBAL",
5223 + /* 28 */ "global ::= globalstart LCURLY metalines RCURLY",
5224 + /* 29 */ "condlines ::= condlines eols ELSE condline",
5225 + /* 30 */ "condlines ::= condline",
5226 + /* 31 */ "condline ::= context LCURLY metalines RCURLY",
5227 + /* 32 */ "context ::= DOLLAR SRVVARNAME LBRACKET stringop RBRACKET cond expression",
5228 + /* 33 */ "cond ::= EQ",
5229 + /* 34 */ "cond ::= MATCH",
5230 + /* 35 */ "cond ::= NE",
5231 + /* 36 */ "cond ::= NOMATCH",
5232 + /* 37 */ "stringop ::= expression",
5233 + /* 38 */ "include ::= INCLUDE stringop",
5234 + /* 39 */ "include_shell ::= INCLUDE_SHELL stringop",
5244 ** This function allocates a new parser.
5245 ** The only argument is a pointer to a function which works like
5248 /* Here is inserted the actions which take place when a
5249 ** terminal or non-terminal is destroyed. This can happen
5250 ** when the symbol is popped from the stack during a
5251 - ** reduce or during error processing or when a parser is
5252 + ** reduce or during error processing or when a parser is
5253 ** being destroyed before it is finished parsing.
5255 ** Note: during a reduce, the only symbols destroyed are those
5256 @@ -528,44 +513,44 @@
5260 -#line 160 "./configparser.y"
5261 +#line 143 "./configparser.y"
5262 { buffer_free((yypminor->yy0)); }
5263 -#line 533 "configparser.c"
5264 +#line 518 "configparser.c"
5267 -#line 151 "./configparser.y"
5268 +#line 134 "./configparser.y"
5269 { (yypminor->yy41)->free((yypminor->yy41)); }
5270 -#line 538 "configparser.c"
5271 +#line 523 "configparser.c"
5274 -#line 152 "./configparser.y"
5275 +#line 135 "./configparser.y"
5276 { (yypminor->yy41)->free((yypminor->yy41)); }
5277 -#line 543 "configparser.c"
5278 +#line 528 "configparser.c"
5281 -#line 153 "./configparser.y"
5282 +#line 136 "./configparser.y"
5283 { (yypminor->yy41)->free((yypminor->yy41)); }
5284 -#line 548 "configparser.c"
5285 +#line 533 "configparser.c"
5288 -#line 154 "./configparser.y"
5289 +#line 137 "./configparser.y"
5290 { array_free((yypminor->yy40)); }
5291 -#line 553 "configparser.c"
5292 +#line 538 "configparser.c"
5295 -#line 155 "./configparser.y"
5296 +#line 138 "./configparser.y"
5297 { array_free((yypminor->yy40)); }
5298 -#line 558 "configparser.c"
5299 +#line 543 "configparser.c"
5302 -#line 156 "./configparser.y"
5303 +#line 139 "./configparser.y"
5304 { buffer_free((yypminor->yy43)); }
5305 -#line 563 "configparser.c"
5306 +#line 548 "configparser.c"
5309 -#line 157 "./configparser.y"
5310 +#line 140 "./configparser.y"
5311 { buffer_free((yypminor->yy43)); }
5312 -#line 568 "configparser.c"
5313 +#line 553 "configparser.c"
5315 default: break; /* If no destructor action specified: do nothing */
5323 ** Deallocate and destroy a parser. Destructors are all called for
5324 ** all stack elements before shutting the parser down.
5329 int stateno = pParser->yystack[pParser->yyidx].stateno;
5332 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
5333 i = yy_shift_ofst[stateno];
5334 if( i==YY_SHIFT_USE_DFLT ){
5338 int stateno = pParser->yystack[pParser->yyidx].stateno;
5341 i = yy_reduce_ofst[stateno];
5342 if( i==YY_REDUCE_USE_DFLT ){
5343 return yy_default[stateno];
5353 configparserARG_FETCH;
5354 yymsp = &yypParser->yystack[yypParser->yyidx];
5356 - if( yyTraceFILE && yyruleno>=0
5357 + if( yyTraceFILE && yyruleno>=0
5358 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
5359 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
5360 yyRuleName[yyruleno]);
5362 /* No destructor defined for global */
5365 -#line 134 "./configparser.y"
5366 +#line 116 "./configparser.y"
5367 { yymsp[-1].minor.yy78 = NULL; }
5368 -#line 837 "configparser.c"
5369 +#line 823 "configparser.c"
5370 yy_destructor(1,&yymsp[0].minor);
5373 @@ -847,10 +833,15 @@
5374 yy_destructor(1,&yymsp[0].minor);
5377 -#line 162 "./configparser.y"
5378 +#line 145 "./configparser.y"
5380 buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5381 - if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5382 + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5383 + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5384 + ctx->current->context_ndx,
5385 + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5387 + } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
5388 array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5389 yymsp[0].minor.yy41 = NULL;
5391 @@ -864,16 +855,21 @@
5392 buffer_free(yymsp[-2].minor.yy43);
5393 yymsp[-2].minor.yy43 = NULL;
5395 -#line 867 "configparser.c"
5396 +#line 858 "configparser.c"
5397 yy_destructor(2,&yymsp[-1].minor);
5400 -#line 179 "./configparser.y"
5401 +#line 167 "./configparser.y"
5403 array *vars = ctx->current->value;
5406 - if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5407 + if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5408 + fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5409 + ctx->current->context_ndx,
5410 + ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5412 + } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
5413 /* exists in current block */
5414 du = configparser_merge_data(du, yymsp[0].minor.yy41);
5417 buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5418 array_replace(vars, du);
5420 + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5421 } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
5422 du = configparser_merge_data(du, yymsp[0].minor.yy41);
5424 @@ -892,22 +889,20 @@
5425 buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
5426 array_insert_unique(ctx->current->value, du);
5428 + yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5430 - fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
5431 - ctx->current->context_ndx,
5432 - ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
5434 + buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5435 + array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
5437 buffer_free(yymsp[-2].minor.yy43);
5438 yymsp[-2].minor.yy43 = NULL;
5439 - yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5440 yymsp[0].minor.yy41 = NULL;
5442 -#line 906 "configparser.c"
5443 +#line 901 "configparser.c"
5444 yy_destructor(3,&yymsp[-1].minor);
5447 -#line 214 "./configparser.y"
5448 +#line 206 "./configparser.y"
5450 if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
5451 yygotominor.yy43 = buffer_init_string("var.");
5452 @@ -919,10 +914,10 @@
5453 yymsp[0].minor.yy0 = NULL;
5456 -#line 922 "configparser.c"
5457 +#line 917 "configparser.c"
5460 -#line 226 "./configparser.y"
5461 +#line 218 "./configparser.y"
5463 yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
5464 if (NULL == yygotominor.yy41) {
5465 @@ -932,21 +927,38 @@
5466 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5467 yymsp[0].minor.yy41 = NULL;
5469 -#line 935 "configparser.c"
5470 +#line 930 "configparser.c"
5471 yy_destructor(5,&yymsp[-1].minor);
5474 -#line 236 "./configparser.y"
5475 +#line 228 "./configparser.y"
5477 yygotominor.yy41 = yymsp[0].minor.yy41;
5478 yymsp[0].minor.yy41 = NULL;
5480 -#line 944 "configparser.c"
5481 +#line 939 "configparser.c"
5484 -#line 241 "./configparser.y"
5485 +#line 233 "./configparser.y"
5487 - yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43);
5488 + if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
5491 + if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
5493 + ds = data_string_init();
5494 + buffer_append_string(ds->value, env);
5495 + yygotominor.yy41 = (data_unset *)ds;
5498 + yygotominor.yy41 = NULL;
5499 + fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
5502 + } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
5503 + fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
5506 if (!yygotominor.yy41) {
5507 /* make a dummy so it won't crash */
5508 yygotominor.yy41 = (data_unset *)data_string_init();
5509 @@ -954,50 +966,59 @@
5510 buffer_free(yymsp[0].minor.yy43);
5511 yymsp[0].minor.yy43 = NULL;
5513 -#line 957 "configparser.c"
5514 +#line 969 "configparser.c"
5517 -#line 251 "./configparser.y"
5518 +#line 260 "./configparser.y"
5520 yygotominor.yy41 = (data_unset *)data_string_init();
5521 buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
5522 buffer_free(yymsp[0].minor.yy0);
5523 yymsp[0].minor.yy0 = NULL;
5525 -#line 967 "configparser.c"
5526 +#line 979 "configparser.c"
5529 -#line 258 "./configparser.y"
5530 +#line 267 "./configparser.y"
5532 yygotominor.yy41 = (data_unset *)data_integer_init();
5533 ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
5534 buffer_free(yymsp[0].minor.yy0);
5535 yymsp[0].minor.yy0 = NULL;
5537 -#line 977 "configparser.c"
5538 +#line 989 "configparser.c"
5541 -#line 264 "./configparser.y"
5542 +#line 273 "./configparser.y"
5544 yygotominor.yy41 = (data_unset *)data_array_init();
5545 array_free(((data_array *)(yygotominor.yy41))->value);
5546 ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
5547 yymsp[0].minor.yy40 = NULL;
5549 -#line 987 "configparser.c"
5550 +#line 999 "configparser.c"
5553 -#line 270 "./configparser.y"
5554 +#line 279 "./configparser.y"
5556 + yygotominor.yy40 = array_init();
5558 +#line 1006 "configparser.c"
5559 + yy_destructor(8,&yymsp[-1].minor);
5560 + yy_destructor(9,&yymsp[0].minor);
5563 +#line 282 "./configparser.y"
5565 yygotominor.yy40 = yymsp[-1].minor.yy40;
5566 yymsp[-1].minor.yy40 = NULL;
5568 -#line 995 "configparser.c"
5569 +#line 1016 "configparser.c"
5570 yy_destructor(8,&yymsp[-2].minor);
5571 yy_destructor(9,&yymsp[0].minor);
5574 -#line 275 "./configparser.y"
5576 +#line 287 "./configparser.y"
5578 if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
5579 NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
5580 @@ -1014,37 +1035,37 @@
5581 yygotominor.yy40 = yymsp[-2].minor.yy40;
5582 yymsp[-2].minor.yy40 = NULL;
5584 -#line 1017 "configparser.c"
5585 +#line 1038 "configparser.c"
5586 yy_destructor(10,&yymsp[-1].minor);
5589 -#line 292 "./configparser.y"
5591 +#line 304 "./configparser.y"
5593 yygotominor.yy40 = yymsp[-1].minor.yy40;
5594 yymsp[-1].minor.yy40 = NULL;
5596 -#line 1026 "configparser.c"
5597 +#line 1047 "configparser.c"
5598 yy_destructor(10,&yymsp[0].minor);
5601 -#line 297 "./configparser.y"
5603 +#line 309 "./configparser.y"
5605 yygotominor.yy40 = array_init();
5606 array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
5607 yymsp[0].minor.yy41 = NULL;
5609 -#line 1036 "configparser.c"
5610 +#line 1057 "configparser.c"
5613 -#line 303 "./configparser.y"
5615 +#line 315 "./configparser.y"
5617 yygotominor.yy41 = yymsp[0].minor.yy41;
5618 yymsp[0].minor.yy41 = NULL;
5620 -#line 1044 "configparser.c"
5621 +#line 1065 "configparser.c"
5624 -#line 307 "./configparser.y"
5626 +#line 319 "./configparser.y"
5628 buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
5629 buffer_free(yymsp[-2].minor.yy43);
5630 @@ -1053,27 +1074,27 @@
5631 yygotominor.yy41 = yymsp[0].minor.yy41;
5632 yymsp[0].minor.yy41 = NULL;
5634 -#line 1056 "configparser.c"
5635 +#line 1077 "configparser.c"
5636 yy_destructor(11,&yymsp[-1].minor);
5639 - yy_destructor(1,&yymsp[0].minor);
5642 + yy_destructor(1,&yymsp[0].minor);
5645 -#line 319 "./configparser.y"
5648 +#line 331 "./configparser.y"
5651 dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
5653 configparser_push(ctx, dc, 0);
5655 -#line 1072 "configparser.c"
5656 +#line 1093 "configparser.c"
5657 yy_destructor(12,&yymsp[0].minor);
5660 -#line 326 "./configparser.y"
5662 +#line 338 "./configparser.y"
5666 @@ -1082,16 +1103,16 @@
5668 assert(cur && ctx->current);
5670 - yygotominor.yy0 = cur;
5671 + yygotominor.yy78 = cur;
5673 -#line 1087 "configparser.c"
5674 +#line 1108 "configparser.c"
5675 /* No destructor defined for globalstart */
5676 yy_destructor(13,&yymsp[-2].minor);
5677 /* No destructor defined for metalines */
5678 yy_destructor(14,&yymsp[0].minor);
5681 -#line 337 "./configparser.y"
5683 +#line 349 "./configparser.y"
5685 assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
5686 yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
5687 @@ -1100,20 +1121,20 @@
5688 yymsp[-3].minor.yy78 = NULL;
5689 yymsp[0].minor.yy78 = NULL;
5691 -#line 1103 "configparser.c"
5692 +#line 1124 "configparser.c"
5693 /* No destructor defined for eols */
5694 yy_destructor(15,&yymsp[-1].minor);
5697 -#line 346 "./configparser.y"
5699 +#line 358 "./configparser.y"
5701 yygotominor.yy78 = yymsp[0].minor.yy78;
5702 yymsp[0].minor.yy78 = NULL;
5704 -#line 1113 "configparser.c"
5705 +#line 1134 "configparser.c"
5708 -#line 351 "./configparser.y"
5710 +#line 363 "./configparser.y"
5714 @@ -1124,14 +1145,14 @@
5716 yygotominor.yy78 = cur;
5718 -#line 1127 "configparser.c"
5719 +#line 1148 "configparser.c"
5720 /* No destructor defined for context */
5721 yy_destructor(13,&yymsp[-2].minor);
5722 /* No destructor defined for metalines */
5723 yy_destructor(14,&yymsp[0].minor);
5726 -#line 362 "./configparser.y"
5728 +#line 374 "./configparser.y"
5731 buffer *b, *rvalue, *op;
5732 @@ -1266,45 +1287,45 @@
5733 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5734 yymsp[0].minor.yy41 = NULL;
5736 -#line 1269 "configparser.c"
5737 +#line 1290 "configparser.c"
5738 yy_destructor(16,&yymsp[-6].minor);
5739 yy_destructor(18,&yymsp[-4].minor);
5740 yy_destructor(19,&yymsp[-2].minor);
5743 -#line 496 "./configparser.y"
5745 +#line 508 "./configparser.y"
5747 yygotominor.yy27 = CONFIG_COND_EQ;
5749 -#line 1279 "configparser.c"
5750 +#line 1300 "configparser.c"
5751 yy_destructor(20,&yymsp[0].minor);
5754 -#line 499 "./configparser.y"
5756 +#line 511 "./configparser.y"
5758 yygotominor.yy27 = CONFIG_COND_MATCH;
5760 -#line 1287 "configparser.c"
5761 +#line 1308 "configparser.c"
5762 yy_destructor(21,&yymsp[0].minor);
5765 -#line 502 "./configparser.y"
5767 +#line 514 "./configparser.y"
5769 yygotominor.yy27 = CONFIG_COND_NE;
5771 -#line 1295 "configparser.c"
5772 +#line 1316 "configparser.c"
5773 yy_destructor(22,&yymsp[0].minor);
5776 -#line 505 "./configparser.y"
5778 +#line 517 "./configparser.y"
5780 yygotominor.yy27 = CONFIG_COND_NOMATCH;
5782 -#line 1303 "configparser.c"
5783 +#line 1324 "configparser.c"
5784 yy_destructor(23,&yymsp[0].minor);
5787 -#line 509 "./configparser.y"
5789 +#line 521 "./configparser.y"
5791 yygotominor.yy43 = NULL;
5793 @@ -1321,10 +1342,10 @@
5794 yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
5795 yymsp[0].minor.yy41 = NULL;
5797 -#line 1324 "configparser.c"
5798 +#line 1345 "configparser.c"
5801 -#line 526 "./configparser.y"
5803 +#line 538 "./configparser.y"
5806 if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5807 @@ -1334,11 +1355,11 @@
5808 yymsp[0].minor.yy43 = NULL;
5811 -#line 1337 "configparser.c"
5812 +#line 1358 "configparser.c"
5813 yy_destructor(24,&yymsp[-1].minor);
5816 -#line 536 "./configparser.y"
5818 +#line 548 "./configparser.y"
5821 if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
5822 @@ -1348,7 +1369,7 @@
5823 yymsp[0].minor.yy43 = NULL;
5826 -#line 1351 "configparser.c"
5827 +#line 1372 "configparser.c"
5828 yy_destructor(25,&yymsp[-1].minor);
5831 @@ -1378,11 +1399,11 @@
5832 while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
5833 /* Here code is inserted which will be executed whenever the
5835 -#line 125 "./configparser.y"
5836 +#line 107 "./configparser.y"
5840 -#line 1385 "configparser.c"
5841 +#line 1406 "configparser.c"
5842 configparserARG_STORE; /* Suppress warning about unused %extra_argument variable */
5845 @@ -1489,7 +1510,7 @@
5846 #ifdef YYERRORSYMBOL
5847 /* A syntax error has occurred.
5848 ** The response to an error depends upon whether or not the
5849 - ** grammar defines an error token "ERROR".
5850 + ** grammar defines an error token "ERROR".
5852 ** This is what we do if the grammar does define ERROR:
5854 --- ../lighttpd-1.4.11/src/configparser.y 2006-01-26 18:46:25.000000000 +0200
5855 +++ lighttpd-1.4.12/src/configparser.y 2006-07-16 00:26:04.000000000 +0300
5857 dc->parent = ctx->current;
5858 array_insert_unique(dc->parent->childs, (data_unset *)dc);
5860 - array_insert_unique(ctx->configs_stack, (data_unset *)ctx->current);
5861 + buffer_ptr_append(ctx->configs_stack, (void *)ctx->current);
5865 static data_config *configparser_pop(config_t *ctx) {
5866 data_config *old = ctx->current;
5867 - ctx->current = (data_config *) array_pop(ctx->configs_stack);
5868 + ctx->current = (data_config *) buffer_ptr_pop(ctx->configs_stack);
5872 /* return a copied variable */
5873 static data_unset *configparser_get_variable(config_t *ctx, const buffer *key) {
5874 - if (strncmp(key->ptr, "env.", sizeof("env.") - 1) == 0) {
5877 - if (NULL != (env = getenv(key->ptr + 4))) {
5879 - ds = data_string_init();
5880 - buffer_append_string(ds->value, env);
5881 - return (data_unset *)ds;
5884 - fprintf(stderr, "Undefined env variable: %s\n", key->ptr + 4);
5895 - fprintf(stderr, "get var %s\n", key->ptr);
5896 + fprintf(stderr, "get var %s\n", key->ptr);
5898 - for (dc = ctx->current; dc; dc = dc->parent) {
5899 + for (dc = ctx->current; dc; dc = dc->parent) {
5901 - fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5902 - array_print(dc->value, 0);
5903 + fprintf(stderr, "get var on block: %s\n", dc->key->ptr);
5904 + array_print(dc->value, 0);
5906 - if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5907 - return du->copy(du);
5909 + if (NULL != (du = array_get_element(dc->value, key->ptr))) {
5910 + return du->copy(du);
5912 - fprintf(stderr, "Undefined config variable: %s\n", key->ptr);
5919 /* op1 is to be eat/return by this function, op1->key is not cared
5921 %type aelement {data_unset *}
5922 %type condline {data_config *}
5923 %type condlines {data_config *}
5924 +%type global {data_config *}
5925 %type aelements {array *}
5926 %type array {array *}
5927 %type key {buffer *}
5928 @@ -161,7 +144,12 @@
5930 varline ::= key(A) ASSIGN expression(B). {
5931 buffer_copy_string_buffer(B->key, A);
5932 - if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5933 + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5934 + fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
5935 + ctx->current->context_ndx,
5936 + ctx->current->key->ptr, A->ptr);
5938 + } else if (NULL == array_get_element(ctx->current->value, B->key->ptr)) {
5939 array_insert_unique(ctx->current->value, B);
5942 @@ -180,7 +168,12 @@
5943 array *vars = ctx->current->value;
5946 - if (NULL != (du = array_get_element(vars, A->ptr))) {
5947 + if (strncmp(A->ptr, "env.", sizeof("env.") - 1) == 0) {
5948 + fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
5949 + ctx->current->context_ndx,
5950 + ctx->current->key->ptr, A->ptr);
5952 + } else if (NULL != (du = array_get_element(vars, A->ptr))) {
5953 /* exists in current block */
5954 du = configparser_merge_data(du, B);
5957 buffer_copy_string_buffer(du->key, A);
5958 array_replace(vars, du);
5961 } else if (NULL != (du = configparser_get_variable(ctx, A))) {
5962 du = configparser_merge_data(du, B);
5964 @@ -199,15 +193,13 @@
5965 buffer_copy_string_buffer(du->key, A);
5966 array_insert_unique(ctx->current->value, du);
5970 - fprintf(stderr, "Undefined config variable in conditional %d %s: %s\n",
5971 - ctx->current->context_ndx,
5972 - ctx->current->key->ptr, A->ptr);
5974 + buffer_copy_string_buffer(B->key, A);
5975 + array_insert_unique(ctx->current->value, B);
5983 @@ -239,7 +231,24 @@
5986 value(A) ::= key(B). {
5987 - A = configparser_get_variable(ctx, B);
5988 + if (strncmp(B->ptr, "env.", sizeof("env.") - 1) == 0) {
5991 + if (NULL != (env = getenv(B->ptr + 4))) {
5993 + ds = data_string_init();
5994 + buffer_append_string(ds->value, env);
5995 + A = (data_unset *)ds;
5999 + fprintf(stderr, "Undefined env variable: %s\n", B->ptr + 4);
6002 + } else if (NULL == (A = configparser_get_variable(ctx, B))) {
6003 + fprintf(stderr, "Undefined config variable: %s\n", B->ptr);
6007 /* make a dummy so it won't crash */
6008 A = (data_unset *)data_string_init();
6010 ((data_array *)(A))->value = B;
6013 +array(A) ::= LPARAN RPARAN. {
6016 array(A) ::= LPARAN aelements(B) RPARAN. {
6019 --- ../lighttpd-1.4.11/src/connections-glue.c 2005-09-12 10:04:23.000000000 +0300
6020 +++ lighttpd-1.4.12/src/connections-glue.c 2006-07-16 00:26:03.000000000 +0300
6022 case CON_STATE_REQUEST_END: return "req-end";
6023 case CON_STATE_RESPONSE_START: return "resp-start";
6024 case CON_STATE_RESPONSE_END: return "resp-end";
6025 - default: return "(unknown)";
6026 + default: return "(unknown)";
6031 case CON_STATE_REQUEST_END: return "Q";
6032 case CON_STATE_RESPONSE_START: return "s";
6033 case CON_STATE_RESPONSE_END: return "S";
6034 - default: return "x";
6035 + default: return "x";
6039 int connection_set_state(server *srv, connection *con, connection_state_t state) {
6049 --- ../lighttpd-1.4.11/src/connections.c 2006-03-05 22:14:53.000000000 +0200
6050 +++ lighttpd-1.4.12/src/connections.c 2006-07-18 13:03:40.000000000 +0300
6055 -#include <unistd.h>
6060 #include "inet_ntop_cache.h"
6063 -# include <openssl/ssl.h>
6064 -# include <openssl/err.h>
6065 +# include <openssl/ssl.h>
6066 +# include <openssl/err.h>
6069 #ifdef HAVE_SYS_FILIO_H
6073 #include "sys-socket.h"
6074 +#include "sys-files.h"
6081 static connection *connections_get_new_connection(server *srv) {
6082 connections *conns = srv->conns;
6086 if (conns->size == 0) {
6090 } else if (conns->size == conns->used) {
6092 conns->ptr = realloc(conns->ptr, sizeof(*conns->ptr) * conns->size);
6095 for (i = conns->used; i < conns->size; i++) {
6096 conns->ptr[i] = connection_init(srv);
6100 connection_reset(srv, conns->ptr[conns->used]);
6102 - fprintf(stderr, "%s.%d: add: ", __FILE__, __LINE__);
6103 - for (i = 0; i < conns->used + 1; i++) {
6104 - fprintf(stderr, "%d ", conns->ptr[i]->fd);
6106 - fprintf(stderr, "\n");
6110 conns->ptr[conns->used]->ndx = conns->used;
6111 return conns->ptr[conns->used++];
6113 @@ -77,263 +70,134 @@
6115 connections *conns = srv->conns;
6119 if (con == NULL) return -1;
6122 if (-1 == con->ndx) return -1;
6128 /* not last element */
6131 if (i != conns->used - 1) {
6132 temp = conns->ptr[i];
6133 conns->ptr[i] = conns->ptr[conns->used - 1];
6134 conns->ptr[conns->used - 1] = temp;
6137 conns->ptr[i]->ndx = i;
6138 conns->ptr[conns->used - 1]->ndx = -1;
6147 - fprintf(stderr, "%s.%d: del: (%d)", __FILE__, __LINE__, conns->used);
6148 - for (i = 0; i < conns->used; i++) {
6149 - fprintf(stderr, "%d ", conns->ptr[i]->fd);
6151 - fprintf(stderr, "\n");
6157 int connection_close(server *srv, connection *con) {
6159 server_socket *srv_sock = con->srv_socket;
6164 if (srv_sock->is_ssl) {
6165 - if (con->ssl) SSL_free(con->ssl);
6167 + if (con->sock->ssl) SSL_free(con->sock->ssl);
6168 + con->sock->ssl = NULL;
6172 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
6173 - fdevent_unregister(srv->ev, con->fd);
6175 - if (closesocket(con->fd)) {
6176 - log_error_write(srv, __FILE__, __LINE__, "sds",
6177 - "(warning) close:", con->fd, strerror(errno));
6180 - if (close(con->fd)) {
6182 + fdevent_event_del(srv->ev, con->sock);
6183 + fdevent_unregister(srv->ev, con->sock);
6185 + if (closesocket(con->sock->fd)) {
6186 log_error_write(srv, __FILE__, __LINE__, "sds",
6187 - "(warning) close:", con->fd, strerror(errno));
6188 + "(warning) close:", con->sock->fd, strerror(errno));
6195 - log_error_write(srv, __FILE__, __LINE__, "sd",
6196 - "closed()", con->fd);
6200 connection_del(srv, con);
6201 connection_set_state(srv, con, CON_STATE_CONNECT);
6208 static void dump_packet(const unsigned char *data, size_t len) {
6212 if (len == 0) return;
6215 for (i = 0; i < len; i++) {
6216 if (i % 16 == 0) fprintf(stderr, " ");
6219 fprintf(stderr, "%02x ", data[i]);
6222 if ((i + 1) % 16 == 0) {
6223 fprintf(stderr, " ");
6224 for (j = 0; j <= i % 16; j++) {
6228 if (i-15+j >= len) break;
6234 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6238 fprintf(stderr, "\n");
6243 if (len % 16 != 0) {
6244 for (j = i % 16; j < 16; j++) {
6245 fprintf(stderr, " ");
6249 fprintf(stderr, " ");
6250 for (j = i & ~0xf; j < len; j++) {
6255 fprintf(stderr, "%c", c > 32 && c < 128 ? c : '.');
6257 fprintf(stderr, "\n");
6262 -static int connection_handle_read(server *srv, connection *con) {
6267 - server_socket *srv_sock = con->srv_socket;
6270 - b = chunkqueue_get_append_buffer(con->read_queue);
6271 - buffer_prepare_copy(b, 4096);
6274 - if (srv_sock->is_ssl) {
6275 - len = SSL_read(con->ssl, b->ptr, b->size - 1);
6277 - if (ioctl(con->fd, FIONREAD, &toread)) {
6278 - log_error_write(srv, __FILE__, __LINE__, "sd",
6279 - "unexpected end-of-file:",
6283 - buffer_prepare_copy(b, toread);
6284 +static network_status_t connection_handle_read(server *srv, connection *con) {
6285 + off_t oldlen, newlen;
6287 - len = read(con->fd, b->ptr, b->size - 1);
6289 -#elif defined(__WIN32)
6290 - len = recv(con->fd, b->ptr, b->size - 1, 0);
6292 - if (ioctl(con->fd, FIONREAD, &toread)) {
6293 - log_error_write(srv, __FILE__, __LINE__, "sd",
6294 - "unexpected end-of-file:",
6298 - buffer_prepare_copy(b, toread);
6299 + oldlen = chunkqueue_length(con->read_queue);
6301 - len = read(con->fd, b->ptr, b->size - 1);
6305 + switch(network_read_chunkqueue(srv, con, con->read_queue)) {
6306 + case NETWORK_STATUS_SUCCESS:
6308 + case NETWORK_STATUS_WAIT_FOR_EVENT:
6309 + con->is_readable = 0;
6310 + return NETWORK_STATUS_WAIT_FOR_EVENT;
6311 + case NETWORK_STATUS_INTERRUPTED:
6312 + con->is_readable = 1;
6313 + return NETWORK_STATUS_WAIT_FOR_EVENT;
6314 + case NETWORK_STATUS_CONNECTION_CLOSE:
6316 + con->is_readable = 0;
6317 + return NETWORK_STATUS_CONNECTION_CLOSE;
6318 + case NETWORK_STATUS_FATAL_ERROR:
6319 con->is_readable = 0;
6322 - if (srv_sock->is_ssl) {
6325 - switch ((r = SSL_get_error(con->ssl, len))) {
6326 - case SSL_ERROR_WANT_READ:
6328 - case SSL_ERROR_SYSCALL:
6330 - * man SSL_get_error()
6332 - * SSL_ERROR_SYSCALL
6333 - * Some I/O error occurred. The OpenSSL error queue may contain more
6334 - * information on the error. If the error queue is empty (i.e.
6335 - * ERR_get_error() returns 0), ret can be used to find out more about
6336 - * the error: If ret == 0, an EOF was observed that violates the
6337 - * protocol. If ret == -1, the underlying BIO reported an I/O error
6338 - * (for socket I/O on Unix systems, consult errno for details).
6341 - while((ssl_err = ERR_get_error())) {
6342 - /* get all errors from the error-queue */
6343 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
6344 - r, ERR_error_string(ssl_err, NULL));
6349 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
6356 - case SSL_ERROR_ZERO_RETURN:
6357 - /* clean shutdown on the remote side */
6360 - /* FIXME: later */
6363 - /* fall thourgh */
6365 - while((ssl_err = ERR_get_error())) {
6366 - /* get all errors from the error-queue */
6367 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
6368 - r, ERR_error_string(ssl_err, NULL));
6373 - if (errno == EAGAIN) return 0;
6374 - if (errno == EINTR) {
6375 - /* we have been interrupted before we could read */
6376 - con->is_readable = 1;
6380 - if (errno != ECONNRESET) {
6381 - /* expected for keep-alive */
6382 - log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6386 - if (errno == EAGAIN) return 0;
6387 - if (errno == EINTR) {
6388 - /* we have been interrupted before we could read */
6389 - con->is_readable = 1;
6393 - if (errno != ECONNRESET) {
6394 - /* expected for keep-alive */
6395 - log_error_write(srv, __FILE__, __LINE__, "ssd", "connection closed - read failed: ", strerror(errno), errno);
6398 connection_set_state(srv, con, CON_STATE_ERROR);
6401 - } else if (len == 0) {
6402 - con->is_readable = 0;
6403 - /* the other end close the connection -> KEEP-ALIVE */
6404 + return NETWORK_STATUS_FATAL_ERROR;
6411 + newlen = chunkqueue_length(con->read_queue);
6414 - } else if ((size_t)len < b->size - 1) {
6415 - /* we got less then expected, wait for the next fd-event */
6417 - con->is_readable = 0;
6421 - b->ptr[b->used++] = '\0';
6423 - con->bytes_read += len;
6425 - dump_packet(b->ptr, len);
6429 + con->bytes_read += (newlen - oldlen);
6431 + return NETWORK_STATUS_SUCCESS;
6434 static int connection_handle_write_prepare(server *srv, connection *con) {
6436 case HTTP_METHOD_GET:
6437 case HTTP_METHOD_POST:
6438 case HTTP_METHOD_HEAD:
6440 case HTTP_METHOD_PUT:
6441 case HTTP_METHOD_MKCOL:
6442 case HTTP_METHOD_DELETE:
6443 @@ -350,12 +215,14 @@
6444 case HTTP_METHOD_MOVE:
6445 case HTTP_METHOD_PROPFIND:
6446 case HTTP_METHOD_PROPPATCH:
6447 + case HTTP_METHOD_LOCK:
6448 + case HTTP_METHOD_UNLOCK:
6450 case HTTP_METHOD_OPTIONS:
6452 * 400 is coming from the request-parser BEFORE uri.path is set
6453 - * 403 is from the response handler when noone else catched it
6455 + * 403 is from the response handler when noone else catched it
6458 if (con->uri.path->used &&
6459 con->uri.path->ptr[0] != '*') {
6460 @@ -381,55 +248,60 @@
6466 if (con->http_status == 0) {
6467 con->http_status = 403;
6471 switch(con->http_status) {
6472 case 400: /* class: header + custom body */
6490 if (con->mode != DIRECT) break;
6493 con->file_finished = 0;
6496 buffer_reset(con->physical.path);
6499 /* try to send static errorfile */
6500 if (!buffer_is_empty(con->conf.errorfile_prefix)) {
6501 stat_cache_entry *sce = NULL;
6504 buffer_copy_string_buffer(con->physical.path, con->conf.errorfile_prefix);
6505 buffer_append_string(con->physical.path, get_http_status_body_name(con->http_status));
6508 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
6509 con->file_finished = 1;
6512 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
6513 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
6517 - if (!con->file_finished) {
6519 + if (!con->file_finished) {
6523 buffer_reset(con->physical.path);
6526 con->file_finished = 1;
6527 b = chunkqueue_get_append_buffer(con->write_queue);
6530 /* build default error-page */
6531 - buffer_copy_string(b,
6532 + buffer_copy_string(b,
6533 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
6534 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
6535 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
6537 buffer_append_long(b, con->http_status);
6538 buffer_append_string(b, " - ");
6539 buffer_append_string(b, get_http_status_name(con->http_status));
6542 buffer_append_string(b,
6545 @@ -448,12 +320,12 @@
6546 buffer_append_long(b, con->http_status);
6547 buffer_append_string(b, " - ");
6548 buffer_append_string(b, get_http_status_name(con->http_status));
6550 - buffer_append_string(b,"</h1>\n"
6552 + buffer_append_string(b,"</h1>\n"
6558 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
6561 @@ -463,10 +335,10 @@
6567 case 206: /* write_queue is already prepared */
6568 con->file_finished = 1;
6572 case 205: /* class: header only */
6574 @@ -474,19 +346,19 @@
6575 /* disable chunked encoding again as we have no body */
6576 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED;
6577 chunkqueue_reset(con->write_queue);
6580 con->file_finished = 1;
6586 if (con->file_finished) {
6587 - /* we have all the content and chunked encoding is not used, set a content-length */
6589 - if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6590 + /* we have all the content and chunked encoding is not used, set a content-length */
6592 + if ((!(con->parsed_response & HTTP_CONTENT_LENGTH)) &&
6593 (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) {
6594 buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->write_queue));
6597 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf));
6600 @@ -495,77 +367,79 @@
6601 ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0)) {
6602 con->keep_alive = 0;
6606 if (0 == (con->parsed_response & HTTP_CONNECTION)) {
6607 /* (f)cgi did'nt send Connection: header
6612 if (((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0) &&
6613 (con->parsed_response & HTTP_CONTENT_LENGTH) == 0) {
6614 /* without content_length, no keep-alive */
6617 con->keep_alive = 0;
6620 /* a subrequest disable keep-alive although the client wanted it */
6621 if (con->keep_alive && !con->response.keep_alive) {
6622 con->keep_alive = 0;
6625 /* FIXME: we have to drop the Connection: Header from the subrequest */
6631 if (con->request.http_method == HTTP_METHOD_HEAD) {
6632 chunkqueue_reset(con->write_queue);
6635 http_response_write_header(srv, con);
6641 static int connection_handle_write(server *srv, connection *con) {
6642 switch(network_write_chunkqueue(srv, con, con->write_queue)) {
6644 + case NETWORK_STATUS_SUCCESS:
6645 if (con->file_finished) {
6646 connection_set_state(srv, con, CON_STATE_RESPONSE_END);
6647 joblist_append(srv, con);
6650 - case -1: /* error on our side */
6651 + case NETWORK_STATUS_FATAL_ERROR: /* error on our side */
6652 log_error_write(srv, __FILE__, __LINE__, "sd",
6653 - "connection closed: write failed on fd", con->fd);
6654 + "connection closed: write failed on fd", con->sock->fd);
6655 connection_set_state(srv, con, CON_STATE_ERROR);
6656 joblist_append(srv, con);
6658 - case -2: /* remote close */
6659 + case NETWORK_STATUS_CONNECTION_CLOSE: /* remote close */
6660 connection_set_state(srv, con, CON_STATE_ERROR);
6661 joblist_append(srv, con);
6664 + case NETWORK_STATUS_WAIT_FOR_EVENT:
6665 con->is_writable = 0;
6668 /* not finished yet -> WRITE */
6670 + case NETWORK_STATUS_INTERRUPTED:
6671 + con->is_writable = 1;
6673 + case NETWORK_STATUS_UNSET:
6683 connection *connection_init(server *srv) {
6689 con = calloc(1, sizeof(*con));
6693 + con->sock = iosocket_init();
6695 - con->fde_ndx = -1;
6696 con->bytes_written = 0;
6697 con->bytes_read = 0;
6698 con->bytes_header = 0;
6699 @@ -573,32 +447,32 @@
6702 con->x = buffer_init();
6706 CLEAN(request.request_line);
6707 CLEAN(request.request);
6708 CLEAN(request.pathinfo);
6711 CLEAN(request.orig_uri);
6715 CLEAN(uri.authority);
6717 CLEAN(uri.path_raw);
6721 CLEAN(physical.doc_root);
6722 CLEAN(physical.path);
6723 CLEAN(physical.basedir);
6724 CLEAN(physical.rel_path);
6725 CLEAN(physical.etag);
6726 CLEAN(parse_request);
6731 CLEAN(error_handler);
6732 CLEAN(dst_addr_buf);
6736 con->write_queue = chunkqueue_init();
6737 con->read_queue = chunkqueue_init();
6738 @@ -608,26 +482,27 @@
6739 con->request.headers = array_init();
6740 con->response.headers = array_init();
6741 con->environment = array_init();
6744 /* init plugin specific connection structures */
6747 con->plugin_ctx = calloc(1, (srv->plugins.used + 1) * sizeof(void *));
6750 con->cond_cache = calloc(srv->config_context->used, sizeof(cond_cache_t));
6751 config_setup_connection(srv, con);
6757 void connections_free(server *srv) {
6758 connections *conns = srv->conns;
6763 for (i = 0; i < conns->size; i++) {
6764 connection *con = conns->ptr[i];
6767 connection_reset(srv, con);
6769 + iosocket_free(con->sock);
6771 chunkqueue_free(con->write_queue);
6772 chunkqueue_free(con->read_queue);
6773 chunkqueue_free(con->request_content_queue);
6774 @@ -637,27 +512,27 @@
6777 buffer_free(con->x);
6781 CLEAN(request.request_line);
6782 CLEAN(request.request);
6783 CLEAN(request.pathinfo);
6786 CLEAN(request.orig_uri);
6790 CLEAN(uri.authority);
6792 CLEAN(uri.path_raw);
6796 CLEAN(physical.doc_root);
6797 CLEAN(physical.path);
6798 CLEAN(physical.basedir);
6799 CLEAN(physical.etag);
6800 CLEAN(physical.rel_path);
6801 CLEAN(parse_request);
6806 CLEAN(error_handler);
6807 @@ -665,97 +540,97 @@
6809 free(con->plugin_ctx);
6810 free(con->cond_cache);
6821 int connection_reset(server *srv, connection *con) {
6825 plugins_call_connection_reset(srv, con);
6828 con->is_readable = 1;
6829 con->is_writable = 1;
6830 con->http_status = 0;
6831 con->file_finished = 0;
6832 con->file_started = 0;
6833 con->got_response = 0;
6836 con->parsed_response = 0;
6839 con->bytes_written = 0;
6840 con->bytes_written_cur_second = 0;
6841 con->bytes_read = 0;
6842 con->bytes_header = 0;
6843 con->loops_per_request = 0;
6846 con->request.http_method = HTTP_METHOD_UNSET;
6847 con->request.http_version = HTTP_VERSION_UNSET;
6850 con->request.http_if_modified_since = NULL;
6851 con->request.http_if_none_match = NULL;
6854 con->response.keep_alive = 0;
6855 con->response.content_length = -1;
6856 con->response.transfer_encoding = 0;
6863 if (con->x) buffer_reset(con->x);
6867 CLEAN(request.request_line);
6868 CLEAN(request.pathinfo);
6869 CLEAN(request.request);
6872 CLEAN(request.orig_uri);
6876 CLEAN(uri.authority);
6878 CLEAN(uri.path_raw);
6882 CLEAN(physical.doc_root);
6883 CLEAN(physical.path);
6884 CLEAN(physical.basedir);
6885 CLEAN(physical.rel_path);
6886 CLEAN(physical.etag);
6889 CLEAN(parse_request);
6894 CLEAN(error_handler);
6900 - if (con->x) con->x->used = 0;
6902 + if (con->x) con->x->used = 0;
6908 con->request.x = NULL;
6913 CLEAN(http_content_type);
6915 con->request.content_length = 0;
6918 array_reset(con->request.headers);
6919 array_reset(con->response.headers);
6920 array_reset(con->environment);
6923 chunkqueue_reset(con->write_queue);
6924 chunkqueue_reset(con->request_content_queue);
6926 - /* the plugins should cleanup themself */
6927 + /* the plugins should cleanup themself */
6928 for (i = 0; i < srv->plugins.used; i++) {
6929 plugin *p = ((plugin **)(srv->plugins.ptr))[i];
6930 plugin_data *pd = p->data;
6933 con->plugin_ctx[pd->id] = NULL;
6937 #if COND_RESULT_UNSET
6938 for (i = srv->config_context->used - 1; i >= 0; i --) {
6939 con->cond_cache[i].result = COND_RESULT_UNSET;
6940 @@ -777,56 +652,56 @@
6942 memset(con->cond_cache, 0, sizeof(cond_cache_t) * srv->config_context->used);
6946 con->header_len = 0;
6947 con->in_error_handler = 0;
6950 config_setup_connection(srv, con);
6958 - * search for \r\n\r\n
6961 + * search for \r\n\r\n
6963 * this is a special 32bit version which is using a sliding window for
6964 - * the comparisions
6966 + * the comparisions
6975 * cmpbuf: abcd != cdef
6976 * cmpbuf: bcde != cdef
6977 * cmpbuf: cdef == cdef -> return &c
6979 - * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
6981 + * cmpbuf and rnrn are treated as 32bit uint and bit-ops are used to
6982 * maintain cmpbuf and rnrn
6987 char *buffer_search_rnrn(buffer *b) {
6988 uint32_t cmpbuf, rnrn;
6993 if (b->used < 4) return NULL;
6996 rnrn = ('\r' << 24) | ('\n' << 16) |
6997 ('\r' << 8) | ('\n' << 0);
7000 cmpbuf = (b->ptr[0] << 24) | (b->ptr[1] << 16) |
7001 (b->ptr[2] << 8) | (b->ptr[3] << 0);
7005 for (i = 0; i < b->used - 4; i++) {
7006 if (cmpbuf == rnrn) return cp - 4;
7009 cmpbuf = (cmpbuf << 8 | *(cp++)) & 0xffffffff;
7016 @@ -840,22 +715,25 @@
7018 chunkqueue *cq = con->read_queue;
7019 chunkqueue *dst_cq = con->request_content_queue;
7022 if (con->is_readable) {
7023 con->read_idle_ts = srv->cur_ts;
7026 switch(connection_handle_read(srv, con)) {
7028 + case NETWORK_STATUS_FATAL_ERROR:
7031 + case NETWORK_STATUS_CONNECTION_CLOSE:
7032 /* remote side closed the connection
7033 * if we still have content, handle it, if not leave here */
7035 if (cq->first == cq->last &&
7036 - cq->first->mem->used == 0) {
7037 + (NULL == cq->first ||
7038 + cq->first->mem->used == 0)) {
7040 /* conn-closed, leave here */
7041 connection_set_state(srv, con, CON_STATE_ERROR);
7047 @@ -891,14 +769,14 @@
7048 /* the last node was empty */
7049 if (c->next == NULL) {
7061 /* nothing to handle */
7062 if (cq->first == NULL) return 0;
7064 @@ -906,25 +784,26 @@
7065 case CON_STATE_READ:
7066 /* prepare con->request.request */
7070 /* check if we need the full package */
7071 if (con->request.request->used == 0) {
7075 b.ptr = c->mem->ptr + c->offset;
7076 b.used = c->mem->used - c->offset;
7079 if (NULL != (h_term = buffer_search_rnrn(&b))) {
7081 * - copy everything incl. the terminator to request.request
7084 - buffer_copy_string_len(con->request.request,
7087 + buffer_copy_string_len(con->request.request,
7089 h_term - b.ptr + 4);
7092 /* the buffer has been read up to the terminator */
7093 c->offset += h_term - b.ptr + 4;
7096 /* not found, copy everything */
7097 buffer_copy_string_len(con->request.request, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
7098 @@ -932,14 +811,14 @@
7101 /* have to take care of overlapping header terminators */
7104 size_t l = con->request.request->used - 2;
7105 char *s = con->request.request->ptr;
7109 b.ptr = c->mem->ptr + c->offset;
7110 b.used = c->mem->used - c->offset;
7113 if (con->request.request->used - 1 > 3 &&
7117 c->mem->ptr[0] == '\n') {
7118 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 1);
7122 h_term = con->request.request->ptr;
7123 } else if (con->request.request->used - 1 > 2 &&
7126 c->mem->ptr[1] == '\n') {
7127 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 2);
7131 h_term = con->request.request->ptr;
7132 } else if (con->request.request->used - 1 > 1 &&
7134 @@ -968,17 +847,17 @@
7135 c->mem->ptr[2] == '\n') {
7136 buffer_append_string_len(con->request.request, c->mem->ptr + c->offset, 3);
7140 h_term = con->request.request->ptr;
7141 } else if (NULL != (h_term = buffer_search_string_len(&b, "\r\n\r\n", 4))) {
7143 * - copy everything incl. the terminator to request.request
7146 - buffer_append_string_len(con->request.request,
7147 - c->mem->ptr + c->offset,
7149 + buffer_append_string_len(con->request.request,
7150 + c->mem->ptr + c->offset,
7151 c->offset + h_term - b.ptr + 4);
7154 /* the buffer has been read up to the terminator */
7155 c->offset += h_term - b.ptr + 4;
7157 @@ -999,16 +878,16 @@
7158 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7161 - case CON_STATE_READ_POST:
7162 + case CON_STATE_READ_POST:
7163 for (c = cq->first; c && (dst_cq->bytes_in != (off_t)con->request.content_length); c = c->next) {
7164 off_t weWant, weHave, toRead;
7167 weWant = con->request.content_length - dst_cq->bytes_in;
7170 assert(c->mem->used);
7173 weHave = c->mem->used - c->offset - 1;
7176 toRead = weHave > weWant ? weWant : weHave;
7178 /* the new way, copy everything into a chunkqueue whcih might use tempfiles */
7179 @@ -1017,13 +896,13 @@
7180 /* copy everything to max 1Mb sized tempfiles */
7183 - * if the last chunk is
7184 + * if the last chunk is
7185 * - smaller than 1Mb (size < 1Mb)
7186 * - not read yet (offset == 0)
7189 - * -> create a new chunk
7191 + * -> create a new chunk
7196 @@ -1056,14 +935,14 @@
7197 /* we have a chunk, let's write to it */
7199 if (dst_c->file.fd == -1) {
7200 - /* we don't have file to write to,
7201 + /* we don't have file to write to,
7202 * EACCES might be one reason.
7204 * Instead of sending 500 we send 413 and say the request is too large
7207 log_error_write(srv, __FILE__, __LINE__, "sbs",
7208 - "denying upload as opening to temp-file for upload failed:",
7209 + "denying upload as opening to temp-file for upload failed:",
7210 dst_c->file.name, strerror(errno));
7212 con->http_status = 413; /* Request-Entity too large */
7213 @@ -1074,15 +953,15 @@
7216 if (toRead != write(dst_c->file.fd, c->mem->ptr + c->offset, toRead)) {
7217 - /* write failed for some reason ... disk full ? */
7218 + /* write failed for some reason ... disk full ? */
7219 log_error_write(srv, __FILE__, __LINE__, "sbs",
7220 - "denying upload as writing to file failed:",
7221 + "denying upload as writing to file failed:",
7222 dst_c->file.name, strerror(errno));
7225 con->http_status = 413; /* Request-Entity too large */
7226 con->keep_alive = 0;
7227 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7230 close(dst_c->file.fd);
7231 dst_c->file.fd = -1;
7233 @@ -1090,7 +969,7 @@
7236 dst_c->file.length += toRead;
7239 if (dst_cq->bytes_in + toRead == (off_t)con->request.content_length) {
7240 /* we read everything, close the chunk */
7241 close(dst_c->file.fd);
7242 @@ -1102,7 +981,7 @@
7243 b = chunkqueue_get_append_buffer(dst_cq);
7244 buffer_copy_string_len(b, c->mem->ptr + c->offset, toRead);
7248 c->offset += toRead;
7249 dst_cq->bytes_in += toRead;
7251 @@ -1111,7 +990,7 @@
7252 if (dst_cq->bytes_in == (off_t)con->request.content_length) {
7253 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7260 @@ -1123,100 +1002,104 @@
7261 handler_t connection_handle_fdevent(void *s, void *context, int revents) {
7262 server *srv = (server *)s;
7263 connection *con = context;
7266 joblist_append(srv, con);
7269 if (revents & FDEVENT_IN) {
7270 con->is_readable = 1;
7272 - log_error_write(srv, __FILE__, __LINE__, "sd", "read-wait - done", con->fd);
7275 if (revents & FDEVENT_OUT) {
7276 con->is_writable = 1;
7277 /* we don't need the event twice */
7283 if (revents & ~(FDEVENT_IN | FDEVENT_OUT)) {
7284 /* looks like an error */
7287 /* FIXME: revents = 0x19 still means that we should read from the queue */
7288 if (revents & FDEVENT_HUP) {
7289 if (con->state == CON_STATE_CLOSE) {
7290 con->close_timeout_ts = 0;
7292 /* sigio reports the wrong event here
7294 - * there was no HUP at all
7296 + * there was no HUP at all
7298 #ifdef USE_LINUX_SIGIO
7299 if (srv->ev->in_sigio == 1) {
7300 log_error_write(srv, __FILE__, __LINE__, "sd",
7301 - "connection closed: poll() -> HUP", con->fd);
7302 + "connection closed: poll() -> HUP", con->sock->fd);
7304 connection_set_state(srv, con, CON_STATE_ERROR);
7307 connection_set_state(srv, con, CON_STATE_ERROR);
7312 } else if (revents & FDEVENT_ERR) {
7313 #ifndef USE_LINUX_SIGIO
7314 log_error_write(srv, __FILE__, __LINE__, "sd",
7315 - "connection closed: poll() -> ERR", con->fd);
7317 + "connection closed: poll() -> ERR", con->sock->fd);
7319 connection_set_state(srv, con, CON_STATE_ERROR);
7321 log_error_write(srv, __FILE__, __LINE__, "sd",
7322 "connection closed: poll() -> ???", revents);
7328 if (con->state == CON_STATE_READ ||
7329 con->state == CON_STATE_READ_POST) {
7330 connection_handle_read_state(srv, con);
7332 + * if SSL_read() is not readin in the full packet we won't get
7333 + * a fdevent as the low-level has already fetched everything.
7335 + * we have to call the state-engine to read the rest of the packet
7337 + if (con->is_readable) joblist_append(srv, con);
7341 if (con->state == CON_STATE_WRITE &&
7342 !chunkqueue_is_empty(con->write_queue) &&
7346 if (-1 == connection_handle_write(srv, con)) {
7347 connection_set_state(srv, con, CON_STATE_ERROR);
7350 log_error_write(srv, __FILE__, __LINE__, "ds",
7353 "handle write failed.");
7354 } else if (con->state == CON_STATE_WRITE) {
7355 con->write_request_ts = srv->cur_ts;
7360 if (con->state == CON_STATE_CLOSE) {
7361 /* flush the read buffers */
7364 - if (ioctl(con->fd, FIONREAD, &b)) {
7366 + if (ioctl(con->sock->fd, FIONREAD, &b)) {
7367 log_error_write(srv, __FILE__, __LINE__, "ss",
7368 "ioctl() failed", strerror(errno));
7374 log_error_write(srv, __FILE__, __LINE__, "sdd",
7375 - "CLOSE-read()", con->fd, b);
7377 + "CLOSE-read()", con->sock->fd, b);
7380 - read(con->fd, buf, sizeof(buf));
7381 + read(con->sock->fd, buf, sizeof(buf));
7383 /* nothing to read */
7386 con->close_timeout_ts = 0;
7391 return HANDLER_FINISHED;
7394 @@ -1229,63 +1112,68 @@
7397 /* accept it and register the fd */
7400 cnt_len = sizeof(cnt_addr);
7402 - if (-1 == (cnt = accept(srv_socket->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7403 + if (-1 == (cnt = accept(srv_socket->sock->fd, (struct sockaddr *) &cnt_addr, &cnt_len))) {
7405 + errno = WSAGetLastError();
7407 if ((errno != EAGAIN) &&
7408 + (errno != EWOULDBLOCK) &&
7410 - log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), errno);
7411 + log_error_write(srv, __FILE__, __LINE__, "ssd", "accept failed:", strerror(errno), srv_socket->sock->fd);
7421 /* ok, we have the connection, register it */
7423 log_error_write(srv, __FILE__, __LINE__, "sd",
7429 con = connections_get_new_connection(srv);
7432 - con->fde_ndx = -1;
7434 + con->sock->fd = cnt;
7435 + con->sock->fde_ndx = -1;
7437 gettimeofday(&(con->start_tv), NULL);
7439 - fdevent_register(srv->ev, con->fd, connection_handle_fdevent, con);
7442 + fdevent_register(srv->ev, con->sock, connection_handle_fdevent, con);
7444 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7447 con->connection_start = srv->cur_ts;
7448 con->dst_addr = cnt_addr;
7449 buffer_copy_string(con->dst_addr_buf, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
7450 con->srv_socket = srv_socket;
7452 - if (-1 == (fdevent_fcntl_set(srv->ev, con->fd))) {
7454 + if (-1 == (fdevent_fcntl_set(srv->ev, con->sock))) {
7455 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
7456 + connection_close(srv, con);
7460 /* connect FD to SSL */
7461 if (srv_socket->is_ssl) {
7462 - if (NULL == (con->ssl = SSL_new(srv_socket->ssl_ctx))) {
7463 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7464 + if (NULL == (con->sock->ssl = SSL_new(srv_socket->ssl_ctx))) {
7465 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7466 ERR_error_string(ERR_get_error(), NULL));
7468 + connection_close(srv, con);
7472 - SSL_set_accept_state(con->ssl);
7474 + SSL_set_accept_state(con->sock->ssl);
7477 - if (1 != (SSL_set_fd(con->ssl, cnt))) {
7478 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7480 + if (1 != (SSL_set_fd(con->sock->ssl, cnt))) {
7481 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7482 ERR_error_string(ERR_get_error(), NULL));
7483 + connection_close(srv, con);
7487 @@ -1300,102 +1188,102 @@
7489 server_socket *srv_sock = con->srv_socket;
7493 if (srv->srvconf.log_state_handling) {
7494 - log_error_write(srv, __FILE__, __LINE__, "sds",
7497 + log_error_write(srv, __FILE__, __LINE__, "sds",
7500 connection_get_state(con->state));
7504 size_t ostate = con->state;
7508 switch (con->state) {
7509 case CON_STATE_REQUEST_START: /* transient */
7510 if (srv->srvconf.log_state_handling) {
7511 - log_error_write(srv, __FILE__, __LINE__, "sds",
7512 - "state for fd", con->fd, connection_get_state(con->state));
7513 + log_error_write(srv, __FILE__, __LINE__, "sds",
7514 + "state for fd", con->sock->fd, connection_get_state(con->state));
7518 con->request_start = srv->cur_ts;
7519 con->read_idle_ts = srv->cur_ts;
7522 con->request_count++;
7523 con->loops_per_request = 0;
7526 connection_set_state(srv, con, CON_STATE_READ);
7530 case CON_STATE_REQUEST_END: /* transient */
7531 if (srv->srvconf.log_state_handling) {
7532 - log_error_write(srv, __FILE__, __LINE__, "sds",
7533 - "state for fd", con->fd, connection_get_state(con->state));
7534 + log_error_write(srv, __FILE__, __LINE__, "sds",
7535 + "state for fd", con->sock->fd, connection_get_state(con->state));
7539 if (http_request_parse(srv, con)) {
7540 /* we have to read some data from the POST request */
7543 connection_set_state(srv, con, CON_STATE_READ_POST);
7549 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7553 case CON_STATE_HANDLE_REQUEST:
7556 * the request is parsed
7559 * decided what to do with the request
7569 if (srv->srvconf.log_state_handling) {
7570 - log_error_write(srv, __FILE__, __LINE__, "sds",
7571 - "state for fd", con->fd, connection_get_state(con->state));
7572 + log_error_write(srv, __FILE__, __LINE__, "sds",
7573 + "state for fd", con->sock->fd, connection_get_state(con->state));
7577 switch (r = http_response_prepare(srv, con)) {
7578 case HANDLER_FINISHED:
7579 if (con->http_status == 404 ||
7580 con->http_status == 403) {
7581 /* 404 error-handler */
7583 - if (con->in_error_handler == 0 &&
7585 + if (con->in_error_handler == 0 &&
7586 (!buffer_is_empty(con->conf.error_handler) ||
7587 !buffer_is_empty(con->error_handler))) {
7588 /* call error-handler */
7591 con->error_handler_saved_status = con->http_status;
7592 con->http_status = 0;
7595 if (buffer_is_empty(con->error_handler)) {
7596 buffer_copy_string_buffer(con->request.uri, con->conf.error_handler);
7598 buffer_copy_string_buffer(con->request.uri, con->error_handler);
7600 buffer_reset(con->physical.path);
7603 con->in_error_handler = 1;
7606 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7611 } else if (con->in_error_handler) {
7612 /* error-handler is a 404 */
7615 /* continue as normal, status is the same */
7616 - log_error_write(srv, __FILE__, __LINE__, "sb",
7617 + log_error_write(srv, __FILE__, __LINE__, "sb",
7618 "Warning: Either the error-handler returned status 404 or the error-handler itself was not found:", con->request.uri);
7619 - log_error_write(srv, __FILE__, __LINE__, "sd",
7620 + log_error_write(srv, __FILE__, __LINE__, "sd",
7621 "returning the original status", con->error_handler_saved_status);
7622 - log_error_write(srv, __FILE__, __LINE__, "s",
7623 + log_error_write(srv, __FILE__, __LINE__, "s",
7624 "If this is a rails app: check your production.log");
7625 con->http_status = con->error_handler_saved_status;
7627 @@ -1403,73 +1291,73 @@
7628 /* error-handler is back and has generated content */
7629 /* if Status: was set, take it otherwise use 200 */
7633 if (con->http_status == 0) con->http_status = 200;
7636 /* we have something to send, go on */
7637 connection_set_state(srv, con, CON_STATE_RESPONSE_START);
7639 case HANDLER_WAIT_FOR_FD:
7643 fdwaitqueue_append(srv, con);
7646 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7650 case HANDLER_COMEBACK:
7652 case HANDLER_WAIT_FOR_EVENT:
7653 /* come back here */
7654 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
7659 /* something went wrong */
7660 connection_set_state(srv, con, CON_STATE_ERROR);
7663 - log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->fd, r);
7664 + log_error_write(srv, __FILE__, __LINE__, "sdd", "unknown ret-value: ", con->sock->fd, r);
7670 case CON_STATE_RESPONSE_START:
7673 * the decision is done
7674 * - create the HTTP-Response-Header
7680 if (srv->srvconf.log_state_handling) {
7681 - log_error_write(srv, __FILE__, __LINE__, "sds",
7682 - "state for fd", con->fd, connection_get_state(con->state));
7683 + log_error_write(srv, __FILE__, __LINE__, "sds",
7684 + "state for fd", con->sock->fd, connection_get_state(con->state));
7688 if (-1 == connection_handle_write_prepare(srv, con)) {
7689 connection_set_state(srv, con, CON_STATE_ERROR);
7696 connection_set_state(srv, con, CON_STATE_WRITE);
7698 case CON_STATE_RESPONSE_END: /* transient */
7699 /* log the request */
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 plugins_call_handle_request_done(srv, con);
7716 if (con->keep_alive) {
7717 connection_set_state(srv, con, CON_STATE_REQUEST_START);
7722 con->request_start = srv->cur_ts;
7723 con->read_idle_ts = srv->cur_ts;
7725 @@ -1482,103 +1370,103 @@
7726 log_error_write(srv, __FILE__, __LINE__, "sd", "unhandling return value", r);
7732 if (srv_sock->is_ssl) {
7733 - switch (SSL_shutdown(con->ssl)) {
7734 + switch (SSL_shutdown(con->sock->ssl)) {
7739 - /* wait for fd-event
7741 + /* wait for fd-event
7743 * FIXME: wait for fdevent and call SSL_shutdown again
7751 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7752 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
7753 ERR_error_string(ERR_get_error(), NULL));
7757 connection_close(srv, con);
7764 connection_reset(srv, con);
7768 case CON_STATE_CONNECT:
7769 if (srv->srvconf.log_state_handling) {
7770 - log_error_write(srv, __FILE__, __LINE__, "sds",
7771 - "state for fd", con->fd, connection_get_state(con->state));
7772 + log_error_write(srv, __FILE__, __LINE__, "sds",
7773 + "state for fd", con->sock->fd, connection_get_state(con->state));
7777 chunkqueue_reset(con->read_queue);
7780 con->request_count = 0;
7784 case CON_STATE_CLOSE:
7785 if (srv->srvconf.log_state_handling) {
7786 - log_error_write(srv, __FILE__, __LINE__, "sds",
7787 - "state for fd", con->fd, connection_get_state(con->state));
7788 + log_error_write(srv, __FILE__, __LINE__, "sds",
7789 + "state for fd", con->sock->fd, connection_get_state(con->state));
7793 if (con->keep_alive) {
7794 - if (ioctl(con->fd, FIONREAD, &b)) {
7795 + if (ioctl(con->sock->fd, FIONREAD, &b)) {
7796 log_error_write(srv, __FILE__, __LINE__, "ss",
7797 "ioctl() failed", strerror(errno));
7801 log_error_write(srv, __FILE__, __LINE__, "sdd",
7802 - "CLOSE-read()", con->fd, b);
7804 + "CLOSE-read()", con->sock->fd, b);
7807 - read(con->fd, buf, sizeof(buf));
7808 + read(con->sock->fd, buf, sizeof(buf));
7810 /* nothing to read */
7813 con->close_timeout_ts = 0;
7816 con->close_timeout_ts = 0;
7820 if (srv->cur_ts - con->close_timeout_ts > 1) {
7821 connection_close(srv, con);
7824 if (srv->srvconf.log_state_handling) {
7825 - log_error_write(srv, __FILE__, __LINE__, "sd",
7826 - "connection closed for fd", con->fd);
7827 + log_error_write(srv, __FILE__, __LINE__, "sd",
7828 + "connection closed for fd", con->sock->fd);
7834 case CON_STATE_READ_POST:
7835 case CON_STATE_READ:
7836 if (srv->srvconf.log_state_handling) {
7837 - log_error_write(srv, __FILE__, __LINE__, "sds",
7838 - "state for fd", con->fd, connection_get_state(con->state));
7839 + log_error_write(srv, __FILE__, __LINE__, "sds",
7840 + "state for fd", con->sock->fd, connection_get_state(con->state));
7844 connection_handle_read_state(srv, con);
7846 case CON_STATE_WRITE:
7847 if (srv->srvconf.log_state_handling) {
7848 - log_error_write(srv, __FILE__, __LINE__, "sds",
7849 - "state for fd", con->fd, connection_get_state(con->state));
7850 + log_error_write(srv, __FILE__, __LINE__, "sds",
7851 + "state for fd", con->sock->fd, connection_get_state(con->state));
7855 /* only try to write if we have something in the queue */
7856 if (!chunkqueue_is_empty(con->write_queue)) {
7858 log_error_write(srv, __FILE__, __LINE__, "dsd",
7861 "packets to write:",
7862 con->write_queue->used);
7864 @@ -1586,17 +1474,17 @@
7865 if (!chunkqueue_is_empty(con->write_queue) && con->is_writable) {
7866 if (-1 == connection_handle_write(srv, con)) {
7867 log_error_write(srv, __FILE__, __LINE__, "ds",
7870 "handle write failed.");
7871 connection_set_state(srv, con, CON_STATE_ERROR);
7872 } else if (con->state == CON_STATE_WRITE) {
7873 con->write_request_ts = srv->cur_ts;
7879 case CON_STATE_ERROR: /* transient */
7882 /* even if the connection was drop we still have to write it to the access log */
7883 if (con->http_status) {
7884 plugins_call_handle_request_done(srv, con);
7885 @@ -1604,28 +1492,28 @@
7887 if (srv_sock->is_ssl) {
7889 - switch ((ret = SSL_shutdown(con->ssl))) {
7890 + switch ((ret = SSL_shutdown(con->sock->ssl))) {
7895 - SSL_shutdown(con->ssl);
7896 + SSL_shutdown(con->sock->ssl);
7899 - log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7900 - SSL_get_error(con->ssl, ret),
7901 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
7902 + SSL_get_error(con->sock->ssl, ret),
7903 ERR_error_string(ERR_get_error(), NULL));
7913 - log_error_write(srv, __FILE__, __LINE__, "sd",
7914 - "emergency exit: direct",
7916 + log_error_write(srv, __FILE__, __LINE__, "sd",
7917 + "emergency exit: direct",
7922 @@ -1639,35 +1527,35 @@
7928 connection_reset(srv, con);
7931 /* close the connection */
7932 if ((con->keep_alive == 1) &&
7933 - (0 == shutdown(con->fd, SHUT_WR))) {
7934 + (0 == shutdown(con->sock->fd, SHUT_WR))) {
7935 con->close_timeout_ts = srv->cur_ts;
7936 connection_set_state(srv, con, CON_STATE_CLOSE);
7939 if (srv->srvconf.log_state_handling) {
7940 - log_error_write(srv, __FILE__, __LINE__, "sd",
7941 - "shutdown for fd", con->fd);
7942 + log_error_write(srv, __FILE__, __LINE__, "sd",
7943 + "shutdown for fd", con->sock->fd);
7946 connection_close(srv, con);
7950 con->keep_alive = 0;
7958 - log_error_write(srv, __FILE__, __LINE__, "sdd",
7959 - "unknown state:", con->fd, con->state);
7961 + log_error_write(srv, __FILE__, __LINE__, "sdd",
7962 + "unknown state:", con->sock->fd, con->state);
7970 } else if (ostate == con->state) {
7971 @@ -1676,33 +1564,33 @@
7974 if (srv->srvconf.log_state_handling) {
7975 - log_error_write(srv, __FILE__, __LINE__, "sds",
7978 + log_error_write(srv, __FILE__, __LINE__, "sds",
7981 connection_get_state(con->state));
7985 switch(con->state) {
7986 case CON_STATE_READ_POST:
7987 case CON_STATE_READ:
7988 case CON_STATE_CLOSE:
7989 - fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_IN);
7990 + fdevent_event_add(srv->ev, con->sock, FDEVENT_IN);
7992 case CON_STATE_WRITE:
7993 - /* request write-fdevent only if we really need it
7994 + /* request write-fdevent only if we really need it
7995 * - if we have data to write
7996 - * - if the socket is not writable yet
7997 + * - if the socket is not writable yet
7999 - if (!chunkqueue_is_empty(con->write_queue) &&
8000 + if (!chunkqueue_is_empty(con->write_queue) &&
8001 (con->is_writable == 0) &&
8002 (con->traffic_limit_reached == 0)) {
8003 - fdevent_event_add(srv->ev, &(con->fde_ndx), con->fd, FDEVENT_OUT);
8004 + fdevent_event_add(srv->ev, con->sock, FDEVENT_OUT);
8006 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8007 + fdevent_event_del(srv->ev, con->sock);
8011 - fdevent_event_del(srv->ev, &(con->fde_ndx), con->fd);
8012 + fdevent_event_del(srv->ev, con->sock);
8016 --- ../lighttpd-1.4.11/src/crc32.h 2005-09-30 20:18:59.000000000 +0300
8017 +++ lighttpd-1.4.12/src/crc32.h 2006-07-16 00:26:04.000000000 +0300
8021 #include <sys/types.h>
8022 +#include <stdlib.h>
8024 #if defined HAVE_STDINT_H
8027 #include <inttypes.h>
8031 +#define uint32_t unsigned __int32
8034 uint32_t generate_crc32c(char *string, size_t length);
8037 --- ../lighttpd-1.4.11/src/data_array.c 2005-08-23 17:36:12.000000000 +0300
8038 +++ lighttpd-1.4.12/src/data_array.c 2006-07-16 00:26:04.000000000 +0300
8041 static void data_array_free(data_unset *d) {
8042 data_array *ds = (data_array *)d;
8045 buffer_free(ds->key);
8046 array_free(ds->value);
8052 static void data_array_reset(data_unset *d) {
8053 data_array *ds = (data_array *)d;
8056 /* reused array elements */
8057 buffer_reset(ds->key);
8058 array_reset(ds->value);
8070 data_array *data_array_init(void) {
8074 ds = calloc(1, sizeof(*ds));
8077 ds->key = buffer_init();
8078 ds->value = array_init();
8081 ds->copy = data_array_copy;
8082 ds->free = data_array_free;
8083 ds->reset = data_array_reset;
8084 ds->insert_dup = data_array_insert_dup;
8085 ds->print = data_array_print;
8086 ds->type = TYPE_ARRAY;
8091 --- ../lighttpd-1.4.11/src/data_config.c 2005-08-17 12:53:19.000000000 +0300
8092 +++ lighttpd-1.4.12/src/data_config.c 2006-07-16 00:26:03.000000000 +0300
8095 static void data_config_free(data_unset *d) {
8096 data_config *ds = (data_config *)d;
8099 buffer_free(ds->key);
8100 buffer_free(ds->op);
8101 buffer_free(ds->comp_key);
8104 array_free(ds->value);
8105 array_free(ds->childs);
8108 if (ds->string) buffer_free(ds->string);
8110 if (ds->regex) pcre_free(ds->regex);
8111 if (ds->regex_study) pcre_free(ds->regex_study);
8118 static void data_config_reset(data_unset *d) {
8119 data_config *ds = (data_config *)d;
8122 /* reused array elements */
8123 buffer_reset(ds->key);
8124 buffer_reset(ds->comp_key);
8127 static int data_config_insert_dup(data_unset *dst, data_unset *src) {
8138 array *a = (array *)ds->value;
8143 if (0 == ds->context_ndx) {
8144 fprintf(stderr, "config {\n");
8146 @@ -117,22 +117,22 @@
8148 data_config *data_config_init(void) {
8152 ds = calloc(1, sizeof(*ds));
8155 ds->key = buffer_init();
8156 ds->op = buffer_init();
8157 ds->comp_key = buffer_init();
8158 ds->value = array_init();
8159 ds->childs = array_init();
8160 ds->childs->is_weakref = 1;
8163 ds->copy = data_config_copy;
8164 ds->free = data_config_free;
8165 ds->reset = data_config_reset;
8166 ds->insert_dup = data_config_insert_dup;
8167 ds->print = data_config_print;
8168 ds->type = TYPE_CONFIG;
8173 --- ../lighttpd-1.4.11/src/data_count.c 2005-08-23 17:36:12.000000000 +0300
8174 +++ lighttpd-1.4.12/src/data_count.c 2006-07-16 00:26:03.000000000 +0300
8177 static void data_count_free(data_unset *d) {
8178 data_count *ds = (data_count *)d;
8181 buffer_free(ds->key);
8187 static void data_count_reset(data_unset *d) {
8188 data_count *ds = (data_count *)d;
8191 buffer_reset(ds->key);
8197 static int data_count_insert_dup(data_unset *dst, data_unset *src) {
8198 data_count *ds_dst = (data_count *)dst;
8199 data_count *ds_src = (data_count *)src;
8202 ds_dst->count += ds_src->count;
8211 static void data_count_print(const data_unset *d, int depth) {
8212 data_count *ds = (data_count *)d;
8216 fprintf(stderr, "count(%d)", ds->count);
8220 data_count *data_count_init(void) {
8224 ds = calloc(1, sizeof(*ds));
8227 ds->key = buffer_init();
8231 ds->copy = data_count_copy;
8232 ds->free = data_count_free;
8233 ds->reset = data_count_reset;
8234 ds->insert_dup = data_count_insert_dup;
8235 ds->print = data_count_print;
8236 ds->type = TYPE_COUNT;
8241 --- ../lighttpd-1.4.11/src/data_fastcgi.c 2005-08-23 17:36:12.000000000 +0300
8242 +++ lighttpd-1.4.12/src/data_fastcgi.c 2006-07-16 00:26:04.000000000 +0300
8245 static void data_fastcgi_free(data_unset *d) {
8246 data_fastcgi *ds = (data_fastcgi *)d;
8249 buffer_free(ds->key);
8250 buffer_free(ds->host);
8256 static void data_fastcgi_reset(data_unset *d) {
8257 data_fastcgi *ds = (data_fastcgi *)d;
8260 buffer_reset(ds->key);
8261 buffer_reset(ds->host);
8266 static int data_fastcgi_insert_dup(data_unset *dst, data_unset *src) {
8275 static void data_fastcgi_print(const data_unset *d, int depth) {
8276 data_fastcgi *ds = (data_fastcgi *)d;
8280 fprintf(stderr, "fastcgi(%s)", ds->host->ptr);
8284 data_fastcgi *data_fastcgi_init(void) {
8288 ds = calloc(1, sizeof(*ds));
8291 ds->key = buffer_init();
8292 ds->host = buffer_init();
8294 ds->is_disabled = 0;
8297 ds->copy = data_fastcgi_copy;
8298 ds->free = data_fastcgi_free;
8299 ds->reset = data_fastcgi_reset;
8300 ds->insert_dup = data_fastcgi_insert_dup;
8301 ds->print = data_fastcgi_print;
8302 ds->type = TYPE_FASTCGI;
8307 --- ../lighttpd-1.4.11/src/data_integer.c 2005-08-23 17:36:12.000000000 +0300
8308 +++ lighttpd-1.4.12/src/data_integer.c 2006-07-16 00:26:03.000000000 +0300
8311 static void data_integer_free(data_unset *d) {
8312 data_integer *ds = (data_integer *)d;
8315 buffer_free(ds->key);
8321 static void data_integer_reset(data_unset *d) {
8322 data_integer *ds = (data_integer *)d;
8325 /* reused integer elements */
8326 buffer_reset(ds->key);
8330 static int data_integer_insert_dup(data_unset *dst, data_unset *src) {
8342 data_integer *data_integer_init(void) {
8346 ds = calloc(1, sizeof(*ds));
8349 ds->key = buffer_init();
8353 ds->copy = data_integer_copy;
8354 ds->free = data_integer_free;
8355 ds->reset = data_integer_reset;
8356 ds->insert_dup = data_integer_insert_dup;
8357 ds->print = data_integer_print;
8358 ds->type = TYPE_INTEGER;
8363 --- ../lighttpd-1.4.11/src/data_string.c 2005-08-23 17:36:12.000000000 +0300
8364 +++ lighttpd-1.4.12/src/data_string.c 2006-07-16 00:26:04.000000000 +0300
8367 static void data_string_free(data_unset *d) {
8368 data_string *ds = (data_string *)d;
8371 buffer_free(ds->key);
8372 buffer_free(ds->value);
8378 static void data_string_reset(data_unset *d) {
8379 data_string *ds = (data_string *)d;
8382 /* reused array elements */
8383 buffer_reset(ds->key);
8384 buffer_reset(ds->value);
8386 static int data_string_insert_dup(data_unset *dst, data_unset *src) {
8387 data_string *ds_dst = (data_string *)dst;
8388 data_string *ds_src = (data_string *)src;
8391 if (ds_dst->value->used) {
8392 buffer_append_string(ds_dst->value, ", ");
8393 buffer_append_string_buffer(ds_dst->value, ds_src->value);
8395 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8405 static int data_response_insert_dup(data_unset *dst, data_unset *src) {
8406 data_string *ds_dst = (data_string *)dst;
8407 data_string *ds_src = (data_string *)src;
8410 if (ds_dst->value->used) {
8411 buffer_append_string(ds_dst->value, "\r\n");
8412 buffer_append_string_buffer(ds_dst->value, ds_dst->key);
8415 buffer_copy_string_buffer(ds_dst->value, ds_src->value);
8427 data_string *data_string_init(void) {
8431 ds = calloc(1, sizeof(*ds));
8435 ds->key = buffer_init();
8436 ds->value = buffer_init();
8439 ds->copy = data_string_copy;
8440 ds->free = data_string_free;
8441 ds->reset = data_string_reset;
8442 ds->insert_dup = data_string_insert_dup;
8443 ds->print = data_string_print;
8444 ds->type = TYPE_STRING;
8450 data_string *data_response_init(void) {
8454 ds = data_string_init();
8455 ds->insert_dup = data_response_insert_dup;
8460 --- ../lighttpd-1.4.11/src/etag.c 2005-08-11 01:26:40.000000000 +0300
8461 +++ lighttpd-1.4.12/src/etag.c 2006-07-18 13:03:40.000000000 +0300
8465 int etag_is_equal(buffer *etag, const char *matches) {
8466 - if (0 == strcmp(etag->ptr, matches)) return 1;
8467 + if (buffer_is_equal_string(etag, matches, strlen(matches))) return 1;
8472 buffer_append_off_t(etag, st->st_size);
8473 buffer_append_string_len(etag, CONST_STR_LEN("-"));
8474 buffer_append_long(etag, st->st_mtime);
8480 int etag_mutate(buffer *mut, buffer *etag) {
8484 for (h=0, i=0; i < etag->used; ++i) h = (h<<5)^(h>>27)^(etag->ptr[i]);
8488 buffer_copy_string_len(mut, CONST_STR_LEN("\""));
8489 buffer_append_long(mut, h);
8490 buffer_append_string_len(mut, CONST_STR_LEN("\""));
8495 --- ../lighttpd-1.4.11/src/etag.h 2005-08-11 01:26:40.000000000 +0300
8496 +++ lighttpd-1.4.12/src/etag.h 2006-07-16 00:26:03.000000000 +0300
8499 #include <sys/types.h>
8500 #include <sys/stat.h>
8501 -#include <unistd.h>
8505 int etag_is_equal(buffer *etag, const char *matches);
8506 int etag_create(buffer *etag, struct stat *st);
8507 int etag_mutate(buffer *mut, buffer *etag);
8512 --- ../lighttpd-1.4.11/src/fastcgi.h 2005-08-11 01:26:40.000000000 +0300
8513 +++ lighttpd-1.4.12/src/fastcgi.h 2006-07-16 00:26:03.000000000 +0300
8519 * Defines for the FastCGI protocol.
8524 - unsigned char type;
8525 + unsigned char type;
8526 unsigned char reserved[7];
8527 } FCGI_UnknownTypeBody;
8529 --- ../lighttpd-1.4.11/src/fdevent.c 2005-11-15 10:51:05.000000000 +0200
8530 +++ lighttpd-1.4.12/src/fdevent.c 2006-07-18 13:03:40.000000000 +0300
8533 #include "settings.h"
8535 -#include <unistd.h>
8539 @@ -11,60 +10,116 @@
8541 #include "fdevent.h"
8545 +#include "sys-socket.h"
8547 +fdevent_revent *fdevent_revent_init(void) {
8548 + STRUCT_INIT(fdevent_revent, revent);
8553 +void fdevent_revent_free(fdevent_revent *revent) {
8554 + if (!revent) return;
8559 +fdevent_revents *fdevent_revents_init(void) {
8560 + STRUCT_INIT(fdevent_revents, revents);
8565 +void fdevent_revents_reset(fdevent_revents *revents) {
8566 + if (!revents) return;
8568 + revents->used = 0;
8571 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events) {
8572 + fdevent_revent *revent;
8574 + if (revents->used == revents->size) {
8575 + /* resize the events-array */
8576 + revents->ptr = realloc(revents->ptr, (revents->size + 1) * sizeof(*(revents->ptr)));
8577 + revents->ptr[revents->size++] = fdevent_revent_init();
8580 + revent = revents->ptr[revents->used++];
8582 + revent->revents = events;
8585 +void fdevent_revents_free(fdevent_revents *revents) {
8588 + if (!revents) return;
8590 + if (revents->size) {
8591 + for (i = 0; i < revents->size; i++) {
8592 + fdevent_revent_free(revents->ptr[i]);
8595 + free(revents->ptr);
8600 fdevents *fdevent_init(size_t maxfds, fdevent_handler_t type) {
8604 ev = calloc(1, sizeof(*ev));
8605 ev->fdarray = calloc(maxfds, sizeof(*ev->fdarray));
8606 ev->maxfds = maxfds;
8610 case FDEVENT_HANDLER_POLL:
8611 if (0 != fdevent_poll_init(ev)) {
8612 - fprintf(stderr, "%s.%d: event-handler poll failed\n",
8613 + fprintf(stderr, "%s.%d: event-handler poll failed\n",
8614 __FILE__, __LINE__);
8620 case FDEVENT_HANDLER_SELECT:
8621 if (0 != fdevent_select_init(ev)) {
8622 - fprintf(stderr, "%s.%d: event-handler select failed\n",
8623 + fprintf(stderr, "%s.%d: event-handler select failed\n",
8624 __FILE__, __LINE__);
8628 case FDEVENT_HANDLER_LINUX_RTSIG:
8629 if (0 != fdevent_linux_rtsig_init(ev)) {
8630 - fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8631 + fprintf(stderr, "%s.%d: event-handler linux-rtsig failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8632 __FILE__, __LINE__);
8636 case FDEVENT_HANDLER_LINUX_SYSEPOLL:
8637 if (0 != fdevent_linux_sysepoll_init(ev)) {
8638 - fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8639 + fprintf(stderr, "%s.%d: event-handler linux-sysepoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8640 __FILE__, __LINE__);
8644 case FDEVENT_HANDLER_SOLARIS_DEVPOLL:
8645 if (0 != fdevent_solaris_devpoll_init(ev)) {
8646 - fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8647 + fprintf(stderr, "%s.%d: event-handler solaris-devpoll failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8648 __FILE__, __LINE__);
8652 case FDEVENT_HANDLER_FREEBSD_KQUEUE:
8653 if (0 != fdevent_freebsd_kqueue_init(ev)) {
8654 - fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8655 + fprintf(stderr, "%s.%d: event-handler freebsd-kqueue failed, try to set server.event-handler = \"poll\" or \"select\"\n",
8656 __FILE__, __LINE__);
8661 - fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8662 + fprintf(stderr, "%s.%d: event-handler is unknown, try to set server.event-handler = \"poll\" or \"select\"\n",
8663 __FILE__, __LINE__);
8666 @@ -75,28 +130,29 @@
8667 void fdevent_free(fdevents *ev) {
8672 if (ev->free) ev->free(ev);
8675 for (i = 0; i < ev->maxfds; i++) {
8676 if (ev->fdarray[i]) free(ev->fdarray[i]);
8684 int fdevent_reset(fdevents *ev) {
8685 if (ev->reset) return ev->reset(ev);
8691 fdnode *fdnode_init() {
8695 fdn = calloc(1, sizeof(*fdn));
8701 @@ -104,48 +160,40 @@
8705 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx) {
8706 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx) {
8710 fdn = fdnode_init();
8711 fdn->handler = handler;
8713 + fdn->fd = sock->fd;
8716 - ev->fdarray[fd] = fdn;
8718 + ev->fdarray[sock->fd] = fdn;
8723 -int fdevent_unregister(fdevents *ev, int fd) {
8724 +int fdevent_unregister(fdevents *ev, iosocket *sock) {
8727 - fdn = ev->fdarray[fd];
8729 + fdn = ev->fdarray[sock->fd];
8733 - ev->fdarray[fd] = NULL;
8736 + ev->fdarray[sock->fd] = NULL;
8741 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd) {
8742 - int fde = fde_ndx ? *fde_ndx : -1;
8744 - if (ev->event_del) fde = ev->event_del(ev, fde, fd);
8746 - if (fde_ndx) *fde_ndx = fde;
8748 +int fdevent_event_del(fdevents *ev, iosocket *sock) {
8749 + if (ev->event_del) ev->event_del(ev, sock);
8754 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events) {
8755 - int fde = fde_ndx ? *fde_ndx : -1;
8757 - if (ev->event_add) fde = ev->event_add(ev, fde, fd, events);
8759 - if (fde_ndx) *fde_ndx = fde;
8761 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events) {
8762 + if (ev->event_add) ev->event_add(ev, sock, events);
8767 @@ -154,49 +202,41 @@
8768 return ev->poll(ev, timeout_ms);
8771 -int fdevent_event_get_revent(fdevents *ev, size_t ndx) {
8772 - if (ev->event_get_revent == NULL) SEGFAULT();
8774 - return ev->event_get_revent(ev, ndx);
8776 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
8779 -int fdevent_event_get_fd(fdevents *ev, size_t ndx) {
8780 - if (ev->event_get_fd == NULL) SEGFAULT();
8782 - return ev->event_get_fd(ev, ndx);
8784 + if (ev->get_revents == NULL) SEGFAULT();
8786 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd) {
8787 - if (ev->fdarray[fd] == NULL) SEGFAULT();
8788 - if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8790 - return ev->fdarray[fd]->handler;
8792 + fdevent_revents_reset(revents);
8794 -void * fdevent_get_context(fdevents *ev, int fd) {
8795 - if (ev->fdarray[fd] == NULL) SEGFAULT();
8796 - if (ev->fdarray[fd]->fd != fd) SEGFAULT();
8798 - return ev->fdarray[fd]->ctx;
8799 + ev->get_revents(ev, event_count, revents);
8801 + /* patch the event handlers */
8802 + for (i = 0; i < event_count; i++) {
8803 + fdevent_revent *r = revents->ptr[i];
8805 + r->handler = ev->fdarray[r->fd]->handler;
8806 + r->context = ev->fdarray[r->fd]->ctx;
8812 -int fdevent_fcntl_set(fdevents *ev, int fd) {
8813 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock) {
8818 /* close fd on exec (cgi) */
8819 - fcntl(fd, F_SETFD, FD_CLOEXEC);
8820 + fcntl(sock->fd, F_SETFD, FD_CLOEXEC);
8822 - if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, fd);
8824 - return fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
8825 + if ((ev) && (ev->fcntl_set)) return ev->fcntl_set(ev, sock->fd);
8827 + return fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR);
8828 +#elif defined _WIN32
8829 + return ioctlsocket(sock->fd, FIONBIO, &i);
8836 -int fdevent_event_next_fdndx(fdevents *ev, int ndx) {
8837 - if (ev->event_next_fdndx) return ev->event_next_fdndx(ev, ndx);
8842 --- ../lighttpd-1.4.11/src/fdevent.h 2005-09-27 11:26:33.000000000 +0300
8843 +++ lighttpd-1.4.12/src/fdevent.h 2006-07-18 13:03:40.000000000 +0300
8845 #include "settings.h"
8848 +#include "iosocket.h"
8849 +#include "array-static.h"
8851 /* select event-system */
8853 #if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)
8855 # include <sys/epoll.h>
8858 -/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8859 +/* MacOS 10.3.x has poll.h under /usr/include/, all other unixes
8860 * under /usr/include/sys/ */
8861 #if defined HAVE_POLL && (defined(HAVE_SYS_POLL_H) || defined(HAVE_POLL_H))
8867 # include <sys/poll.h>
8869 # if defined HAVE_SIGTIMEDWAIT && defined(__linux__)
8871 # include <signal.h>
8876 +# define HAVE_SELECT
8878 #if defined HAVE_SELECT
8881 # include <winsock2.h>
8885 #define FDEVENT_HUP BV(4)
8886 #define FDEVENT_NVAL BV(5)
8888 -typedef enum { FD_EVENT_TYPE_UNSET = -1,
8889 - FD_EVENT_TYPE_CONNECTION,
8890 - FD_EVENT_TYPE_FCGI_CONNECTION,
8891 - FD_EVENT_TYPE_DIRWATCH,
8892 - FD_EVENT_TYPE_CGI_CONNECTION
8893 +typedef enum { FD_EVENT_TYPE_UNSET = -1,
8894 + FD_EVENT_TYPE_CONNECTION,
8895 + FD_EVENT_TYPE_FCGI_CONNECTION,
8896 + FD_EVENT_TYPE_DIRWATCH,
8897 + FD_EVENT_TYPE_CGI_CONNECTION
8900 -typedef enum { FDEVENT_HANDLER_UNSET,
8901 +typedef enum { FDEVENT_HANDLER_UNSET,
8902 FDEVENT_HANDLER_SELECT,
8903 FDEVENT_HANDLER_POLL,
8904 FDEVENT_HANDLER_LINUX_RTSIG,
8908 * a mapping from fd to connection structure
8913 int fd; /**< the fd */
8914 @@ -96,43 +101,51 @@
8918 +ARRAY_STATIC_DEF(fd_conn_buffer, fd_conn, );
8932 + fdevent_handler handler;
8936 +ARRAY_STATIC_DEF(fdevent_revents, fdevent_revent, );
8939 * array of unused fd's
8944 typedef struct _fdnode {
8945 - fdevent_handler handler;
8949 + fdevent_handler handler; /* who handles the events for this fd */
8950 + void *ctx; /* opaque pointer which is passed as 3rd parameter to the handler */
8953 struct _fdnode *prev, *next;
8965 * fd-event handler for select(), poll() and rt-signals on Linux 2.4
8969 typedef struct fdevents {
8970 fdevent_handler_t type;
8974 + fdnode **fdarray; /* a list of fdnodes */
8978 #ifdef USE_LINUX_SIGIO
8981 @@ -146,21 +159,21 @@
8984 struct pollfd *pollfds;
8995 fd_set select_write;
8996 fd_set select_error;
8999 fd_set select_set_read;
9000 fd_set select_set_write;
9001 fd_set select_set_error;
9006 #ifdef USE_SOLARIS_DEVPOLL
9007 @@ -177,16 +190,13 @@
9009 int (*reset)(struct fdevents *ev);
9010 void (*free)(struct fdevents *ev);
9012 - int (*event_add)(struct fdevents *ev, int fde_ndx, int fd, int events);
9013 - int (*event_del)(struct fdevents *ev, int fde_ndx, int fd);
9014 - int (*event_get_revent)(struct fdevents *ev, size_t ndx);
9015 - int (*event_get_fd)(struct fdevents *ev, size_t ndx);
9017 - int (*event_next_fdndx)(struct fdevents *ev, int ndx);
9020 + int (*event_add)(struct fdevents *ev, iosocket *sock, int events);
9021 + int (*event_del)(struct fdevents *ev, iosocket *sock);
9022 + int (*get_revents)(struct fdevents *ev, size_t event_count, fdevent_revents *revents);
9024 int (*poll)(struct fdevents *ev, int timeout_ms);
9027 int (*fcntl_set)(struct fdevents *ev, int fd);
9030 @@ -194,22 +204,44 @@
9031 int fdevent_reset(fdevents *ev);
9032 void fdevent_free(fdevents *ev);
9034 -int fdevent_event_add(fdevents *ev, int *fde_ndx, int fd, int events);
9035 -int fdevent_event_del(fdevents *ev, int *fde_ndx, int fd);
9036 -int fdevent_event_get_revent(fdevents *ev, size_t ndx);
9037 -int fdevent_event_get_fd(fdevents *ev, size_t ndx);
9038 -fdevent_handler fdevent_get_handler(fdevents *ev, int fd);
9039 -void * fdevent_get_context(fdevents *ev, int fd);
9041 + * call the plugin for the number of available events
9043 +int fdevent_poll(fdevents *ev, int timeout_ms);
9045 + * get all available events
9047 +int fdevent_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents);
9049 -int fdevent_event_next_fdndx(fdevents *ev, int ndx);
9051 + * add or remove a fd to the handled-pool
9053 +int fdevent_register(fdevents *ev, iosocket *sock, fdevent_handler handler, void *ctx);
9054 +int fdevent_unregister(fdevents *ev, iosocket *sock);
9056 -int fdevent_poll(fdevents *ev, int timeout_ms);
9058 + * add a event to a registered fd
9060 +int fdevent_event_add(fdevents *ev, iosocket *sock, int events);
9061 +int fdevent_event_del(fdevents *ev, iosocket *sock);
9064 + * set non-blocking
9066 +int fdevent_fcntl_set(fdevents *ev, iosocket *sock);
9068 +fdevent_revents *fdevent_revents_init(void);
9069 +void fdevent_revents_reset(fdevent_revents *revents);
9070 +void fdevent_revents_add(fdevent_revents *revents, int fd, int events);
9071 +void fdevent_revents_free(fdevent_revents *revents);
9073 -int fdevent_register(fdevents *ev, int fd, fdevent_handler handler, void *ctx);
9074 -int fdevent_unregister(fdevents *ev, int fd);
9075 +fdevent_revent *fdevent_revent_init(void);
9076 +void fdevent_revent_free(fdevent_revent *revent);
9078 -int fdevent_fcntl_set(fdevents *ev, int fd);
9083 int fdevent_select_init(fdevents *ev);
9084 int fdevent_poll_init(fdevents *ev);
9085 int fdevent_linux_rtsig_init(fdevents *ev);
9086 --- ../lighttpd-1.4.11/src/fdevent_freebsd_kqueue.c 2005-09-01 10:46:24.000000000 +0300
9087 +++ lighttpd-1.4.12/src/fdevent_freebsd_kqueue.c 2006-07-16 00:26:03.000000000 +0300
9089 #include <sys/types.h>
9091 -#include <unistd.h>
9110 ret = kevent(ev->kq_fd,
9119 if (filter == EVFILT_READ) {
9120 bitset_set_bit(ev->kq_bevents, fd);
9123 } else if (e == EVFILT_WRITE) {
9124 events |= FDEVENT_OUT;
9128 e = ev->kq_results[ndx].flags;
9131 @@ -152,10 +151,10 @@
9132 if (-1 == (ev->kq_fd = kqueue())) {
9133 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9134 __FILE__, __LINE__, strerror(errno));
9145 if (-1 == (ev->kq_fd = kqueue())) {
9146 fprintf(stderr, "%s.%d: kqueue failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9147 __FILE__, __LINE__, strerror(errno));
9153 --- ../lighttpd-1.4.11/src/fdevent_linux_rtsig.c 2005-11-21 19:56:11.000000000 +0200
9154 +++ lighttpd-1.4.12/src/fdevent_linux_rtsig.c 2006-07-18 13:03:40.000000000 +0300
9156 #include <sys/types.h>
9158 -#include <unistd.h>
9163 #include "fdevent.h"
9164 #include "settings.h"
9166 +#include "sys-process.h"
9169 #ifdef USE_LINUX_SIGIO
9170 static void fdevent_linux_rtsig_free(fdevents *ev) {
9175 -static int fdevent_linux_rtsig_event_del(fdevents *ev, int fde_ndx, int fd) {
9176 - if (fde_ndx < 0) return -1;
9178 - if ((size_t)fde_ndx >= ev->used) {
9179 - fprintf(stderr, "%s.%d: del! out of range %d %zu\n", __FILE__, __LINE__, fde_ndx, ev->used);
9180 +static int fdevent_linux_rtsig_event_del(fdevents *ev, iosocket *sock) {
9181 + if (sock->fde_ndx < 0) return -1;
9183 + if ((size_t)sock->fde_ndx >= ev->used) {
9184 + TRACE("del! out of range %d %zu\n", sock->fde_ndx, ev->used);
9188 - if (ev->pollfds[fde_ndx].fd == fd) {
9189 - size_t k = fde_ndx;
9192 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9193 + size_t k = sock->fde_ndx;
9195 ev->pollfds[k].fd = -1;
9197 - bitset_clear_bit(ev->sigbset, fd);
9199 + bitset_clear_bit(ev->sigbset, sock->fd);
9201 if (ev->unused.size == 0) {
9202 ev->unused.size = 16;
9203 ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9205 ev->unused.size += 16;
9206 ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9210 ev->unused.ptr[ev->unused.used++] = k;
9212 - fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[fde_ndx].fd, fd);
9214 + fprintf(stderr, "%s.%d: del! %d %d\n", __FILE__, __LINE__, ev->pollfds[sock->fde_ndx].fd, sock->fd);
9220 + sock->fde_ndx = -1;
9226 static int fdevent_linux_rtsig_event_compress(fdevents *ev) {
9230 if (ev->used == 0) return 0;
9231 if (ev->unused.used != 0) return 0;
9234 for (j = ev->used - 1; j + 1 > 0; j--) {
9235 if (ev->pollfds[j].fd == -1) ev->used--;
9245 -static int fdevent_linux_rtsig_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9246 +static int fdevent_linux_rtsig_event_add(fdevents *ev, iosocket *sock, int events) {
9248 - if (fde_ndx != -1) {
9249 - if (ev->pollfds[fde_ndx].fd == fd) {
9250 - ev->pollfds[fde_ndx].events = events;
9253 + if (sock->fde_ndx != -1) {
9254 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9255 + ev->pollfds[sock->fde_ndx].events = events;
9257 + return sock->fde_ndx;
9259 - fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9260 + fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9265 if (ev->unused.used > 0) {
9266 int k = ev->unused.ptr[--ev->unused.used];
9268 - ev->pollfds[k].fd = fd;
9270 + ev->pollfds[k].fd = sock->fd;
9271 ev->pollfds[k].events = events;
9273 - bitset_set_bit(ev->sigbset, fd);
9275 + bitset_set_bit(ev->sigbset, sock->fd);
9279 if (ev->size == 0) {
9280 @@ -102,12 +104,12 @@
9282 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9285 - ev->pollfds[ev->used].fd = fd;
9287 + ev->pollfds[ev->used].fd = sock->fd;
9288 ev->pollfds[ev->used].events = events;
9290 - bitset_set_bit(ev->sigbset, fd);
9292 + bitset_set_bit(ev->sigbset, sock->fd);
9297 @@ -115,20 +117,20 @@
9298 static int fdevent_linux_rtsig_poll(fdevents *ev, int timeout_ms) {
9304 fdevent_linux_rtsig_event_compress(ev);
9311 ts.tv_sec = timeout_ms / 1000;
9312 ts.tv_nsec = (timeout_ms % 1000) * 1000000;
9313 r = sigtimedwait(&(ev->sigset), &(ev->siginfo), &(ts));
9318 if (errno == EAGAIN) return 0;
9321 } else if (r == SIGIO) {
9322 struct sigaction act;
9325 /* re-enable the signal queue */
9326 act.sa_handler = SIG_DFL;
9327 sigaction(ev->signum, &act, NULL);
9331 r = poll(ev->pollfds, ev->used, timeout_ms);
9333 @@ -156,97 +158,67 @@
9337 -static int fdevent_linux_rtsig_event_get_revent(fdevents *ev, size_t ndx) {
9338 +static int fdevent_linux_rtsig_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9339 if (ev->in_sigio == 1) {
9341 - if (ev->siginfo.si_band == POLLERR) {
9342 - fprintf(stderr, "event: %d %02lx %02x %s\n", ev->siginfo.si_fd, ev->siginfo.si_band, errno, strerror(errno));
9346 - fprintf(stderr, "+\n");
9350 - return ev->siginfo.si_band & 0x3f;
9351 + /* only one event */
9353 + fdevent_revents_add(revents, ev->siginfo.si_fd, ev->siginfo.si_band & 0x3f);
9355 - if (ndx >= ev->used) {
9356 - fprintf(stderr, "%s.%d: event: %zu %zu\n", __FILE__, __LINE__, ndx, ev->used);
9360 + for (ndx = 0; ndx < ev->used; ndx++) {
9361 + if (ev->pollfds[ndx].revents) {
9362 + fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9365 - return ev->pollfds[ndx].revents;
9369 -static int fdevent_linux_rtsig_event_get_fd(fdevents *ev, size_t ndx) {
9370 - if (ev->in_sigio == 1) {
9371 - return ev->siginfo.si_fd;
9373 - return ev->pollfds[ndx].fd;
9378 static int fdevent_linux_rtsig_fcntl_set(fdevents *ev, int fd) {
9379 static pid_t pid = 0;
9382 if (pid == 0) pid = getpid();
9385 if (-1 == fcntl(fd, F_SETSIG, ev->signum)) return -1;
9388 if (-1 == fcntl(fd, F_SETOWN, (int) pid)) return -1;
9391 return fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK | O_RDWR);
9395 -static int fdevent_linux_rtsig_event_next_fdndx(fdevents *ev, int ndx) {
9396 - if (ev->in_sigio == 1) {
9397 - if (ndx < 0) return 0;
9402 - i = (ndx < 0) ? 0 : ndx + 1;
9403 - for (; i < ev->used; i++) {
9404 - if (ev->pollfds[i].revents) break;
9411 int fdevent_linux_rtsig_init(fdevents *ev) {
9412 ev->type = FDEVENT_HANDLER_LINUX_RTSIG;
9414 ev->x = fdevent_linux_rtsig_##x;
9424 - SET(event_next_fdndx);
9427 - SET(event_get_fd);
9428 - SET(event_get_revent);
9432 ev->signum = SIGRTMIN + 1;
9435 sigemptyset(&(ev->sigset));
9436 sigaddset(&(ev->sigset), ev->signum);
9437 sigaddset(&(ev->sigset), SIGIO);
9438 if (-1 == sigprocmask(SIG_BLOCK, &(ev->sigset), NULL)) {
9439 fprintf(stderr, "%s.%d: sigprocmask failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9440 __FILE__, __LINE__, strerror(errno));
9449 ev->sigbset = bitset_init(ev->maxfds);
9455 --- ../lighttpd-1.4.11/src/fdevent_linux_sysepoll.c 2005-09-30 20:29:27.000000000 +0300
9456 +++ lighttpd-1.4.12/src/fdevent_linux_sysepoll.c 2006-07-18 13:03:40.000000000 +0300
9458 #include <sys/types.h>
9460 -#include <unistd.h>
9465 #include "fdevent.h"
9466 #include "settings.h"
9470 +#include "sys-files.h"
9472 #ifdef USE_LINUX_EPOLL
9473 static void fdevent_linux_sysepoll_free(fdevents *ev) {
9475 free(ev->epoll_events);
9478 -static int fdevent_linux_sysepoll_event_del(fdevents *ev, int fde_ndx, int fd) {
9479 +static int fdevent_linux_sysepoll_event_del(fdevents *ev, iosocket *sock) {
9480 struct epoll_event ep;
9482 - if (fde_ndx < 0) return -1;
9485 + if (sock->fde_ndx < 0) return -1;
9487 memset(&ep, 0, sizeof(ep));
9491 + ep.data.fd = sock->fd;
9494 - if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, fd, &ep)) {
9496 + if (0 != epoll_ctl(ev->epoll_fd, EPOLL_CTL_DEL, sock->fd, &ep)) {
9497 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9509 + sock->fde_ndx = -1;
9514 -static int fdevent_linux_sysepoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9515 +static int fdevent_linux_sysepoll_event_add(fdevents *ev, iosocket *sock, int events) {
9516 struct epoll_event ep;
9519 - if (fde_ndx == -1) add = 1;
9523 + if (sock->fde_ndx == -1) add = 1;
9525 memset(&ep, 0, sizeof(ep));
9531 if (events & FDEVENT_IN) ep.events |= EPOLLIN;
9532 if (events & FDEVENT_OUT) ep.events |= EPOLLOUT;
9540 ep.events |= EPOLLERR | EPOLLHUP /* | EPOLLET */;
9546 - if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, fd, &ep)) {
9547 + ep.data.fd = sock->fd;
9549 + if (0 != epoll_ctl(ev->epoll_fd, add ? EPOLL_CTL_ADD : EPOLL_CTL_MOD, sock->fd, &ep)) {
9550 fprintf(stderr, "%s.%d: epoll_ctl failed: %s, dying\n", __FILE__, __LINE__, strerror(errno));
9561 + sock->fde_ndx = sock->fd;
9566 static int fdevent_linux_sysepoll_poll(fdevents *ev, int timeout_ms) {
9567 return epoll_wait(ev->epoll_fd, ev->epoll_events, ev->maxfds, timeout_ms);
9570 -static int fdevent_linux_sysepoll_event_get_revent(fdevents *ev, size_t ndx) {
9571 - int events = 0, e;
9573 - e = ev->epoll_events[ndx].events;
9574 - if (e & EPOLLIN) events |= FDEVENT_IN;
9575 - if (e & EPOLLOUT) events |= FDEVENT_OUT;
9576 - if (e & EPOLLERR) events |= FDEVENT_ERR;
9577 - if (e & EPOLLHUP) events |= FDEVENT_HUP;
9578 - if (e & EPOLLPRI) events |= FDEVENT_PRI;
9583 -static int fdevent_linux_sysepoll_event_get_fd(fdevents *ev, size_t ndx) {
9585 - fprintf(stderr, "%s.%d: %d, %d\n", __FILE__, __LINE__, ndx, ev->epoll_events[ndx].data.fd);
9588 - return ev->epoll_events[ndx].data.fd;
9591 -static int fdevent_linux_sysepoll_event_next_fdndx(fdevents *ev, int ndx) {
9595 +static int fdevent_linux_sysepoll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9598 + for (ndx = 0; ndx < event_count; ndx++) {
9599 + int events = 0, e;
9601 + e = ev->epoll_events[ndx].events;
9602 + if (e & EPOLLIN) events |= FDEVENT_IN;
9603 + if (e & EPOLLOUT) events |= FDEVENT_OUT;
9604 + if (e & EPOLLERR) events |= FDEVENT_ERR;
9605 + if (e & EPOLLHUP) events |= FDEVENT_HUP;
9606 + if (e & EPOLLPRI) events |= FDEVENT_PRI;
9608 - i = (ndx < 0) ? 0 : ndx + 1;
9611 + fdevent_revents_add(revents, ev->epoll_events[ndx].data.fd, e);
9617 int fdevent_linux_sysepoll_init(fdevents *ev) {
9618 ev->type = FDEVENT_HANDLER_LINUX_SYSEPOLL;
9620 ev->x = fdevent_linux_sysepoll_##x;
9630 - SET(event_next_fdndx);
9631 - SET(event_get_fd);
9632 - SET(event_get_revent);
9637 if (-1 == (ev->epoll_fd = epoll_create(ev->maxfds))) {
9638 fprintf(stderr, "%s.%d: epoll_create failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
9639 __FILE__, __LINE__, strerror(errno));
9642 fprintf(stderr, "%s.%d: linux-sysepoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
9643 __FILE__, __LINE__);
9649 --- ../lighttpd-1.4.11/src/fdevent_poll.c 2005-11-18 13:59:16.000000000 +0200
9650 +++ lighttpd-1.4.12/src/fdevent_poll.c 2006-07-18 13:03:40.000000000 +0300
9652 #include <sys/types.h>
9654 -#include <unistd.h>
9659 #include "fdevent.h"
9660 #include "settings.h"
9665 static void fdevent_poll_free(fdevents *ev) {
9667 if (ev->unused.ptr) free(ev->unused.ptr);
9670 -static int fdevent_poll_event_del(fdevents *ev, int fde_ndx, int fd) {
9671 - if (fde_ndx < 0) return -1;
9673 - if ((size_t)fde_ndx >= ev->used) {
9674 - fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, fde_ndx, ev->used);
9675 +static int fdevent_poll_event_del(fdevents *ev, iosocket *sock) {
9676 + if (sock->fde_ndx < 0) return -1;
9678 + if ((size_t)sock->fde_ndx >= ev->used) {
9679 + fprintf(stderr, "%s.%d: del! out of range %d %zd\n", __FILE__, __LINE__, sock->fde_ndx, ev->used);
9683 - if (ev->pollfds[fde_ndx].fd == fd) {
9684 - size_t k = fde_ndx;
9687 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9688 + size_t k = sock->fde_ndx;
9690 ev->pollfds[k].fd = -1;
9691 /* ev->pollfds[k].events = 0; */
9692 /* ev->pollfds[k].revents = 0; */
9695 if (ev->unused.size == 0) {
9696 ev->unused.size = 16;
9697 ev->unused.ptr = malloc(sizeof(*(ev->unused.ptr)) * ev->unused.size);
9699 ev->unused.size += 16;
9700 ev->unused.ptr = realloc(ev->unused.ptr, sizeof(*(ev->unused.ptr)) * ev->unused.size);
9704 ev->unused.ptr[ev->unused.used++] = k;
9711 + sock->fde_ndx = -1;
9717 static int fdevent_poll_event_compress(fdevents *ev) {
9721 if (ev->used == 0) return 0;
9722 if (ev->unused.used != 0) return 0;
9725 for (j = ev->used - 1; j + 1 > 0 && ev->pollfds[j].fd == -1; j--) ev->used--;
9732 -static int fdevent_poll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9735 - if (fde_ndx != -1) {
9736 - if (ev->pollfds[fde_ndx].fd == fd) {
9737 - ev->pollfds[fde_ndx].events = events;
9740 +static int fdevent_poll_event_add(fdevents *ev, iosocket *sock, int events) {
9741 + if (sock->fde_ndx != -1) {
9742 + /* this fd was already added, just change the requested events */
9744 + if (ev->pollfds[sock->fde_ndx].fd == sock->fd) {
9745 + ev->pollfds[sock->fde_ndx].events = events;
9747 + return sock->fde_ndx;
9749 - fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, fde_ndx, ev->pollfds[fde_ndx].fd);
9750 + fprintf(stderr, "%s.%d: add: (%d, %d)\n", __FILE__, __LINE__, sock->fde_ndx, ev->pollfds[sock->fde_ndx].fd);
9755 if (ev->unused.used > 0) {
9756 int k = ev->unused.ptr[--ev->unused.used];
9758 - ev->pollfds[k].fd = fd;
9760 + ev->pollfds[k].fd = sock->fd;
9761 ev->pollfds[k].events = events;
9765 + sock->fde_ndx = k;
9768 if (ev->size == 0) {
9772 ev->pollfds = realloc(ev->pollfds, sizeof(*ev->pollfds) * ev->size);
9775 - ev->pollfds[ev->used].fd = fd;
9777 + ev->pollfds[ev->used].fd = sock->fd;
9778 ev->pollfds[ev->used].events = events;
9780 - return ev->used++;
9782 + sock->fde_ndx = ev->used++;
9787 static int fdevent_poll_poll(fdevents *ev, int timeout_ms) {
9788 @@ -105,71 +109,38 @@
9789 return poll(ev->pollfds, ev->used, timeout_ms);
9792 -static int fdevent_poll_event_get_revent(fdevents *ev, size_t ndx) {
9794 - if (ndx >= ev->used) {
9795 - fprintf(stderr, "%s.%d: dying because: event: %zd >= %zd\n", __FILE__, __LINE__, ndx, ev->used);
9802 - if (ev->pollfds[ndx].revents & POLLNVAL) {
9803 - /* should never happen */
9806 +static int fdevent_poll_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9810 - poll_r = ev->pollfds[ndx].revents;
9811 + for (ndx = 0; ndx < ev->used; ndx++) {
9812 + if (ev->pollfds[ndx].revents) {
9813 + if (ev->pollfds[ndx].revents & POLLNVAL) {
9814 + /* should never happen */
9818 - /* map POLL* to FDEVEN_* */
9820 - if (poll_r & POLLIN) r |= FDEVENT_IN;
9821 - if (poll_r & POLLOUT) r |= FDEVENT_OUT;
9822 - if (poll_r & POLLERR) r |= FDEVENT_ERR;
9823 - if (poll_r & POLLHUP) r |= FDEVENT_HUP;
9824 - if (poll_r & POLLNVAL) r |= FDEVENT_NVAL;
9825 - if (poll_r & POLLPRI) r |= FDEVENT_PRI;
9827 - return ev->pollfds[ndx].revents;
9830 -static int fdevent_poll_event_get_fd(fdevents *ev, size_t ndx) {
9831 - return ev->pollfds[ndx].fd;
9834 -static int fdevent_poll_event_next_fdndx(fdevents *ev, int ndx) {
9837 - i = (ndx < 0) ? 0 : ndx + 1;
9838 - for (; i < ev->used; i++) {
9839 - if (ev->pollfds[i].revents) break;
9840 + fdevent_revents_add(revents, ev->pollfds[ndx].fd, ev->pollfds[ndx].revents);
9849 int fdevent_poll_init(fdevents *ev) {
9850 ev->type = FDEVENT_HANDLER_POLL;
9852 ev->x = fdevent_poll_##x;
9862 - SET(event_next_fdndx);
9863 - SET(event_get_fd);
9864 - SET(event_get_revent);
9876 int fdevent_poll_init(fdevents *ev) {
9877 --- ../lighttpd-1.4.11/src/fdevent_select.c 2005-08-31 11:12:46.000000000 +0300
9878 +++ lighttpd-1.4.12/src/fdevent_select.c 2006-07-18 13:03:40.000000000 +0300
9880 -#include <sys/time.h>
9881 #include <sys/types.h>
9883 -#include <unistd.h>
9892 #include "fdevent.h"
9893 #include "settings.h"
9896 +#include "sys-socket.h"
9900 static int fdevent_select_reset(fdevents *ev) {
9901 @@ -24,101 +25,98 @@
9905 -static int fdevent_select_event_del(fdevents *ev, int fde_ndx, int fd) {
9906 - if (fde_ndx < 0) return -1;
9907 +static int fdevent_select_event_del(fdevents *ev, iosocket *sock) {
9908 + if (sock->fde_ndx < 0) return -1;
9910 - FD_CLR(fd, &(ev->select_set_read));
9911 - FD_CLR(fd, &(ev->select_set_write));
9912 - FD_CLR(fd, &(ev->select_set_error));
9913 + FD_CLR(sock->fd, &(ev->select_set_read));
9914 + FD_CLR(sock->fd, &(ev->select_set_write));
9915 + FD_CLR(sock->fd, &(ev->select_set_error));
9919 + /* mark the fdevent as deleted */
9920 + sock->fde_ndx = -1;
9922 -static int fdevent_select_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
9927 +static int fdevent_select_event_add(fdevents *ev, iosocket *sock, int events) {
9928 /* we should be protected by max-fds, but you never know */
9929 - assert(fd < FD_SETSIZE);
9931 + assert(sock->fd < FD_SETSIZE);
9934 if (events & FDEVENT_IN) {
9935 - FD_SET(fd, &(ev->select_set_read));
9936 - FD_CLR(fd, &(ev->select_set_write));
9937 + FD_SET(sock->fd, &(ev->select_set_read));
9938 + FD_CLR(sock->fd, &(ev->select_set_write));
9940 if (events & FDEVENT_OUT) {
9941 - FD_CLR(fd, &(ev->select_set_read));
9942 - FD_SET(fd, &(ev->select_set_write));
9943 + FD_CLR(sock->fd, &(ev->select_set_read));
9944 + FD_SET(sock->fd, &(ev->select_set_write));
9946 - FD_SET(fd, &(ev->select_set_error));
9948 - if (fd > ev->select_max_fd) ev->select_max_fd = fd;
9951 + FD_SET(sock->fd, &(ev->select_set_error));
9953 + /* we need this for the poll */
9954 + if (sock->fd > ev->select_max_fd) ev->select_max_fd = sock->fd;
9956 + /* mark fd as added */
9957 + sock->fde_ndx = sock->fd;
9962 static int fdevent_select_poll(fdevents *ev, int timeout_ms) {
9966 tv.tv_sec = timeout_ms / 1000;
9967 tv.tv_usec = (timeout_ms % 1000) * 1000;
9970 ev->select_read = ev->select_set_read;
9971 ev->select_write = ev->select_set_write;
9972 ev->select_error = ev->select_set_error;
9975 return select(ev->select_max_fd + 1, &(ev->select_read), &(ev->select_write), &(ev->select_error), &tv);
9978 -static int fdevent_select_event_get_revent(fdevents *ev, size_t ndx) {
9981 - if (FD_ISSET(ndx, &(ev->select_read))) {
9982 - revents |= FDEVENT_IN;
9984 + * scan the fdset for events
9986 +static int fdevent_select_get_revents(fdevents *ev, size_t event_count, fdevent_revents *revents) {
9990 + for (ndx = 0; ndx < ev->select_max_fd; ndx++) {
9993 + if (FD_ISSET(ndx, &(ev->select_read))) {
9994 + events |= FDEVENT_IN;
9996 + if (FD_ISSET(ndx, &(ev->select_write))) {
9997 + events |= FDEVENT_OUT;
9999 + if (FD_ISSET(ndx, &(ev->select_error))) {
10000 + events |= FDEVENT_ERR;
10004 + fdevent_revents_add(revents, ndx, events);
10007 - if (FD_ISSET(ndx, &(ev->select_write))) {
10008 - revents |= FDEVENT_OUT;
10010 - if (FD_ISSET(ndx, &(ev->select_error))) {
10011 - revents |= FDEVENT_ERR;
10017 -static int fdevent_select_event_get_fd(fdevents *ev, size_t ndx) {
10023 -static int fdevent_select_event_next_fdndx(fdevents *ev, int ndx) {
10026 - i = (ndx < 0) ? 0 : ndx + 1;
10028 - for (; i < ev->select_max_fd + 1; i++) {
10029 - if (FD_ISSET(i, &(ev->select_read))) break;
10030 - if (FD_ISSET(i, &(ev->select_write))) break;
10031 - if (FD_ISSET(i, &(ev->select_error))) break;
10038 int fdevent_select_init(fdevents *ev) {
10039 ev->type = FDEVENT_HANDLER_SELECT;
10041 ev->x = fdevent_select_##x;
10051 - SET(event_next_fdndx);
10052 - SET(event_get_fd);
10053 - SET(event_get_revent);
10056 + SET(get_revents);
10061 --- ../lighttpd-1.4.11/src/fdevent_solaris_devpoll.c 2005-09-01 10:45:26.000000000 +0300
10062 +++ lighttpd-1.4.12/src/fdevent_solaris_devpoll.c 2006-07-16 00:26:03.000000000 +0300
10064 #include <sys/types.h>
10066 -#include <unistd.h>
10067 #include <stdlib.h>
10069 #include <string.h>
10070 @@ -23,55 +22,55 @@
10072 static int fdevent_solaris_devpoll_event_del(fdevents *ev, int fde_ndx, int fd) {
10076 if (fde_ndx < 0) return -1;
10080 pfd.events = POLLREMOVE;
10084 if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10085 - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10086 - __FILE__, __LINE__,
10087 + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10088 + __FILE__, __LINE__,
10089 fd, strerror(errno));
10099 static int fdevent_solaris_devpoll_event_add(fdevents *ev, int fde_ndx, int fd, int events) {
10104 if (fde_ndx == -1) add = 1;
10108 pfd.events = events;
10112 if (-1 == write(ev->devpoll_fd, &pfd, sizeof(pfd))) {
10113 - fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10114 - __FILE__, __LINE__,
10115 + fprintf(stderr, "%s.%d: (del) write failed: (%d, %s)\n",
10116 + __FILE__, __LINE__,
10117 fd, strerror(errno));
10127 static int fdevent_solaris_devpoll_poll(fdevents *ev, int timeout_ms) {
10128 struct dvpoll dopoll;
10132 dopoll.dp_timeout = timeout_ms;
10133 dopoll.dp_nfds = ev->maxfds;
10134 dopoll.dp_fds = ev->devpollfds;
10137 ret = ioctl(ev->devpoll_fd, DP_POLL, &dopoll);
10143 @@ -85,11 +84,11 @@
10145 static int fdevent_solaris_devpoll_event_next_fdndx(fdevents *ev, int last_ndx) {
10151 i = (last_ndx < 0) ? 0 : last_ndx + 1;
10157 @@ -117,20 +116,20 @@
10158 ev->type = FDEVENT_HANDLER_SOLARIS_DEVPOLL;
10160 ev->x = fdevent_solaris_devpoll_##x;
10172 SET(event_next_fdndx);
10174 SET(event_get_revent);
10177 ev->devpollfds = malloc(sizeof(*ev->devpollfds) * ev->maxfds);
10180 if ((ev->devpoll_fd = open("/dev/poll", O_RDWR)) < 0) {
10181 fprintf(stderr, "%s.%d: opening /dev/poll failed (%s), try to set server.event-handler = \"poll\" or \"select\"\n",
10182 __FILE__, __LINE__, strerror(errno));
10183 @@ -152,7 +151,7 @@
10185 fprintf(stderr, "%s.%d: solaris-devpoll not supported, try to set server.event-handler = \"poll\" or \"select\"\n",
10186 __FILE__, __LINE__);
10192 --- ../lighttpd-1.4.11/src/http-header-glue.c 2006-02-08 15:31:36.000000000 +0200
10193 +++ lighttpd-1.4.12/src/http-header-glue.c 2006-07-18 13:03:40.000000000 +0300
10194 @@ -45,20 +45,20 @@
10195 # ifdef HAVE_STRUCT_SOCKADDR_STORAGE
10196 static size_t get_sa_len(const struct sockaddr *addr) {
10197 switch (addr->sa_family) {
10202 return (sizeof (struct sockaddr_in));
10208 return (sizeof (struct sockaddr_in6));
10213 return (sizeof (struct sockaddr));
10218 # define SA_LEN(addr) (get_sa_len(addr))
10221 int response_header_insert(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10227 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
10228 @@ -82,32 +82,32 @@
10230 buffer_copy_string_len(ds->key, key, keylen);
10231 buffer_copy_string_len(ds->value, value, vallen);
10234 array_insert_unique(con->response.headers, (data_unset *)ds);
10240 int response_header_overwrite(server *srv, connection *con, const char *key, size_t keylen, const char *value, size_t vallen) {
10246 /* if there already is a key by this name overwrite the value */
10247 if (NULL != (ds = (data_string *)array_get_element(con->response.headers, key))) {
10248 buffer_copy_string(ds->value, value);
10255 return response_header_insert(srv, con, key, keylen, value, vallen);
10258 int http_response_redirect_to_directory(server *srv, connection *con) {
10265 if (con->conf.is_ssl) {
10266 buffer_copy_string(o, "https://");
10268 @@ -123,36 +123,36 @@
10270 sock_addr our_addr;
10271 socklen_t our_addr_len;
10274 our_addr_len = sizeof(our_addr);
10276 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
10278 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
10279 con->http_status = 500;
10282 log_error_write(srv, __FILE__, __LINE__, "ss",
10283 "can't get sockname", strerror(errno));
10293 /* Lookup name: secondly try to get hostname for bind address */
10294 switch(our_addr.plain.sa_family) {
10297 - if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10298 - SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10299 + if (0 != getnameinfo((const struct sockaddr *)(&our_addr.ipv6),
10300 + SA_LEN((const struct sockaddr *)&our_addr.ipv6),
10301 hbuf, sizeof(hbuf), NULL, 0, 0)) {
10304 char dst[INET6_ADDRSTRLEN];
10307 log_error_write(srv, __FILE__, __LINE__,
10308 "SSSS", "NOTICE: getnameinfo failed: ",
10309 strerror(errno), ", using ip-address instead");
10311 - buffer_append_string(o,
10312 - inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10314 + buffer_append_string(o,
10315 + inet_ntop(AF_INET6, (char *)&our_addr.ipv6.sin6_addr,
10316 dst, sizeof(dst)));
10318 buffer_append_string(o, hbuf);
10319 @@ -164,7 +164,7 @@
10320 log_error_write(srv, __FILE__, __LINE__,
10321 "SdSS", "NOTICE: gethostbyaddr failed: ",
10322 h_errno, ", using ip-address instead");
10325 buffer_append_string(o, inet_ntoa(our_addr.ipv4.sin_addr));
10327 buffer_append_string(o, he->h_name);
10328 @@ -173,12 +173,12 @@
10330 log_error_write(srv, __FILE__, __LINE__,
10331 "S", "ERROR: unsupported address-type");
10338 - if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10340 + if (!((con->conf.is_ssl == 0 && srv->srvconf.port == 80) ||
10341 (con->conf.is_ssl == 1 && srv->srvconf.port == 443))) {
10342 buffer_append_string(o, ":");
10343 buffer_append_long(o, srv->srvconf.port);
10344 @@ -190,41 +190,41 @@
10345 buffer_append_string(o, "?");
10346 buffer_append_string_buffer(o, con->uri.query);
10350 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(o));
10353 con->http_status = 301;
10354 con->file_finished = 1;
10363 buffer * strftime_cache_get(server *srv, time_t last_mod) {
10368 for (i = 0; i < FILE_CACHE_MAX; i++) {
10369 /* found cache-entry */
10370 if (srv->mtime_cache[i].mtime == last_mod) return srv->mtime_cache[i].str;
10373 /* found empty slot */
10374 if (srv->mtime_cache[i].mtime == 0) break;
10378 if (i == FILE_CACHE_MAX) {
10383 srv->mtime_cache[i].mtime = last_mod;
10384 buffer_prepare_copy(srv->mtime_cache[i].str, 1024);
10385 tm = gmtime(&(srv->mtime_cache[i].mtime));
10386 - srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10387 + srv->mtime_cache[i].str->used = strftime(srv->mtime_cache[i].str->ptr,
10388 srv->mtime_cache[i].str->size - 1,
10389 "%a, %d %b %Y %H:%M:%S GMT", tm);
10390 srv->mtime_cache[i].str->used++;
10393 return srv->mtime_cache[i].str;
10396 @@ -239,56 +239,60 @@
10397 * request. That is, if no entity tags match, then the server MUST NOT
10398 * return a 304 (Not Modified) response.
10402 /* last-modified handling */
10403 if (con->request.http_if_none_match) {
10404 if (etag_is_equal(con->physical.etag, con->request.http_if_none_match)) {
10405 - if (con->request.http_method == HTTP_METHOD_GET ||
10406 + if (con->request.http_method == HTTP_METHOD_GET ||
10407 con->request.http_method == HTTP_METHOD_HEAD) {
10410 /* check if etag + last-modified */
10411 if (con->request.http_if_modified_since) {
10416 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10417 used_len = strlen(con->request.http_if_modified_since);
10419 used_len = semicolon - con->request.http_if_modified_since;
10423 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10424 con->http_status = 304;
10425 return HANDLER_FINISHED;
10427 +#ifdef HAVE_STRPTIME
10428 char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10429 + time_t t_header, t_file;
10432 - /* convert to timestamp */
10433 - if (used_len < sizeof(buf)) {
10434 - time_t t_header, t_file;
10437 - strncpy(buf, con->request.http_if_modified_since, used_len);
10438 - buf[used_len] = '\0';
10440 - strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10441 - t_header = mktime(&tm);
10443 - strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10444 - t_file = mktime(&tm);
10446 - if (t_file > t_header) {
10447 - con->http_status = 304;
10448 - return HANDLER_FINISHED;
10451 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
10452 - "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10453 + /* check if we can safely copy the string */
10454 + if (used_len >= sizeof(buf)) {
10455 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
10456 + "DEBUG: Last-Modified check failed as the received timestamp was too long:",
10457 con->request.http_if_modified_since, used_len, sizeof(buf) - 1);
10460 con->http_status = 412;
10461 return HANDLER_FINISHED;
10465 + strncpy(buf, con->request.http_if_modified_since, used_len);
10466 + buf[used_len] = '\0';
10468 + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10469 + t_header = mktime(&tm);
10471 + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10472 + t_file = mktime(&tm);
10474 + if (t_file > t_header) return HANDLER_GO_ON;
10476 + con->http_status = 304;
10477 + return HANDLER_FINISHED;
10479 + return HANDLER_GO_ON;
10483 con->http_status = 304;
10484 @@ -302,16 +306,41 @@
10485 } else if (con->request.http_if_modified_since) {
10490 if (NULL == (semicolon = strchr(con->request.http_if_modified_since, ';'))) {
10491 used_len = strlen(con->request.http_if_modified_since);
10493 used_len = semicolon - con->request.http_if_modified_since;
10497 if (0 == strncmp(con->request.http_if_modified_since, mtime->ptr, used_len)) {
10498 con->http_status = 304;
10499 return HANDLER_FINISHED;
10501 +#ifdef HAVE_STRPTIME
10502 + char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
10503 + time_t t_header, t_file;
10506 + /* convert to timestamp */
10507 + if (used_len >= sizeof(buf)) return HANDLER_GO_ON;
10509 + strncpy(buf, con->request.http_if_modified_since, used_len);
10510 + buf[used_len] = '\0';
10512 + strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10513 + t_header = mktime(&tm);
10515 + strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm);
10516 + t_file = mktime(&tm);
10518 + if (t_file > t_header) return HANDLER_GO_ON;
10520 + con->http_status = 304;
10521 + return HANDLER_FINISHED;
10523 + return HANDLER_GO_ON;
10528 --- ../lighttpd-1.4.11/src/http_auth.c 2006-02-01 13:02:52.000000000 +0200
10529 +++ lighttpd-1.4.12/src/http_auth.c 2006-07-18 13:03:40.000000000 +0300
10531 #include <string.h>
10534 -#include <unistd.h>
10537 #include "server.h"
10538 @@ -31,23 +30,14 @@
10539 #include "http_auth_digest.h"
10540 #include "stream.h"
10542 +#include "sys-strings.h"
10545 # include <openssl/md5.h>
10552 -#include <security/pam_appl.h>
10553 -#include <security/pam_misc.h>
10555 -static struct pam_conv conv = {
10561 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
10563 static const char base64_pad = '=';
10564 @@ -75,25 +65,25 @@
10565 unsigned char *result;
10570 size_t in_len = strlen(in);
10573 buffer_prepare_copy(out, in_len);
10576 result = (unsigned char *)out->ptr;
10580 /* run through the whole string, converting as we go */
10581 for (i = 0; i < in_len; i++) {
10585 if (ch == '\0') break;
10588 if (ch == base64_pad) break;
10591 ch = base64_reverse_table[ch];
10592 if (ch < 0) continue;
10597 result[j] = ch << 2;
10598 @@ -125,168 +115,168 @@
10610 static int http_auth_get_password(server *srv, mod_auth_plugin_data *p, buffer *username, buffer *realm, buffer *password) {
10614 if (!username->used|| !realm->used) return -1;
10617 if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10622 if (buffer_is_empty(p->conf.auth_htdigest_userfile)) return -1;
10625 if (0 != stream_open(&f, p->conf.auth_htdigest_userfile)) {
10626 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening digest-userfile", p->conf.auth_htdigest_userfile, "failed:", strerror(errno));
10636 while (f_line - f.start != f.size) {
10637 char *f_user, *f_pwd, *e, *f_realm;
10638 size_t u_len, pwd_len, r_len;
10648 - * user:realm:md5(user:realm:password)
10650 + * user:realm:md5(user:realm:password)
10654 if (NULL == (f_realm = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10655 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10656 - "parsed error in", p->conf.auth_htdigest_userfile,
10657 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10658 + "parsed error in", p->conf.auth_htdigest_userfile,
10659 "expected 'username:realm:hashed password'");
10669 if (NULL == (f_pwd = memchr(f_realm + 1, ':', f.size - (f_realm + 1 - f.start)))) {
10670 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10671 - "parsed error in", p->conf.auth_plain_userfile,
10672 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10673 + "parsed error in", p->conf.auth_plain_userfile,
10674 "expected 'username:realm:hashed password'");
10684 /* get pointers to the fields */
10685 - u_len = f_realm - f_user;
10686 + u_len = f_realm - f_user;
10688 r_len = f_pwd - f_realm;
10692 if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10693 pwd_len = e - f_pwd;
10695 pwd_len = f.size - (f_pwd - f.start);
10699 if (username->used - 1 == u_len &&
10700 (realm->used - 1 == r_len) &&
10701 (0 == strncmp(username->ptr, f_user, u_len)) &&
10702 (0 == strncmp(realm->ptr, f_realm, r_len))) {
10706 buffer_copy_string_len(password, f_pwd, pwd_len);
10723 } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD ||
10724 p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
10730 auth_fn = (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) ? p->conf.auth_htpasswd_userfile : p->conf.auth_plain_userfile;
10733 if (buffer_is_empty(auth_fn)) return -1;
10736 if (0 != stream_open(&f, auth_fn)) {
10737 - log_error_write(srv, __FILE__, __LINE__, "sbss",
10738 + log_error_write(srv, __FILE__, __LINE__, "sbss",
10739 "opening plain-userfile", auth_fn, "failed:", strerror(errno));
10749 while (f_line - f.start != f.size) {
10750 char *f_user, *f_pwd, *e;
10751 size_t u_len, pwd_len;
10762 * user:crypted passwd
10766 if (NULL == (f_pwd = memchr(f_user, ':', f.size - (f_user - f.start) ))) {
10767 - log_error_write(srv, __FILE__, __LINE__, "sbs",
10768 - "parsed error in", auth_fn,
10769 + log_error_write(srv, __FILE__, __LINE__, "sbs",
10770 + "parsed error in", auth_fn,
10771 "expected 'username:hashed password'");
10781 /* get pointers to the fields */
10782 - u_len = f_pwd - f_user;
10783 + u_len = f_pwd - f_user;
10787 if (NULL != (e = memchr(f_pwd, '\n', f.size - (f_pwd - f.start)))) {
10788 pwd_len = e - f_pwd;
10790 pwd_len = f.size - (f_pwd - f.start);
10794 if (username->used - 1 == u_len &&
10795 (0 == strncmp(username->ptr, f_user, u_len))) {
10799 buffer_copy_string_len(password, f_pwd, pwd_len);
10816 } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
10826 @@ -296,7 +286,7 @@
10828 data_string *require;
10835 @@ -304,12 +294,12 @@
10836 /* search auth-directives for path */
10837 for (i = 0; i < p->conf.auth_require->used; i++) {
10838 if (p->conf.auth_require->data[i]->key->used == 0) continue;
10841 if (0 == strncmp(url, p->conf.auth_require->data[i]->key->ptr, p->conf.auth_require->data[i]->key->used - 1)) {
10847 if (i == p->conf.auth_require->used) {
10850 @@ -317,72 +307,72 @@
10851 req = ((data_array *)(p->conf.auth_require->data[i]))->value;
10853 require = (data_string *)array_get_element(req, "require");
10856 /* if we get here, the user we got a authed user */
10857 - if (0 == strcmp(require->value->ptr, "valid-user")) {
10858 + if (buffer_is_equal_string(require->value, CONST_STR_LEN("valid-user"))) {
10863 /* user=name1|group=name3|host=name4 */
10866 /* seperate the string by | */
10868 log_error_write(srv, __FILE__, __LINE__, "sb", "rules", require->value);
10873 username_len = username ? strlen(username) : 0;
10876 r = rules = require->value->ptr;
10881 const char *k, *v, *e;
10882 int k_len, v_len, r_len;
10885 e = strchr(r, '|');
10891 r_len = strlen(rules) - (r - rules);
10895 /* from r to r + r_len is a rule */
10898 if (0 == strncmp(r, "valid-user", r_len)) {
10899 - log_error_write(srv, __FILE__, __LINE__, "sb",
10900 + log_error_write(srv, __FILE__, __LINE__, "sb",
10901 "parsing the 'require' section in 'auth.require' failed: valid-user cannot be combined with other require rules",
10907 /* search for = in the rules */
10908 if (NULL == (eq = strchr(r, '='))) {
10909 - log_error_write(srv, __FILE__, __LINE__, "sb",
10910 - "parsing the 'require' section in 'auth.require' failed: a = is missing",
10911 + log_error_write(srv, __FILE__, __LINE__, "sb",
10912 + "parsing the 'require' section in 'auth.require' failed: a = is missing",
10918 /* = out of range */
10919 if (eq > r + r_len) {
10920 - log_error_write(srv, __FILE__, __LINE__, "sb",
10921 + log_error_write(srv, __FILE__, __LINE__, "sb",
10922 "parsing the 'require' section in 'auth.require' failed: = out of range",
10930 /* the part before the = is user|group|host */
10936 v_len = r_len - k_len - 1;
10940 if (0 == strncmp(k, "user", k_len)) {
10943 username_len == v_len &&
10944 0 == strncmp(username, v, v_len)) {
10946 @@ -404,19 +394,19 @@
10947 log_error_write(srv, __FILE__, __LINE__, "s", "unknown key");
10957 log_error_write(srv, __FILE__, __LINE__, "s", "nothing matched");
10968 * @param password password-string from the auth-backend
10969 * @param pw password-string from the client
10971 @@ -426,16 +416,16 @@
10974 if (p->conf.auth_backend == AUTH_BACKEND_HTDIGEST) {
10979 - * user:realm:md5(user:realm:password)
10981 + * user:realm:md5(user:realm:password)
10991 MD5_Update(&Md5Ctx, (unsigned char *)username->ptr, username->used - 1);
10992 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
10993 @@ -443,24 +433,24 @@
10994 MD5_Update(&Md5Ctx, (unsigned char *)":", 1);
10995 MD5_Update(&Md5Ctx, (unsigned char *)pw, strlen(pw));
10996 MD5_Final(HA1, &Md5Ctx);
11001 - if (0 == strcmp(password->ptr, a1)) {
11003 + if (buffer_is_equal_string(password, a1, strlen(a1))) {
11006 - } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11008 + } else if (p->conf.auth_backend == AUTH_BACKEND_HTPASSWD) {
11012 size_t salt_len = 0;
11018 * user:crypted password
11024 * CRYPT_STD_DES 2-character (Default)
11025 * CRYPT_EXT_DES 9-character
11026 @@ -478,7 +468,7 @@
11028 } else if (password->ptr[0] == '$' && password->ptr[2] == '$') {
11029 char *dollar = NULL;
11032 if (NULL == (dollar = strchr(password->ptr + 3, '$'))) {
11033 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11035 @@ -495,48 +485,21 @@
11036 strncpy(salt, password->ptr, salt_len);
11038 salt[salt_len] = '\0';
11041 crypted = crypt(pw, salt);
11043 - if (0 == strcmp(password->ptr, crypted)) {
11044 + if (buffer_is_equal_string(password, crypted, strlen(crypted))) {
11047 fprintf(stderr, "%s.%d\n", __FILE__, __LINE__);
11051 - } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11052 - if (0 == strcmp(password->ptr, pw)) {
11055 - } else if (p->conf.auth_backend == AUTH_BACKEND_PAM) {
11057 - pam_handle_t *pamh=NULL;
11060 - retval = pam_start("lighttpd", username->ptr, &conv, &pamh);
11062 - if (retval == PAM_SUCCESS)
11063 - retval = pam_authenticate(pamh, 0); /* is user really user? */
11065 - if (retval == PAM_SUCCESS)
11066 - retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
11068 - /* This is where we have been authorized or not. */
11070 - if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
11072 - log_error_write(srv, __FILE__, __LINE__, "s", "failed to release authenticator");
11075 - if (retval == PAM_SUCCESS) {
11076 - log_error_write(srv, __FILE__, __LINE__, "s", "Authenticated");
11079 + } else if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11080 + if (buffer_is_equal_string(password, pw, strlen(pw))) {
11083 - log_error_write(srv, __FILE__, __LINE__, "s", "Not Authenticated");
11086 - } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11087 + } else if (p->conf.auth_backend == AUTH_BACKEND_LDAP) {
11090 LDAPMessage *lm, *first;
11091 @@ -544,45 +507,45 @@
11093 char *attrs[] = { LDAP_NO_ATTRS, NULL };
11097 /* for now we stay synchronous */
11102 * 1. connect anonymously (done in plugin init)
11103 * 2. get DN for uid = username
11104 * 3. auth against ldap server
11105 * 4. (optional) check a field
11115 * we have to protect us againt username which modifies out filter in
11120 for (i = 0; i < username->used - 1; i++) {
11121 char c = username->ptr[i];
11127 - log_error_write(srv, __FILE__, __LINE__, "sbd",
11129 + log_error_write(srv, __FILE__, __LINE__, "sbd",
11130 "ldap: invalid character (a-zA-Z0-9 allowed) in username:", username, i);
11143 buffer_copy_string_buffer(p->ldap_filter, p->conf.ldap_filter_pre);
11144 buffer_append_string_buffer(p->ldap_filter, username);
11145 buffer_append_string_buffer(p->ldap_filter, p->conf.ldap_filter_post);
11151 if (p->conf.ldap == NULL ||
11152 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))) {
11153 @@ -590,71 +553,71 @@
11155 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))) {
11157 - log_error_write(srv, __FILE__, __LINE__, "sssb",
11158 + log_error_write(srv, __FILE__, __LINE__, "sssb",
11159 "ldap:", ldap_err2string(ret), "filter:", p->ldap_filter);
11167 if (NULL == (first = ldap_first_entry(p->conf.ldap, lm))) {
11168 log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11178 if (NULL == (dn = ldap_get_dn(p->conf.ldap, first))) {
11179 log_error_write(srv, __FILE__, __LINE__, "s", "ldap ...");
11195 if (NULL == (ldap = ldap_init(p->conf.auth_ldap_hostname->ptr, LDAP_PORT))) {
11196 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
11201 ret = LDAP_VERSION3;
11202 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
11203 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11206 ldap_unbind_s(ldap);
11213 if (p->conf.auth_ldap_starttls == 1) {
11214 if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(ldap, NULL, NULL))) {
11215 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
11218 ldap_unbind_s(ldap);
11227 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(ldap, dn, pw))) {
11228 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
11231 ldap_unbind_s(ldap);
11239 ldap_unbind_s(ldap);
11242 /* everything worked, good, access granted */
11248 @@ -664,65 +627,65 @@
11249 int http_auth_basic_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11250 buffer *username, *password;
11254 data_string *realm;
11257 realm = (data_string *)array_get_element(req, "realm");
11260 username = buffer_init();
11261 password = buffer_init();
11264 base64_decode(username, realm_str);
11267 /* r2 == user:password */
11268 if (NULL == (pw = strchr(username->ptr, ':'))) {
11269 buffer_free(username);
11272 log_error_write(srv, __FILE__, __LINE__, "sb", ": is missing in", username);
11282 username->used = pw - username->ptr;
11285 /* copy password to r1 */
11286 if (http_auth_get_password(srv, p, username, realm->value, password)) {
11287 buffer_free(username);
11288 buffer_free(password);
11291 log_error_write(srv, __FILE__, __LINE__, "s", "get_password failed");
11298 /* password doesn't match */
11299 if (http_auth_basic_password_compare(srv, p, req, username, realm->value, password, pw)) {
11300 log_error_write(srv, __FILE__, __LINE__, "sbb", "password doesn't match for", con->uri.path, username);
11303 buffer_free(username);
11304 buffer_free(password);
11311 /* value is our allow-rules */
11312 if (http_auth_match_rules(srv, p, url->ptr, username->ptr, NULL, NULL)) {
11313 buffer_free(username);
11314 buffer_free(password);
11317 log_error_write(srv, __FILE__, __LINE__, "s", "rules didn't match");
11324 /* remember the username */
11325 buffer_copy_string_buffer(p->auth_user, username);
11328 buffer_free(username);
11329 buffer_free(password);
11335 @@ -735,7 +698,7 @@
11336 int http_auth_digest_check(server *srv, connection *con, mod_auth_plugin_data *p, array *req, buffer *url, const char *realm_str) {
11344 @@ -745,18 +708,18 @@
11351 const char *m = NULL;
11353 buffer *password, *b, *username_buf, *realm_buf;
11364 /* init pointers */
11366 @@ -771,11 +734,11 @@
11369 { S("response=") },
11377 dkv[0].ptr = &username;
11378 dkv[1].ptr = &realm;
11379 dkv[2].ptr = &nonce;
11380 @@ -786,24 +749,24 @@
11382 dkv[8].ptr = &respons;
11389 for (i = 0; dkv[i].key; i++) {
11390 *(dkv[i].ptr) = NULL;
11396 if (p->conf.auth_backend != AUTH_BACKEND_HTDIGEST &&
11397 p->conf.auth_backend != AUTH_BACKEND_PLAIN) {
11398 - log_error_write(srv, __FILE__, __LINE__, "s",
11399 + log_error_write(srv, __FILE__, __LINE__, "s",
11400 "digest: unsupported backend (only htdigest or plain)");
11407 b = buffer_init_string(realm_str);
11410 /* parse credentials from client */
11411 for (c = b->ptr; *c; c++) {
11412 /* skip whitespaces */
11413 @@ -812,18 +775,18 @@
11415 for (i = 0; dkv[i].key; i++) {
11416 if ((0 == strncmp(c, dkv[i].key, dkv[i].key_len))) {
11417 - if ((c[dkv[i].key_len] == '"') &&
11418 + if ((c[dkv[i].key_len] == '"') &&
11419 (NULL != (e = strchr(c + dkv[i].key_len + 1, '"')))) {
11420 /* value with "..." */
11421 *(dkv[i].ptr) = c + dkv[i].key_len + 1;
11426 } else if (NULL != (e = strchr(c + dkv[i].key_len, ','))) {
11427 /* value without "...", terminated by ',' */
11428 *(dkv[i].ptr) = c + dkv[i].key_len;
11434 /* value without "...", terminated by EOL */
11435 @@ -833,7 +796,7 @@
11441 if (p->conf.auth_debug > 1) {
11442 log_error_write(srv, __FILE__, __LINE__, "ss", "username", username);
11443 log_error_write(srv, __FILE__, __LINE__, "ss", "realm", realm);
11444 @@ -845,22 +808,22 @@
11445 log_error_write(srv, __FILE__, __LINE__, "ss", "nc", nc);
11446 log_error_write(srv, __FILE__, __LINE__, "ss", "response", respons);
11450 /* check if everything is transmitted */
11456 (qop && (!nc || !cnonce)) ||
11458 /* missing field */
11460 - log_error_write(srv, __FILE__, __LINE__, "s",
11462 + log_error_write(srv, __FILE__, __LINE__, "s",
11463 "digest: missing field");
11467 - m = get_http_method_name(con->request.http_method);
11468 + m = get_http_method_name(con->request.http_method);
11470 /* password-string == HA1 */
11471 password = buffer_init();
11472 @@ -873,10 +836,10 @@
11473 buffer_free(realm_buf);
11478 buffer_free(username_buf);
11479 buffer_free(realm_buf);
11482 if (p->conf.auth_backend == AUTH_BACKEND_PLAIN) {
11483 /* generate password from plain-text */
11485 @@ -890,16 +853,16 @@
11487 /* transform the 32-byte-hex-md5 to a 16-byte-md5 */
11488 for (i = 0; i < HASHLEN; i++) {
11489 - HA1[i] = hex2int(password->ptr[i*2]) << 4;
11490 - HA1[i] |= hex2int(password->ptr[i*2+1]);
11491 + HA1[i] = hex2int(password->ptr[i*2]) << 4;
11492 + HA1[i] |= hex2int(password->ptr[i*2+1]);
11495 /* we already check that above */
11500 buffer_free(password);
11504 strcasecmp(algorithm, "md5-sess") == 0) {
11506 @@ -910,9 +873,9 @@
11507 MD5_Update(&Md5Ctx, (unsigned char *)cnonce, strlen(cnonce));
11508 MD5_Final(HA1, &Md5Ctx);
11515 /* calculate H(A2) */
11517 MD5_Update(&Md5Ctx, (unsigned char *)m, strlen(m));
11518 @@ -924,7 +887,7 @@
11520 MD5_Final(HA2, &Md5Ctx);
11521 CvtHex(HA2, HA2Hex);
11524 /* calculate response */
11526 MD5_Update(&Md5Ctx, (unsigned char *)a1, HASHHEXLEN);
11527 @@ -942,39 +905,39 @@
11528 MD5_Update(&Md5Ctx, (unsigned char *)HA2Hex, HASHHEXLEN);
11529 MD5_Final(RespHash, &Md5Ctx);
11530 CvtHex(RespHash, a2);
11533 if (0 != strcmp(a2, respons)) {
11534 /* digest not ok */
11537 if (p->conf.auth_debug) {
11538 - log_error_write(srv, __FILE__, __LINE__, "sss",
11539 + log_error_write(srv, __FILE__, __LINE__, "sss",
11540 "digest: digest mismatch", a2, respons);
11543 - log_error_write(srv, __FILE__, __LINE__, "sss",
11545 + log_error_write(srv, __FILE__, __LINE__, "sss",
11546 "digest: auth failed for", username, "wrong password");
11554 /* value is our allow-rules */
11555 if (http_auth_match_rules(srv, p, url->ptr, username, NULL, NULL)) {
11558 - log_error_write(srv, __FILE__, __LINE__, "s",
11560 + log_error_write(srv, __FILE__, __LINE__, "s",
11561 "digest: rules did match");
11568 /* remember the username */
11569 buffer_copy_string(p->auth_user, username);
11575 if (p->conf.auth_debug) {
11576 - log_error_write(srv, __FILE__, __LINE__, "s",
11577 + log_error_write(srv, __FILE__, __LINE__, "s",
11578 "digest: auth ok");
11581 @@ -985,23 +948,23 @@
11589 /* generate shared-secret */
11591 MD5_Update(&Md5Ctx, (unsigned char *)fn->ptr, fn->used - 1);
11592 MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
11595 /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
11596 ltostr(hh, srv->cur_ts);
11597 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11598 ltostr(hh, rand());
11599 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
11602 MD5_Final(h, &Md5Ctx);
11610 --- ../lighttpd-1.4.11/src/http_auth.h 2005-08-14 17:12:31.000000000 +0300
11611 +++ lighttpd-1.4.12/src/http_auth.h 2006-07-16 00:26:04.000000000 +0300
11616 -typedef enum { AUTH_BACKEND_UNSET, AUTH_BACKEND_PLAIN,
11617 - AUTH_BACKEND_LDAP, AUTH_BACKEND_HTPASSWD,
11618 - AUTH_BACKEND_HTDIGEST, AUTH_BACKEND_PAM } auth_backend_t;
11620 + AUTH_BACKEND_UNSET,
11621 + AUTH_BACKEND_PLAIN,
11622 + AUTH_BACKEND_LDAP,
11623 + AUTH_BACKEND_HTPASSWD,
11624 + AUTH_BACKEND_HTDIGEST
11629 array *auth_require;
11632 buffer *auth_plain_groupfile;
11633 buffer *auth_plain_userfile;
11636 buffer *auth_htdigest_userfile;
11637 buffer *auth_htpasswd_userfile;
11640 buffer *auth_backend_conf;
11643 buffer *auth_ldap_hostname;
11644 buffer *auth_ldap_basedn;
11645 buffer *auth_ldap_binddn;
11646 @@ -32,15 +36,15 @@
11647 buffer *auth_ldap_filter;
11648 buffer *auth_ldap_cafile;
11649 unsigned short auth_ldap_starttls;
11652 unsigned short auth_debug;
11656 auth_backend_t auth_backend;
11663 buffer *ldap_filter_pre;
11664 buffer *ldap_filter_post;
11666 @@ -49,15 +53,15 @@
11675 buffer *ldap_filter;
11679 mod_auth_plugin_config **config_storage;
11682 mod_auth_plugin_config conf; /* this is only used as long as no handler_ctx is setup */
11683 } mod_auth_plugin_data;
11685 --- ../lighttpd-1.4.11/src/http_auth_digest.h 2006-01-05 00:54:01.000000000 +0200
11686 +++ lighttpd-1.4.12/src/http_auth_digest.h 2006-07-16 00:26:04.000000000 +0300
11696 --- ../lighttpd-1.4.11/src/http_chunk.c 2005-08-11 01:26:50.000000000 +0300
11697 +++ lighttpd-1.4.12/src/http_chunk.c 2006-07-16 00:26:04.000000000 +0300
11700 * the HTTP chunk-API
11707 #include <sys/types.h>
11710 #include <stdlib.h>
11712 -#include <unistd.h>
11716 @@ -23,19 +22,19 @@
11717 static int http_chunk_append_len(server *srv, connection *con, size_t len) {
11718 size_t i, olen = len, j;
11722 b = srv->tmp_chunk_len;
11726 buffer_copy_string(b, "0");
11728 for (i = 0; i < 8 && len; i++) {
11733 /* i is the number of hex digits we have */
11734 buffer_prepare_copy(b, i + 1);
11737 for (j = i-1, len = olen; j+1 > 0; j--) {
11738 b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);
11740 @@ -43,61 +42,61 @@
11742 b->ptr[b->used++] = '\0';
11746 buffer_append_string(b, "\r\n");
11747 chunkqueue_append_buffer(con->write_queue, b);
11754 int http_chunk_append_file(server *srv, connection *con, buffer *fn, off_t offset, off_t len) {
11758 if (!con) return -1;
11761 cq = con->write_queue;
11764 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11765 http_chunk_append_len(srv, con, len);
11769 chunkqueue_append_file(cq, fn, offset, len);
11772 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && len > 0) {
11773 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11780 int http_chunk_append_buffer(server *srv, connection *con, buffer *mem) {
11784 if (!con) return -1;
11787 cq = con->write_queue;
11790 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11791 http_chunk_append_len(srv, con, mem->used - 1);
11795 chunkqueue_append_buffer(cq, mem);
11798 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED && mem->used > 0) {
11799 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11806 int http_chunk_append_mem(server *srv, connection *con, const char * mem, size_t len) {
11810 if (!con) return -1;
11813 cq = con->write_queue;
11817 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11818 http_chunk_append_len(srv, con, 0);
11819 @@ -107,17 +106,17 @@
11825 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11826 http_chunk_append_len(srv, con, len - 1);
11830 chunkqueue_append_mem(cq, mem, len);
11833 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
11834 chunkqueue_append_mem(cq, "\r\n", 2 + 1);
11841 @@ -125,9 +124,9 @@
11842 off_t http_chunkqueue_length(server *srv, connection *con) {
11844 log_error_write(srv, __FILE__, __LINE__, "s", "connection is NULL!!");
11851 return chunkqueue_length(con->write_queue);
11853 --- ../lighttpd-1.4.11/src/http_resp.c 1970-01-01 03:00:00.000000000 +0300
11854 +++ lighttpd-1.4.12/src/http_resp.c 2006-07-18 13:03:40.000000000 +0300
11856 +#include <string.h>
11857 +#include <stdlib.h>
11858 +#include <stdio.h>
11859 +#include <assert.h>
11862 +#include "http_resp.h"
11863 +#include "http_resp_parser.h"
11865 +/* declare prototypes for the parser */
11866 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t));
11867 +void http_resp_parserFree(void *p, void (*freeProc)(void*));
11868 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt);
11869 +void http_resp_parser(void *, int, buffer *, http_resp_ctx_t *);
11874 + chunk *c; /* current chunk in the chunkqueue */
11875 + size_t offset; /* current offset in current chunk */
11878 + size_t lookup_offset;
11881 + int is_statusline;
11882 +} http_resp_tokenizer_t;
11884 +http_resp *http_response_init(void) {
11885 + http_resp *resp = calloc(1, sizeof(*resp));
11887 + resp->reason = buffer_init();
11888 + resp->headers = array_init();
11893 +void http_response_reset(http_resp *resp) {
11894 + if (!resp) return;
11896 + buffer_reset(resp->reason);
11897 + array_reset(resp->headers);
11901 +void http_response_free(http_resp *resp) {
11902 + if (!resp) return;
11904 + buffer_free(resp->reason);
11905 + array_free(resp->headers);
11910 +static int http_resp_get_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11911 + if (t->offset == t->c->mem->used - 1) {
11912 + /* end of chunk, open next chunk */
11914 + if (!t->c->next) return -1;
11916 + t->c = t->c->next;
11920 + *c = t->c->mem->ptr[t->offset++];
11922 + t->lookup_offset = t->offset;
11923 + t->lookup_c = t->c;
11926 + fprintf(stderr, "%s.%d: get: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->offset - 1);
11932 +static int http_resp_lookup_next_char(http_resp_tokenizer_t *t, unsigned char *c) {
11933 + if (t->lookup_offset == t->lookup_c->mem->used - 1) {
11934 + /* end of chunk, open next chunk */
11936 + if (!t->lookup_c->next) return -1;
11938 + t->lookup_c = t->lookup_c->next;
11939 + t->lookup_offset = 0;
11942 + *c = t->lookup_c->mem->ptr[t->lookup_offset++];
11944 + fprintf(stderr, "%s.%d: lookup: %c (%d) at offset: %d\r\n", __FILE__, __LINE__, *c > 31 ? *c : ' ', *c, t->lookup_offset - 1);
11951 +static int http_resp_tokenizer(
11952 + http_resp_tokenizer_t *t,
11959 + /* push the token to the parser */
11961 + while (tid == 0 && 0 == http_resp_get_next_char(t, &c)) {
11975 + if (0 != http_resp_lookup_next_char(t, &c)) return -1;
11980 + t->c = t->lookup_c;
11981 + t->offset = t->lookup_offset;
11983 + t->is_statusline = 0;
11986 + fprintf(stderr, "%s.%d: CR with out LF\r\n", __FILE__, __LINE__);
11993 + t->is_statusline = 0;
11998 + while (c >= 32 && c != 127 && c != 255) {
11999 + if (t->is_statusline) {
12000 + if (c == ':') { t->is_statusline = 0; break; } /* this is not a status line by a real header */
12001 + if (c == 32) break; /* the space is a splitter in the statusline */
12004 + if (c == ':') break; /* the : is the splitter between key and value */
12007 + if (0 != http_resp_lookup_next_char(t, &c)) return -1;
12010 + if (t->c == t->lookup_c &&
12011 + t->offset == t->lookup_offset + 1) {
12013 + fprintf(stderr, "%s.%d: invalid char in string\n", __FILE__, __LINE__);
12019 + /* the lookup points to the first invalid char */
12020 + t->lookup_offset--;
12022 + /* no overlapping string */
12023 + if (t->c == t->lookup_c) {
12024 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->lookup_offset - t->offset + 1);
12026 + /* first chunk */
12027 + buffer_copy_string_len(token, t->c->mem->ptr + t->offset - 1, t->c->mem->used - t->offset);
12029 + /* chunks in the middle */
12030 + for (t->c = t->c->next; t->c != t->lookup_c; t->c = t->c->next) {
12031 + buffer_append_string_buffer(token, t->c->mem);
12032 + t->offset = t->c->mem->used - 1;
12036 + buffer_append_string_len(token, t->c->mem->ptr, t->lookup_offset);
12039 + t->offset = t->lookup_offset;
12054 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *resp) {
12055 + http_resp_tokenizer_t t;
12056 + void *pParser = NULL;
12057 + int token_id = 0;
12058 + buffer *token = NULL;
12059 + http_resp_ctx_t context;
12060 + parse_status_t ret = PARSE_UNSET;
12061 + int last_token_id = 0;
12065 + t.offset = t.c->offset;
12067 + t.is_statusline = 1;
12070 + context.errmsg = buffer_init();
12071 + context.resp = resp;
12073 + pParser = http_resp_parserAlloc( malloc );
12074 + token = buffer_init();
12076 + http_resp_parserTrace(stderr, "http-response: ");
12079 + while((1 == http_resp_tokenizer(&t, &token_id, token)) && context.ok) {
12080 + http_resp_parser(pParser, token_id, token, &context);
12082 + token = buffer_init();
12084 + /* CRLF CRLF ... the header end sequence */
12085 + if (last_token_id == TK_CRLF &&
12086 + token_id == TK_CRLF) break;
12088 + last_token_id = token_id;
12091 + /* oops, the parser failed */
12092 + if (context.ok == 0) {
12093 + ret = PARSE_ERROR;
12095 + if (!buffer_is_empty(context.errmsg)) {
12096 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12098 + TRACE("%s", "parsing failed ...");
12102 + http_resp_parser(pParser, 0, token, &context);
12103 + http_resp_parserFree(pParser, free);
12105 + if (context.ok == 0) {
12106 + /* we are missing the some tokens */
12108 + if (!buffer_is_empty(context.errmsg)) {
12109 + TRACE("parsing failed: %s", BUF_STR(context.errmsg));
12112 + if (ret == PARSE_UNSET) {
12113 + ret = buffer_is_empty(context.errmsg) ? PARSE_NEED_MORE : PARSE_ERROR;
12118 + for (c = cq->first; c != t.c; c = c->next) {
12119 + c->offset = c->mem->used - 1;
12122 + c->offset = t.offset;
12124 + ret = PARSE_SUCCESS;
12127 + buffer_free(token);
12128 + buffer_free(context.errmsg);
12133 --- ../lighttpd-1.4.11/src/http_resp.h 1970-01-01 03:00:00.000000000 +0300
12134 +++ lighttpd-1.4.12/src/http_resp.h 2006-07-16 00:26:04.000000000 +0300
12136 +#ifndef _HTTP_RESP_H_
12137 +#define _HTTP_RESP_H_
12139 +#include "array.h"
12140 +#include "chunk.h"
12150 + int protocol; /* http/1.0, http/1.1 */
12151 + int status; /* e.g. 200 */
12152 + buffer *reason; /* e.g. Ok */
12161 +} http_resp_ctx_t;
12163 +http_resp *http_response_init(void);
12164 +void http_response_free(http_resp *resp);
12165 +void http_response_reset(http_resp *resp);
12167 +parse_status_t http_response_parse_cq(chunkqueue *cq, http_resp *http_response);
12170 --- ../lighttpd-1.4.11/src/http_resp_parser.c 1970-01-01 03:00:00.000000000 +0300
12171 +++ lighttpd-1.4.12/src/http_resp_parser.c 2006-07-18 13:03:52.000000000 +0300
12173 +/* Driver template for the LEMON parser generator.
12174 +** The author disclaims copyright to this source code.
12176 +/* First off, code is include which follows the "include" declaration
12177 +** in the input file. */
12178 +#include <stdio.h>
12179 +#line 6 "./http_resp_parser.y"
12181 +#include <assert.h>
12182 +#include <string.h>
12183 +#include "http_resp.h"
12184 +#include "keyvalue.h"
12185 +#include "array.h"
12188 +#line 17 "http_resp_parser.c"
12189 +/* Next is all token values, in a form suitable for use by makeheaders.
12190 +** This section will be null unless lemon is run with the -m switch.
12193 +** These constants (all generated automatically by the parser generator)
12194 +** specify the various kinds of tokens (terminals) that the parser
12197 +** Each symbol here is a terminal symbol in the grammar.
12199 +/* Make sure the INTERFACE macro is defined.
12202 +# define INTERFACE 1
12204 +/* The next thing included is series of defines which control
12205 +** various aspects of the generated parser.
12206 +** YYCODETYPE is the data type used for storing terminal
12207 +** and nonterminal numbers. "unsigned char" is
12208 +** used if there are fewer than 250 terminals
12209 +** and nonterminals. "int" is used otherwise.
12210 +** YYNOCODE is a number of type YYCODETYPE which corresponds
12211 +** to no legal terminal or nonterminal number. This
12212 +** number is used to fill in empty slots of the hash
12214 +** YYFALLBACK If defined, this indicates that one or more tokens
12215 +** have fall-back values which should be used if the
12216 +** original value of the token will not parse.
12217 +** YYACTIONTYPE is the data type used for storing terminal
12218 +** and nonterminal numbers. "unsigned char" is
12219 +** used if there are fewer than 250 rules and
12220 +** states combined. "int" is used otherwise.
12221 +** http_resp_parserTOKENTYPE is the data type used for minor tokens given
12222 +** directly to the parser from the tokenizer.
12223 +** YYMINORTYPE is the data type used for all minor tokens.
12224 +** This is typically a union of many types, one of
12225 +** which is http_resp_parserTOKENTYPE. The entry in the union
12226 +** for base tokens is called "yy0".
12227 +** YYSTACKDEPTH is the maximum depth of the parser's stack.
12228 +** http_resp_parserARG_SDECL A static variable declaration for the %extra_argument
12229 +** http_resp_parserARG_PDECL A parameter declaration for the %extra_argument
12230 +** http_resp_parserARG_STORE Code to store %extra_argument into yypParser
12231 +** http_resp_parserARG_FETCH Code to extract %extra_argument from yypParser
12232 +** YYNSTATE the combined number of states.
12233 +** YYNRULE the number of rules in the grammar
12234 +** YYERRORSYMBOL is the code number of the error symbol. If not
12235 +** defined, then do no error processing.
12238 +#define YYCODETYPE unsigned char
12239 +#define YYNOCODE 12
12240 +#define YYACTIONTYPE unsigned char
12241 +#define http_resp_parserTOKENTYPE buffer *
12243 + http_resp_parserTOKENTYPE yy0;
12245 + data_string * yy9;
12250 +#define YYSTACKDEPTH 100
12251 +#define http_resp_parserARG_SDECL http_resp_ctx_t *ctx;
12252 +#define http_resp_parserARG_PDECL ,http_resp_ctx_t *ctx
12253 +#define http_resp_parserARG_FETCH http_resp_ctx_t *ctx = yypParser->ctx
12254 +#define http_resp_parserARG_STORE yypParser->ctx = ctx
12255 +#define YYNSTATE 19
12257 +#define YYERRORSYMBOL 4
12258 +#define YYERRSYMDT yy23
12259 +#define YY_NO_ACTION (YYNSTATE+YYNRULE+2)
12260 +#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1)
12261 +#define YY_ERROR_ACTION (YYNSTATE+YYNRULE)
12263 +/* Next are that tables used to determine what action to take based on the
12264 +** current state and lookahead token. These tables are used to implement
12265 +** functions that take a state number and lookahead value and return an
12266 +** action integer.
12268 +** Suppose the action integer is N. Then the action is determined as
12271 +** 0 <= N < YYNSTATE Shift N. That is, push the lookahead
12272 +** token onto the stack and goto state N.
12274 +** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE.
12276 +** N == YYNSTATE+YYNRULE A syntax error has occurred.
12278 +** N == YYNSTATE+YYNRULE+1 The parser accepts its input.
12280 +** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused
12281 +** slots in the yy_action[] table.
12283 +** The action table is constructed as a single large table named yy_action[].
12284 +** Given state S and lookahead X, the action is computed as
12286 +** yy_action[ yy_shift_ofst[S] + X ]
12288 +** If the index value yy_shift_ofst[S]+X is out of range or if the value
12289 +** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
12290 +** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
12291 +** and that yy_default[S] should be used instead.
12293 +** The formula above is for computing the action when the lookahead is
12294 +** a terminal symbol. If the lookahead is a non-terminal (as occurs after
12295 +** a reduce action) then the yy_reduce_ofst[] array is used in place of
12296 +** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
12297 +** YY_SHIFT_USE_DFLT.
12299 +** The following are the tables generated in this section:
12301 +** yy_action[] A single table containing all actions.
12302 +** yy_lookahead[] A table containing the lookahead for each entry in
12303 +** yy_action. Used to detect hash collisions.
12304 +** yy_shift_ofst[] For each state, the offset into yy_action for
12305 +** shifting terminals.
12306 +** yy_reduce_ofst[] For each state, the offset into yy_action for
12307 +** shifting non-terminals after a reduce.
12308 +** yy_default[] Default action for each state.
12310 +static YYACTIONTYPE yy_action[] = {
12311 + /* 0 */ 8, 29, 18, 1, 14, 2, 4, 11, 15, 12,
12312 + /* 10 */ 14, 13, 4, 21, 5, 19, 3, 5, 6, 7,
12313 + /* 20 */ 9, 17, 16, 4, 20, 22, 22, 10,
12315 +static YYCODETYPE yy_lookahead[] = {
12316 + /* 0 */ 5, 6, 2, 8, 9, 1, 2, 1, 2, 8,
12317 + /* 10 */ 9, 1, 2, 2, 3, 0, 9, 3, 2, 1,
12318 + /* 20 */ 7, 2, 2, 2, 0, 2, 11, 10,
12320 +#define YY_SHIFT_USE_DFLT (-1)
12321 +static signed char yy_shift_ofst[] = {
12322 + /* 0 */ 0, 4, 15, -1, 14, 16, 18, -1, 19, 20,
12323 + /* 10 */ 6, 21, 10, 24, -1, -1, -1, 23, 11,
12325 +#define YY_REDUCE_USE_DFLT (-6)
12326 +static signed char yy_reduce_ofst[] = {
12327 + /* 0 */ -5, 7, -6, -6, -6, -6, -6, -6, 13, 17,
12328 + /* 10 */ -6, 1, 7, -6, -6, -6, -6, -6, -6,
12330 +static YYACTIONTYPE yy_default[] = {
12331 + /* 0 */ 28, 28, 28, 25, 28, 28, 28, 27, 28, 28,
12332 + /* 10 */ 28, 28, 28, 28, 26, 24, 23, 28, 28,
12334 +#define YY_SZ_ACTTAB (sizeof(yy_action)/sizeof(yy_action[0]))
12336 +/* The next table maps tokens into fallback tokens. If a construct
12337 +** like the following:
12339 +** %fallback ID X Y Z.
12341 +** appears in the grammer, then ID becomes a fallback token for X, Y,
12342 +** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
12343 +** but it does not parse, the type of the token is changed to ID and
12344 +** the parse is retried before an error is thrown.
12347 +static const YYCODETYPE yyFallback[] = {
12349 +#endif /* YYFALLBACK */
12351 +/* The following structure represents a single element of the
12352 +** parser's stack. Information stored includes:
12354 +** + The state number for the parser at this level of the stack.
12356 +** + The value of the token stored at this level of the stack.
12357 +** (In other words, the "major" token.)
12359 +** + The semantic value stored at this level of the stack. This is
12360 +** the information used by the action routines in the grammar.
12361 +** It is sometimes called the "minor" token.
12363 +struct yyStackEntry {
12364 + int stateno; /* The state-number */
12365 + int major; /* The major token value. This is the code
12366 + ** number for the token at this stack level */
12367 + YYMINORTYPE minor; /* The user-supplied minor token value. This
12368 + ** is the value of the token */
12370 +typedef struct yyStackEntry yyStackEntry;
12372 +/* The state of the parser is completely contained in an instance of
12373 +** the following structure */
12375 + int yyidx; /* Index of top element in stack */
12376 + int yyerrcnt; /* Shifts left before out of the error */
12377 + http_resp_parserARG_SDECL /* A place to hold %extra_argument */
12378 + yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
12380 +typedef struct yyParser yyParser;
12383 +#include <stdio.h>
12384 +static FILE *yyTraceFILE = 0;
12385 +static char *yyTracePrompt = 0;
12386 +#endif /* NDEBUG */
12390 +** Turn parser tracing on by giving a stream to which to write the trace
12391 +** and a prompt to preface each trace message. Tracing is turned off
12392 +** by making either argument NULL
12396 +** <li> A FILE* to which trace output should be written.
12397 +** If NULL, then tracing is turned off.
12398 +** <li> A prefix string written at the beginning of every
12399 +** line of trace output. If NULL, then tracing is
12406 +void http_resp_parserTrace(FILE *TraceFILE, char *zTracePrompt){
12407 + yyTraceFILE = TraceFILE;
12408 + yyTracePrompt = zTracePrompt;
12409 + if( yyTraceFILE==0 ) yyTracePrompt = 0;
12410 + else if( yyTracePrompt==0 ) yyTraceFILE = 0;
12412 +#endif /* NDEBUG */
12415 +/* For tracing shifts, the names of all terminals and nonterminals
12416 +** are required. The following table supplies these names */
12417 +static const char *yyTokenName[] = {
12418 + "$", "CRLF", "STRING", "COLON",
12419 + "error", "protocol", "response_hdr", "number",
12420 + "headers", "header", "reason",
12422 +#endif /* NDEBUG */
12425 +/* For tracing reduce actions, the names of all rules are required.
12427 +static const char *yyRuleName[] = {
12428 + /* 0 */ "response_hdr ::= headers CRLF",
12429 + /* 1 */ "response_hdr ::= protocol number reason CRLF headers CRLF",
12430 + /* 2 */ "protocol ::= STRING",
12431 + /* 3 */ "number ::= STRING",
12432 + /* 4 */ "reason ::= STRING",
12433 + /* 5 */ "reason ::= reason STRING",
12434 + /* 6 */ "headers ::= headers header",
12435 + /* 7 */ "headers ::= header",
12436 + /* 8 */ "header ::= STRING COLON STRING CRLF",
12438 +#endif /* NDEBUG */
12441 +** This function returns the symbolic name associated with a token
12444 +const char *http_resp_parserTokenName(int tokenType){
12446 + if( tokenType>0 && tokenType<(sizeof(yyTokenName)/sizeof(yyTokenName[0])) ){
12447 + return yyTokenName[tokenType];
12449 + return "Unknown";
12457 +** This function allocates a new parser.
12458 +** The only argument is a pointer to a function which works like
12462 +** A pointer to the function used to allocate memory.
12465 +** A pointer to a parser. This pointer is used in subsequent calls
12466 +** to http_resp_parser and http_resp_parserFree.
12468 +void *http_resp_parserAlloc(void *(*mallocProc)(size_t)){
12469 + yyParser *pParser;
12470 + pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) );
12472 + pParser->yyidx = -1;
12477 +/* The following function deletes the value associated with a
12478 +** symbol. The symbol can be either a terminal or nonterminal.
12479 +** "yymajor" is the symbol code, and "yypminor" is a pointer to
12482 +static void yy_destructor(YYCODETYPE yymajor, YYMINORTYPE *yypminor){
12483 + switch( yymajor ){
12484 + /* Here is inserted the actions which take place when a
12485 + ** terminal or non-terminal is destroyed. This can happen
12486 + ** when the symbol is popped from the stack during a
12487 + ** reduce or during error processing or when a parser is
12488 + ** being destroyed before it is finished parsing.
12490 + ** Note: during a reduce, the only symbols destroyed are those
12491 + ** which appear on the RHS of the rule, but which are not used
12492 + ** inside the C code.
12497 +#line 25 "./http_resp_parser.y"
12498 +{ buffer_free((yypminor->yy0)); }
12499 +#line 327 "http_resp_parser.c"
12502 +#line 24 "./http_resp_parser.y"
12503 +{ buffer_free((yypminor->yy0)); }
12504 +#line 332 "http_resp_parser.c"
12506 + default: break; /* If no destructor action specified: do nothing */
12511 +** Pop the parser's stack once.
12513 +** If there is a destructor routine associated with the token which
12514 +** is popped from the stack, then call it.
12516 +** Return the major token number for the symbol popped.
12518 +static int yy_pop_parser_stack(yyParser *pParser){
12519 + YYCODETYPE yymajor;
12520 + yyStackEntry *yytos = &pParser->yystack[pParser->yyidx];
12522 + if( pParser->yyidx<0 ) return 0;
12524 + if( yyTraceFILE && pParser->yyidx>=0 ){
12525 + fprintf(yyTraceFILE,"%sPopping %s\n",
12527 + yyTokenName[yytos->major]);
12530 + yymajor = yytos->major;
12531 + yy_destructor( yymajor, &yytos->minor);
12532 + pParser->yyidx--;
12537 +** Deallocate and destroy a parser. Destructors are all called for
12538 +** all stack elements before shutting the parser down.
12542 +** <li> A pointer to the parser. This should be a pointer
12543 +** obtained from http_resp_parserAlloc.
12544 +** <li> A pointer to a function used to reclaim memory obtained
12548 +void http_resp_parserFree(
12549 + void *p, /* The parser to be deleted */
12550 + void (*freeProc)(void*) /* Function used to reclaim memory */
12552 + yyParser *pParser = (yyParser*)p;
12553 + if( pParser==0 ) return;
12554 + while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser);
12555 + (*freeProc)((void*)pParser);
12559 +** Find the appropriate action for a parser given the terminal
12560 +** look-ahead token iLookAhead.
12562 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12563 +** independent of the look-ahead. If it is, return the action, otherwise
12564 +** return YY_NO_ACTION.
12566 +static int yy_find_shift_action(
12567 + yyParser *pParser, /* The parser */
12568 + int iLookAhead /* The look-ahead token */
12571 + int stateno = pParser->yystack[pParser->yyidx].stateno;
12573 + /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
12574 + i = yy_shift_ofst[stateno];
12575 + if( i==YY_SHIFT_USE_DFLT ){
12576 + return yy_default[stateno];
12578 + if( iLookAhead==YYNOCODE ){
12579 + return YY_NO_ACTION;
12582 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12584 + int iFallback; /* Fallback token */
12585 + if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
12586 + && (iFallback = yyFallback[iLookAhead])!=0 ){
12588 + if( yyTraceFILE ){
12589 + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
12590 + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
12593 + return yy_find_shift_action(pParser, iFallback);
12596 + return yy_default[stateno];
12598 + return yy_action[i];
12603 +** Find the appropriate action for a parser given the non-terminal
12604 +** look-ahead token iLookAhead.
12606 +** If the look-ahead token is YYNOCODE, then check to see if the action is
12607 +** independent of the look-ahead. If it is, return the action, otherwise
12608 +** return YY_NO_ACTION.
12610 +static int yy_find_reduce_action(
12611 + yyParser *pParser, /* The parser */
12612 + int iLookAhead /* The look-ahead token */
12615 + int stateno = pParser->yystack[pParser->yyidx].stateno;
12617 + i = yy_reduce_ofst[stateno];
12618 + if( i==YY_REDUCE_USE_DFLT ){
12619 + return yy_default[stateno];
12621 + if( iLookAhead==YYNOCODE ){
12622 + return YY_NO_ACTION;
12625 + if( i<0 || i>=YY_SZ_ACTTAB || yy_lookahead[i]!=iLookAhead ){
12626 + return yy_default[stateno];
12628 + return yy_action[i];
12633 +** Perform a shift action.
12635 +static void yy_shift(
12636 + yyParser *yypParser, /* The parser to be shifted */
12637 + int yyNewState, /* The new state to shift in */
12638 + int yyMajor, /* The major token to shift in */
12639 + YYMINORTYPE *yypMinor /* Pointer ot the minor token to shift in */
12641 + yyStackEntry *yytos;
12642 + yypParser->yyidx++;
12643 + if( yypParser->yyidx>=YYSTACKDEPTH ){
12644 + http_resp_parserARG_FETCH;
12645 + yypParser->yyidx--;
12647 + if( yyTraceFILE ){
12648 + fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
12651 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12652 + /* Here code is inserted which will execute if the parser
12653 + ** stack every overflows */
12654 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
12657 + yytos = &yypParser->yystack[yypParser->yyidx];
12658 + yytos->stateno = yyNewState;
12659 + yytos->major = yyMajor;
12660 + yytos->minor = *yypMinor;
12662 + if( yyTraceFILE && yypParser->yyidx>0 ){
12664 + fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState);
12665 + fprintf(yyTraceFILE,"%sStack:",yyTracePrompt);
12666 + for(i=1; i<=yypParser->yyidx; i++)
12667 + fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]);
12668 + fprintf(yyTraceFILE,"\n");
12673 +/* The following table contains information about every rule that
12674 +** is used during the reduce.
12677 + YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
12678 + unsigned char nrhs; /* Number of right-hand side symbols in the rule */
12679 +} yyRuleInfo[] = {
12691 +static void yy_accept(yyParser*); /* Forward Declaration */
12694 +** Perform a reduce action and the shift that must immediately
12695 +** follow the reduce.
12697 +static void yy_reduce(
12698 + yyParser *yypParser, /* The parser */
12699 + int yyruleno /* Number of the rule by which to reduce */
12701 + int yygoto; /* The next state */
12702 + int yyact; /* The next action */
12703 + YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
12704 + yyStackEntry *yymsp; /* The top of the parser's stack */
12705 + int yysize; /* Amount to pop the stack */
12706 + http_resp_parserARG_FETCH;
12707 + yymsp = &yypParser->yystack[yypParser->yyidx];
12709 + if( yyTraceFILE && yyruleno>=0
12710 + && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
12711 + fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
12712 + yyRuleName[yyruleno]);
12714 +#endif /* NDEBUG */
12716 + switch( yyruleno ){
12717 + /* Beginning here are the reduction cases. A typical example
12720 + ** #line <lineno> <grammarfile>
12721 + ** { ... } // User supplied code
12722 + ** #line <lineno> <thisfile>
12726 +#line 28 "./http_resp_parser.y"
12728 + http_resp *resp = ctx->resp;
12731 + resp->protocol = HTTP_VERSION_UNSET;
12733 + buffer_copy_string(resp->reason, ""); /* no reason */
12734 + array_free(resp->headers);
12735 + resp->headers = yymsp[-1].minor.yy12;
12737 + if (NULL == (ds = (data_string *)array_get_element(yymsp[-1].minor.yy12, "Status"))) {
12738 + resp->status = 0;
12741 + resp->status = strtol(ds->value->ptr, &err, 10);
12743 + if (*err != '\0' && *err != ' ') {
12744 + buffer_copy_string(ctx->errmsg, "expected a number: ");
12745 + buffer_append_string_buffer(ctx->errmsg, ds->value);
12746 + buffer_append_string(ctx->errmsg, err);
12752 + yymsp[-1].minor.yy12 = NULL;
12754 +#line 582 "http_resp_parser.c"
12755 + yy_destructor(1,&yymsp[0].minor);
12758 +#line 56 "./http_resp_parser.y"
12760 + http_resp *resp = ctx->resp;
12762 + resp->status = yymsp[-4].minor.yy20;
12763 + resp->protocol = yymsp[-5].minor.yy20;
12764 + buffer_copy_string_buffer(resp->reason, yymsp[-3].minor.yy0);
12765 + buffer_free(yymsp[-3].minor.yy0);
12767 + array_free(resp->headers);
12769 + resp->headers = yymsp[-1].minor.yy12;
12771 +#line 599 "http_resp_parser.c"
12772 + yy_destructor(1,&yymsp[-2].minor);
12773 + yy_destructor(1,&yymsp[0].minor);
12776 +#line 69 "./http_resp_parser.y"
12778 + if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.0"))) {
12779 + yygotominor.yy20 = HTTP_VERSION_1_0;
12780 + } else if (buffer_is_equal_string(yymsp[0].minor.yy0, CONST_STR_LEN("HTTP/1.1"))) {
12781 + yygotominor.yy20 = HTTP_VERSION_1_1;
12783 + buffer_copy_string(ctx->errmsg, "unknown protocol: ");
12784 + buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12788 + buffer_free(yymsp[0].minor.yy0);
12790 +#line 618 "http_resp_parser.c"
12793 +#line 83 "./http_resp_parser.y"
12796 + yygotominor.yy20 = strtol(yymsp[0].minor.yy0->ptr, &err, 10);
12798 + if (*err != '\0') {
12799 + buffer_copy_string(ctx->errmsg, "expected a number, got: ");
12800 + buffer_append_string_buffer(ctx->errmsg, yymsp[0].minor.yy0);
12804 + buffer_free(yymsp[0].minor.yy0);
12806 +#line 634 "http_resp_parser.c"
12809 +#line 96 "./http_resp_parser.y"
12811 + yygotominor.yy0 = yymsp[0].minor.yy0;
12813 +#line 641 "http_resp_parser.c"
12816 +#line 100 "./http_resp_parser.y"
12818 + yygotominor.yy0 = yymsp[-1].minor.yy0;
12820 + buffer_append_string(yygotominor.yy0, " ");
12821 + buffer_append_string_buffer(yygotominor.yy0, yymsp[0].minor.yy0);
12823 + buffer_free(yymsp[0].minor.yy0);
12825 +#line 653 "http_resp_parser.c"
12828 +#line 109 "./http_resp_parser.y"
12830 + yygotominor.yy12 = yymsp[-1].minor.yy12;
12832 + array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12834 +#line 662 "http_resp_parser.c"
12837 +#line 115 "./http_resp_parser.y"
12839 + yygotominor.yy12 = array_init();
12841 + array_insert_unique(yygotominor.yy12, (data_unset *)yymsp[0].minor.yy9);
12843 +#line 671 "http_resp_parser.c"
12846 +#line 120 "./http_resp_parser.y"
12848 + yygotominor.yy9 = data_string_init();
12850 + buffer_copy_string_buffer(yygotominor.yy9->key, yymsp[-3].minor.yy0);
12851 + buffer_copy_string_buffer(yygotominor.yy9->value, yymsp[-1].minor.yy0);
12852 + buffer_free(yymsp[-3].minor.yy0);
12853 + buffer_free(yymsp[-1].minor.yy0);
12855 +#line 683 "http_resp_parser.c"
12856 + yy_destructor(3,&yymsp[-2].minor);
12857 + yy_destructor(1,&yymsp[0].minor);
12860 + yygoto = yyRuleInfo[yyruleno].lhs;
12861 + yysize = yyRuleInfo[yyruleno].nrhs;
12862 + yypParser->yyidx -= yysize;
12863 + yyact = yy_find_reduce_action(yypParser,yygoto);
12864 + if( yyact < YYNSTATE ){
12865 + yy_shift(yypParser,yyact,yygoto,&yygotominor);
12866 + }else if( yyact == YYNSTATE + YYNRULE + 1 ){
12867 + yy_accept(yypParser);
12872 +** The following code executes when the parse fails
12874 +static void yy_parse_failed(
12875 + yyParser *yypParser /* The parser */
12877 + http_resp_parserARG_FETCH;
12879 + if( yyTraceFILE ){
12880 + fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
12883 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12884 + /* Here code is inserted which will be executed whenever the
12885 + ** parser fails */
12886 +#line 15 "./http_resp_parser.y"
12890 +#line 718 "http_resp_parser.c"
12891 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12895 +** The following code executes when a syntax error first occurs.
12897 +static void yy_syntax_error(
12898 + yyParser *yypParser, /* The parser */
12899 + int yymajor, /* The major type of the error token */
12900 + YYMINORTYPE yyminor /* The minor type of the error token */
12902 + http_resp_parserARG_FETCH;
12903 +#define TOKEN (yyminor.yy0)
12904 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12908 +** The following is executed when the parser accepts
12910 +static void yy_accept(
12911 + yyParser *yypParser /* The parser */
12913 + http_resp_parserARG_FETCH;
12915 + if( yyTraceFILE ){
12916 + fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
12919 + while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser);
12920 + /* Here code is inserted which will be executed whenever the
12921 + ** parser accepts */
12922 + http_resp_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
12925 +/* The main parser program.
12926 +** The first argument is a pointer to a structure obtained from
12927 +** "http_resp_parserAlloc" which describes the current state of the parser.
12928 +** The second argument is the major token number. The third is
12929 +** the minor token. The fourth optional argument is whatever the
12930 +** user wants (and specified in the grammar) and is available for
12931 +** use by the action routines.
12935 +** <li> A pointer to the parser (an opaque structure.)
12936 +** <li> The major token number.
12937 +** <li> The minor token number.
12938 +** <li> An option argument of a grammar-specified type.
12944 +void http_resp_parser(
12945 + void *yyp, /* The parser */
12946 + int yymajor, /* The major token code number */
12947 + http_resp_parserTOKENTYPE yyminor /* The value for the token */
12948 + http_resp_parserARG_PDECL /* Optional %extra_argument parameter */
12950 + YYMINORTYPE yyminorunion;
12951 + int yyact; /* The parser action. */
12952 + int yyendofinput; /* True if we are at the end of input */
12953 + int yyerrorhit = 0; /* True if yymajor has invoked an error */
12954 + yyParser *yypParser; /* The parser */
12956 + /* (re)initialize the parser, if necessary */
12957 + yypParser = (yyParser*)yyp;
12958 + if( yypParser->yyidx<0 ){
12959 + if( yymajor==0 ) return;
12960 + yypParser->yyidx = 0;
12961 + yypParser->yyerrcnt = -1;
12962 + yypParser->yystack[0].stateno = 0;
12963 + yypParser->yystack[0].major = 0;
12965 + yyminorunion.yy0 = yyminor;
12966 + yyendofinput = (yymajor==0);
12967 + http_resp_parserARG_STORE;
12970 + if( yyTraceFILE ){
12971 + fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]);
12976 + yyact = yy_find_shift_action(yypParser,yymajor);
12977 + if( yyact<YYNSTATE ){
12978 + yy_shift(yypParser,yyact,yymajor,&yyminorunion);
12979 + yypParser->yyerrcnt--;
12980 + if( yyendofinput && yypParser->yyidx>=0 ){
12983 + yymajor = YYNOCODE;
12985 + }else if( yyact < YYNSTATE + YYNRULE ){
12986 + yy_reduce(yypParser,yyact-YYNSTATE);
12987 + }else if( yyact == YY_ERROR_ACTION ){
12990 + if( yyTraceFILE ){
12991 + fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
12994 +#ifdef YYERRORSYMBOL
12995 + /* A syntax error has occurred.
12996 + ** The response to an error depends upon whether or not the
12997 + ** grammar defines an error token "ERROR".
12999 + ** This is what we do if the grammar does define ERROR:
13001 + ** * Call the %syntax_error function.
13003 + ** * Begin popping the stack until we enter a state where
13004 + ** it is legal to shift the error symbol, then shift
13005 + ** the error symbol.
13007 + ** * Set the error count to three.
13009 + ** * Begin accepting and shifting new tokens. No new error
13010 + ** processing will occur until three tokens have been
13011 + ** shifted successfully.
13014 + if( yypParser->yyerrcnt<0 ){
13015 + yy_syntax_error(yypParser,yymajor,yyminorunion);
13017 + yymx = yypParser->yystack[yypParser->yyidx].major;
13018 + if( yymx==YYERRORSYMBOL || yyerrorhit ){
13020 + if( yyTraceFILE ){
13021 + fprintf(yyTraceFILE,"%sDiscard input token %s\n",
13022 + yyTracePrompt,yyTokenName[yymajor]);
13025 + yy_destructor(yymajor,&yyminorunion);
13026 + yymajor = YYNOCODE;
13029 + yypParser->yyidx >= 0 &&
13030 + yymx != YYERRORSYMBOL &&
13031 + (yyact = yy_find_shift_action(yypParser,YYERRORSYMBOL)) >= YYNSTATE
13033 + yy_pop_parser_stack(yypParser);
13035 + if( yypParser->yyidx < 0 || yymajor==0 ){
13036 + yy_destructor(yymajor,&yyminorunion);
13037 + yy_parse_failed(yypParser);
13038 + yymajor = YYNOCODE;
13039 + }else if( yymx!=YYERRORSYMBOL ){
13041 + u2.YYERRSYMDT = 0;
13042 + yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
13045 + yypParser->yyerrcnt = 3;
13047 +#else /* YYERRORSYMBOL is not defined */
13048 + /* This is what we do if the grammar does not define ERROR:
13050 + ** * Report an error message, and throw away the input token.
13052 + ** * If the input token is $, then fail the parse.
13054 + ** As before, subsequent error messages are suppressed until
13055 + ** three input tokens have been successfully shifted.
13057 + if( yypParser->yyerrcnt<=0 ){
13058 + yy_syntax_error(yypParser,yymajor,yyminorunion);
13060 + yypParser->yyerrcnt = 3;
13061 + yy_destructor(yymajor,&yyminorunion);
13062 + if( yyendofinput ){
13063 + yy_parse_failed(yypParser);
13065 + yymajor = YYNOCODE;
13068 + yy_accept(yypParser);
13069 + yymajor = YYNOCODE;
13071 + }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 );
13074 --- ../lighttpd-1.4.11/src/http_resp_parser.h 1970-01-01 03:00:00.000000000 +0300
13075 +++ lighttpd-1.4.12/src/http_resp_parser.h 2006-07-18 13:03:52.000000000 +0300
13078 +#define TK_STRING 2
13079 +#define TK_COLON 3
13080 --- ../lighttpd-1.4.11/src/http_resp_parser.y 1970-01-01 03:00:00.000000000 +0300
13081 +++ lighttpd-1.4.12/src/http_resp_parser.y 2006-07-18 13:03:40.000000000 +0300
13084 +%token_type {buffer *}
13085 +%extra_argument {http_resp_ctx_t *ctx}
13086 +%name http_resp_parser
13089 +#include <assert.h>
13090 +#include <string.h>
13091 +#include "http_resp.h"
13092 +#include "keyvalue.h"
13093 +#include "array.h"
13101 +%type protocol { int }
13102 +%type response_hdr { http_resp * }
13103 +%type number { int }
13104 +%type headers { array * }
13105 +%type header { data_string * }
13106 +%destructor reason { buffer_free($$); }
13107 +%token_destructor { buffer_free($$); }
13109 +/* just headers + Status: ... */
13110 +response_hdr ::= headers(HDR) CRLF . {
13111 + http_resp *resp = ctx->resp;
13114 + resp->protocol = HTTP_VERSION_UNSET;
13116 + buffer_copy_string(resp->reason, ""); /* no reason */
13117 + array_free(resp->headers);
13118 + resp->headers = HDR;
13120 + if (NULL == (ds = (data_string *)array_get_element(HDR, "Status"))) {
13121 + resp->status = 0;
13124 + resp->status = strtol(ds->value->ptr, &err, 10);
13126 + if (*err != '\0' && *err != ' ') {
13127 + buffer_copy_string(ctx->errmsg, "expected a number: ");
13128 + buffer_append_string_buffer(ctx->errmsg, ds->value);
13129 + buffer_append_string(ctx->errmsg, err);
13137 +/* HTTP/1.0 <status> ... */
13138 +response_hdr ::= protocol(B) number(C) reason(D) CRLF headers(HDR) CRLF . {
13139 + http_resp *resp = ctx->resp;
13141 + resp->status = C;
13142 + resp->protocol = B;
13143 + buffer_copy_string_buffer(resp->reason, D);
13146 + array_free(resp->headers);
13148 + resp->headers = HDR;
13151 +protocol(A) ::= STRING(B). {
13152 + if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.0"))) {
13153 + A = HTTP_VERSION_1_0;
13154 + } else if (buffer_is_equal_string(B, CONST_STR_LEN("HTTP/1.1"))) {
13155 + A = HTTP_VERSION_1_1;
13157 + buffer_copy_string(ctx->errmsg, "unknown protocol: ");
13158 + buffer_append_string_buffer(ctx->errmsg, B);
13165 +number(A) ::= STRING(B). {
13167 + A = strtol(B->ptr, &err, 10);
13169 + if (*err != '\0') {
13170 + buffer_copy_string(ctx->errmsg, "expected a number, got: ");
13171 + buffer_append_string_buffer(ctx->errmsg, B);
13178 +reason(A) ::= STRING(B). {
13182 +reason(A) ::= reason(C) STRING(B). {
13185 + buffer_append_string(A, " ");
13186 + buffer_append_string_buffer(A, B);
13191 +headers(HDRS) ::= headers(SRC) header(HDR). {
13194 + array_insert_unique(HDRS, (data_unset *)HDR);
13197 +headers(HDRS) ::= header(HDR). {
13198 + HDRS = array_init();
13200 + array_insert_unique(HDRS, (data_unset *)HDR);
13202 +header(HDR) ::= STRING(A) COLON STRING(B) CRLF. {
13203 + HDR = data_string_init();
13205 + buffer_copy_string_buffer(HDR->key, A);
13206 + buffer_copy_string_buffer(HDR->value, B);
13210 --- ../lighttpd-1.4.11/src/inet_ntop_cache.c 2005-08-11 01:26:38.000000000 +0300
13211 +++ lighttpd-1.4.12/src/inet_ntop_cache.c 2006-07-16 00:26:04.000000000 +0300
13213 #include "sys-socket.h"
13215 const char * inet_ntop_cache_get_ip(server *srv, sock_addr *addr) {
13219 for (i = 0; i < INET_NTOP_CACHE_MAX; i++) {
13220 if (srv->inet_ntop_cache[i].ts != 0) {
13221 @@ -20,31 +20,31 @@
13222 srv->inet_ntop_cache[i].addr.ipv4.s_addr == addr->ipv4.sin_addr.s_addr) {
13223 /* IPv4 found in cache */
13232 if (i == INET_NTOP_CACHE_MAX) {
13233 /* not found in cache */
13237 - inet_ntop(addr->plain.sa_family,
13238 - addr->plain.sa_family == AF_INET6 ?
13239 + inet_ntop(addr->plain.sa_family,
13240 + addr->plain.sa_family == AF_INET6 ?
13241 (const void *) &(addr->ipv6.sin6_addr) :
13242 (const void *) &(addr->ipv4.sin_addr),
13243 srv->inet_ntop_cache[i].b2, INET6_ADDRSTRLEN);
13246 srv->inet_ntop_cache[i].ts = srv->cur_ts;
13247 srv->inet_ntop_cache[i].family = addr->plain.sa_family;
13250 if (srv->inet_ntop_cache[i].family == AF_INET) {
13251 srv->inet_ntop_cache[i].addr.ipv4.s_addr = addr->ipv4.sin_addr.s_addr;
13252 } else if (srv->inet_ntop_cache[i].family == AF_INET6) {
13253 memcpy(srv->inet_ntop_cache[i].addr.ipv6.s6_addr, addr->ipv6.sin6_addr.s6_addr, 16);
13258 return srv->inet_ntop_cache[i].b2;
13261 --- ../lighttpd-1.4.11/src/iosocket.c 1970-01-01 03:00:00.000000000 +0300
13262 +++ lighttpd-1.4.12/src/iosocket.c 2006-07-18 13:03:40.000000000 +0300
13264 +#include <stdlib.h>
13266 +#include "iosocket.h"
13267 +#include "sys-socket.h"
13268 +#include "sys-files.h"
13269 +#include "array-static.h"
13271 +iosocket *iosocket_init(void) {
13272 + STRUCT_INIT(iosocket, sock);
13274 + sock->fde_ndx = -1;
13277 + sock->type = IOSOCKET_TYPE_SOCKET;
13282 +void iosocket_free(iosocket *sock) {
13283 + if (!sock) return;
13285 + if (sock->fd != -1) {
13286 + switch (sock->type) {
13287 + case IOSOCKET_TYPE_SOCKET:
13288 + closesocket(sock->fd);
13290 + case IOSOCKET_TYPE_PIPE:
13300 --- ../lighttpd-1.4.11/src/iosocket.h 1970-01-01 03:00:00.000000000 +0300
13301 +++ lighttpd-1.4.12/src/iosocket.h 2006-07-18 13:03:40.000000000 +0300
13303 +#ifndef _IOSOCKET_H_
13304 +#define _IOSOCKET_H_
13306 +#if defined HAVE_LIBSSL && defined HAVE_OPENSSL_SSL_H
13307 +# define USE_OPENSSL
13308 +# include <openssl/ssl.h>
13312 + IOSOCKET_TYPE_UNSET,
13313 + IOSOCKET_TYPE_SOCKET,
13314 + IOSOCKET_TYPE_PIPE
13318 + * a non-blocking fd
13324 +#ifdef USE_OPENSSL
13328 + iosocket_t type; /**< sendfile on solaris doesn't work on pipes */
13331 +iosocket *iosocket_init(void);
13332 +void iosocket_free(iosocket *sock);
13335 --- ../lighttpd-1.4.11/src/joblist.c 2005-08-11 01:26:41.000000000 +0300
13336 +++ lighttpd-1.4.12/src/joblist.c 2006-07-16 00:26:03.000000000 +0300
13339 int joblist_append(server *srv, connection *con) {
13340 if (con->in_joblist) return 0;
13343 if (srv->joblist->size == 0) {
13344 srv->joblist->size = 16;
13345 srv->joblist->ptr = malloc(sizeof(*srv->joblist->ptr) * srv->joblist->size);
13346 @@ -15,15 +15,15 @@
13347 srv->joblist->size += 16;
13348 srv->joblist->ptr = realloc(srv->joblist->ptr, sizeof(*srv->joblist->ptr) * srv->joblist->size);
13352 srv->joblist->ptr[srv->joblist->used++] = con;
13358 void joblist_free(server *srv, connections *joblist) {
13362 free(joblist->ptr);
13365 @@ -31,14 +31,14 @@
13366 connection *fdwaitqueue_unshift(server *srv, connections *fdwaitqueue) {
13373 if (fdwaitqueue->used == 0) return NULL;
13376 con = fdwaitqueue->ptr[0];
13379 memmove(fdwaitqueue->ptr, &(fdwaitqueue->ptr[1]), --fdwaitqueue->used * sizeof(*(fdwaitqueue->ptr)));
13386 srv->fdwaitqueue->size += 16;
13387 srv->fdwaitqueue->ptr = realloc(srv->fdwaitqueue->ptr, sizeof(*(srv->fdwaitqueue->ptr)) * srv->fdwaitqueue->size);
13391 srv->fdwaitqueue->ptr[srv->fdwaitqueue->used++] = con;
13397 --- ../lighttpd-1.4.11/src/keyvalue.c 2006-03-02 16:08:06.000000000 +0200
13398 +++ lighttpd-1.4.12/src/keyvalue.c 2006-07-16 00:26:03.000000000 +0300
13400 { 504, "Gateway Timeout" },
13401 { 505, "HTTP Version Not Supported" },
13402 { 507, "Insufficient Storage" }, /* WebDAV */
13404 + { 509, "Bandwidth Limit exceeded" },
13409 @@ -102,12 +103,12 @@
13410 { 501, "501.html" },
13411 { 503, "503.html" },
13412 { 505, "505.html" },
13419 -const char *keyvalue_get_value(keyvalue *kv, int k) {
13420 +const char *keyvalue_get_value(keyvalue *kv, int k) {
13422 for (i = 0; kv[i].value; i++) {
13423 if (kv[i].key == k) return kv[i].value;
13424 @@ -115,7 +116,7 @@
13428 -int keyvalue_get_key(keyvalue *kv, const char *s) {
13429 +int keyvalue_get_key(keyvalue *kv, const char *s) {
13431 for (i = 0; kv[i].value; i++) {
13432 if (0 == strcmp(kv[i].value, s)) return kv[i].key;
13433 @@ -125,9 +126,9 @@
13435 keyvalue_buffer *keyvalue_buffer_init(void) {
13436 keyvalue_buffer *kvb;
13439 kvb = calloc(1, sizeof(*kvb));
13445 @@ -135,49 +136,49 @@
13447 if (kvb->size == 0) {
13451 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13454 for(i = 0; i < kvb->size; i++) {
13455 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13457 } else if (kvb->used == kvb->size) {
13461 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13464 for(i = kvb->used; i < kvb->size; i++) {
13465 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13470 kvb->kv[kvb->used]->key = key;
13471 kvb->kv[kvb->used]->value = strdup(value);
13480 void keyvalue_buffer_free(keyvalue_buffer *kvb) {
13484 for (i = 0; i < kvb->size; i++) {
13485 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13490 if (kvb->kv) free(kvb->kv);
13497 s_keyvalue_buffer *s_keyvalue_buffer_init(void) {
13498 s_keyvalue_buffer *kvb;
13501 kvb = calloc(1, sizeof(*kvb));
13507 @@ -186,50 +187,50 @@
13508 if (kvb->size == 0) {
13513 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13516 for(i = 0; i < kvb->size; i++) {
13517 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13519 } else if (kvb->used == kvb->size) {
13523 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13526 for(i = kvb->used; i < kvb->size; i++) {
13527 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13532 kvb->kv[kvb->used]->key = key ? strdup(key) : NULL;
13533 kvb->kv[kvb->used]->value = strdup(value);
13542 void s_keyvalue_buffer_free(s_keyvalue_buffer *kvb) {
13546 for (i = 0; i < kvb->size; i++) {
13547 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13548 if (kvb->kv[i]->value) free(kvb->kv[i]->value);
13553 if (kvb->kv) free(kvb->kv);
13560 httpauth_keyvalue_buffer *httpauth_keyvalue_buffer_init(void) {
13561 httpauth_keyvalue_buffer *kvb;
13564 kvb = calloc(1, sizeof(*kvb));
13570 @@ -237,42 +238,42 @@
13572 if (kvb->size == 0) {
13576 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13579 for(i = 0; i < kvb->size; i++) {
13580 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13582 } else if (kvb->used == kvb->size) {
13586 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13589 for(i = kvb->used; i < kvb->size; i++) {
13590 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13595 kvb->kv[kvb->used]->key = strdup(key);
13596 kvb->kv[kvb->used]->realm = strdup(realm);
13597 kvb->kv[kvb->used]->type = type;
13606 void httpauth_keyvalue_buffer_free(httpauth_keyvalue_buffer *kvb) {
13610 for (i = 0; i < kvb->size; i++) {
13611 if (kvb->kv[i]->key) free(kvb->kv[i]->key);
13612 if (kvb->kv[i]->realm) free(kvb->kv[i]->realm);
13617 if (kvb->kv) free(kvb->kv);
13623 @@ -306,9 +307,9 @@
13625 pcre_keyvalue_buffer *pcre_keyvalue_buffer_init(void) {
13626 pcre_keyvalue_buffer *kvb;
13629 kvb = calloc(1, sizeof(*kvb));
13635 @@ -319,46 +320,46 @@
13641 if (!key) return -1;
13644 if (kvb->size == 0) {
13649 kvb->kv = malloc(kvb->size * sizeof(*kvb->kv));
13652 for(i = 0; i < kvb->size; i++) {
13653 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13655 } else if (kvb->used == kvb->size) {
13659 kvb->kv = realloc(kvb->kv, kvb->size * sizeof(*kvb->kv));
13662 for(i = kvb->used; i < kvb->size; i++) {
13663 kvb->kv[i] = calloc(1, sizeof(**kvb->kv));
13668 kv = kvb->kv[kvb->used];
13669 if (NULL == (kv->key = pcre_compile(key,
13670 0, &errptr, &erroff, NULL))) {
13673 fprintf(stderr, "%s.%d: rexexp compilation error at %s\n", __FILE__, __LINE__, errptr);
13677 - if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13678 + if (NULL == (kv->key_extra = pcre_study(kv->key, 0, &errptr)) &&
13684 kv->value = buffer_init_string(value);
13693 @@ -380,9 +381,9 @@
13694 if (kv->value) buffer_free(kv->value);
13699 if (kvb->kv) free(kvb->kv);
13705 --- ../lighttpd-1.4.11/src/keyvalue.h 2006-03-02 16:08:06.000000000 +0200
13706 +++ lighttpd-1.4.12/src/keyvalue.h 2006-07-16 00:26:04.000000000 +0300
13712 - HTTP_METHOD_UNSET = -1,
13714 - HTTP_METHOD_POST,
13715 - HTTP_METHOD_HEAD,
13716 - HTTP_METHOD_OPTIONS,
13718 + HTTP_METHOD_UNSET = -1,
13720 + HTTP_METHOD_POST,
13721 + HTTP_METHOD_HEAD,
13722 + HTTP_METHOD_OPTIONS,
13723 HTTP_METHOD_PROPFIND, /* WebDAV */
13724 - HTTP_METHOD_MKCOL,
13726 - HTTP_METHOD_DELETE,
13727 - HTTP_METHOD_COPY,
13728 - HTTP_METHOD_MOVE,
13729 - HTTP_METHOD_PROPPATCH,
13730 + HTTP_METHOD_MKCOL,
13732 + HTTP_METHOD_DELETE,
13733 + HTTP_METHOD_COPY,
13734 + HTTP_METHOD_MOVE,
13735 + HTTP_METHOD_PROPPATCH,
13736 HTTP_METHOD_REPORT, /* DeltaV */
13737 HTTP_METHOD_CHECKOUT,
13738 HTTP_METHOD_CHECKIN,
13739 @@ -39,13 +39,13 @@
13757 pcre_extra *key_extra;
13771 httpauth_type type;
13772 } httpauth_keyvalue;
13773 --- ../lighttpd-1.4.11/src/lemon.c 2005-09-01 00:21:34.000000000 +0300
13774 +++ lighttpd-1.4.12/src/lemon.c 2006-07-16 00:26:03.000000000 +0300
13775 @@ -579,7 +579,7 @@
13778 /* Find a precedence symbol of every rule in the grammar.
13781 ** Those rules which have a precedence symbol coded in the input
13782 ** grammar using the "[symbol]" construct will already have the
13783 ** rp->precsym field filled. Other rules take as their precedence
13784 @@ -869,7 +869,7 @@
13785 cfp->status = INCOMPLETE;
13792 for(i=0; i<lemp->nstate; i++){
13793 @@ -900,7 +900,7 @@
13797 - /* Add all of the reduce actions
13798 + /* Add all of the reduce actions
13799 ** A reduce action is added for each element of the followset of
13800 ** a configuration which has its dot at the extreme right.
13802 @@ -1017,7 +1017,7 @@
13803 apx->type = RD_RESOLVED;
13808 apx->type==SH_RESOLVED ||
13809 apx->type==RD_RESOLVED ||
13810 apx->type==CONFLICT ||
13811 @@ -1350,7 +1350,7 @@
13812 OptInit(argv,options,stderr);
13814 printf("Lemon version 1.0\n");
13818 if( OptNArgs() < 1 ){
13819 fprintf(stderr,"Exactly one filename argument is required.\n");
13820 @@ -2031,7 +2031,7 @@
13824 - rp = (struct rule *)malloc( sizeof(struct rule) +
13825 + rp = (struct rule *)malloc( sizeof(struct rule) +
13826 sizeof(struct symbol*)*psp->nrhs + sizeof(char*)*psp->nrhs );
13828 ErrorMsg(psp->filename,psp->tokenlineno,
13829 @@ -2546,7 +2546,7 @@
13833 -/* Duplicate the input file without comments and without actions
13834 +/* Duplicate the input file without comments and without actions
13837 struct lemon *lemp;
13838 @@ -2822,7 +2822,7 @@
13839 PRIVATE FILE *tplt_open(lemp)
13840 struct lemon *lemp;
13847 @@ -2930,7 +2930,7 @@
13853 ** Generate code which executes when the rule "rp" is reduced. Write
13854 ** the code to "out". Make sure lineno stays up-to-date.
13856 @@ -3384,7 +3384,7 @@
13858 /* Output the yy_shift_ofst[] table */
13859 fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
13860 - fprintf(out, "static %s yy_shift_ofst[] = {\n",
13861 + fprintf(out, "static %s yy_shift_ofst[] = {\n",
13862 minimum_size_type(mnTknOfst-1, mxTknOfst)); lineno++;
13864 for(i=j=0; i<n; i++){
13865 @@ -3405,7 +3405,7 @@
13867 /* Output the yy_reduce_ofst[] table */
13868 fprintf(out, "#define YY_REDUCE_USE_DFLT (%d)\n", mnNtOfst-1); lineno++;
13869 - fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13870 + fprintf(out, "static %s yy_reduce_ofst[] = {\n",
13871 minimum_size_type(mnNtOfst-1, mxNtOfst)); lineno++;
13873 for(i=j=0; i<n; i++){
13874 @@ -3480,7 +3480,7 @@
13875 tplt_xfer(lemp->name,in,out,&lineno);
13877 /* Generate code which executes every time a symbol is popped from
13878 - ** the stack while processing errors or while destroying the parser.
13879 + ** the stack while processing errors or while destroying the parser.
13880 ** (In other words, generate the %destructor actions)
13882 if( lemp->tokendest ){
13883 @@ -3522,7 +3522,7 @@
13884 tplt_print(out,lemp,lemp->overflow,lemp->overflowln,&lineno);
13885 tplt_xfer(lemp->name,in,out,&lineno);
13887 - /* Generate the table of rule information
13888 + /* Generate the table of rule information
13890 ** Note: This code depends on the fact that rules are number
13891 ** sequentually beginning with 0.
13892 @@ -3589,7 +3589,7 @@
13893 for(i=1; i<lemp->nterminal; i++){
13894 fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
13901 @@ -3630,7 +3630,7 @@
13907 /* Do not make a default if the number of rules to default
13908 ** is not at least 2 */
13909 if( nbest<2 ) continue;
13910 @@ -3781,7 +3781,7 @@
13914 - x1a->tbl = (x1node*)malloc(
13915 + x1a->tbl = (x1node*)malloc(
13916 (sizeof(x1node) + sizeof(x1node*))*1024 );
13919 @@ -3943,7 +3943,7 @@
13923 - x2a->tbl = (x2node*)malloc(
13924 + x2a->tbl = (x2node*)malloc(
13925 (sizeof(x2node) + sizeof(x2node*))*128 );
13928 @@ -4149,7 +4149,7 @@
13932 - x3a->tbl = (x3node*)malloc(
13933 + x3a->tbl = (x3node*)malloc(
13934 (sizeof(x3node) + sizeof(x3node*))*128 );
13937 @@ -4295,7 +4295,7 @@
13941 - x4a->tbl = (x4node*)malloc(
13942 + x4a->tbl = (x4node*)malloc(
13943 (sizeof(x4node) + sizeof(x4node*))*64 );
13946 --- ../lighttpd-1.4.11/src/lempar.c 2005-08-11 01:26:40.000000000 +0300
13947 +++ lighttpd-1.4.12/src/lempar.c 2006-07-16 00:26:03.000000000 +0300
13949 /* Next is all token values, in a form suitable for use by makeheaders.
13950 ** This section will be null unless lemon is run with the -m switch.
13954 ** These constants (all generated automatically by the parser generator)
13955 ** specify the various kinds of tokens (terminals) that the parser
13959 ** Each symbol here is a terminal symbol in the grammar.
13962 ** and nonterminals. "int" is used otherwise.
13963 ** YYNOCODE is a number of type YYCODETYPE which corresponds
13964 ** to no legal terminal or nonterminal number. This
13965 -** number is used to fill in empty slots of the hash
13966 +** number is used to fill in empty slots of the hash
13968 ** YYFALLBACK If defined, this indicates that one or more tokens
13969 ** have fall-back values which should be used if the
13971 ** and nonterminal numbers. "unsigned char" is
13972 ** used if there are fewer than 250 rules and
13973 ** states combined. "int" is used otherwise.
13974 -** ParseTOKENTYPE is the data type used for minor tokens given
13975 +** ParseTOKENTYPE is the data type used for minor tokens given
13976 ** directly to the parser from the tokenizer.
13977 ** YYMINORTYPE is the data type used for all minor tokens.
13978 ** This is typically a union of many types, one of
13980 /* Next are that tables used to determine what action to take based on the
13981 ** current state and lookahead token. These tables are used to implement
13982 ** functions that take a state number and lookahead value and return an
13983 -** action integer.
13984 +** action integer.
13986 ** Suppose the action integer is N. Then the action is determined as
13989 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
13990 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
13991 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
13992 -** and that yy_default[S] should be used instead.
13993 +** and that yy_default[S] should be used instead.
13995 ** The formula above is for computing the action when the lookahead is
13996 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
13997 @@ -111,7 +111,7 @@
13999 /* The next table maps tokens into fallback tokens. If a construct
14000 ** like the following:
14003 ** %fallback ID X Y Z.
14005 ** appears in the grammer, then ID becomes a fallback token for X, Y,
14006 @@ -163,10 +163,10 @@
14007 #endif /* NDEBUG */
14012 ** Turn parser tracing on by giving a stream to which to write the trace
14013 ** and a prompt to preface each trace message. Tracing is turned off
14014 -** by making either argument NULL
14015 +** by making either argument NULL
14019 @@ -191,7 +191,7 @@
14021 /* For tracing shifts, the names of all terminals and nonterminals
14022 ** are required. The following table supplies these names */
14023 -static const char *yyTokenName[] = {
14024 +static const char *yyTokenName[] = {
14027 #endif /* NDEBUG */
14028 @@ -220,7 +220,7 @@
14034 ** This function allocates a new parser.
14035 ** The only argument is a pointer to a function which works like
14037 @@ -251,7 +251,7 @@
14038 /* Here is inserted the actions which take place when a
14039 ** terminal or non-terminal is destroyed. This can happen
14040 ** when the symbol is popped from the stack during a
14041 - ** reduce or during error processing or when a parser is
14042 + ** reduce or during error processing or when a parser is
14043 ** being destroyed before it is finished parsing.
14045 ** Note: during a reduce, the only symbols destroyed are those
14046 @@ -289,7 +289,7 @@
14052 ** Deallocate and destroy a parser. Destructors are all called for
14053 ** all stack elements before shutting the parser down.
14055 @@ -325,7 +325,7 @@
14058 int stateno = pParser->yystack[pParser->yyidx].stateno;
14061 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
14062 i = yy_shift_ofst[stateno];
14063 if( i==YY_SHIFT_USE_DFLT ){
14064 @@ -369,7 +369,7 @@
14067 int stateno = pParser->yystack[pParser->yyidx].stateno;
14070 i = yy_reduce_ofst[stateno];
14071 if( i==YY_REDUCE_USE_DFLT ){
14072 return yy_default[stateno];
14073 @@ -455,7 +455,7 @@
14075 yymsp = &yypParser->yystack[yypParser->yyidx];
14077 - if( yyTraceFILE && yyruleno>=0
14078 + if( yyTraceFILE && yyruleno>=0
14079 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
14080 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
14081 yyRuleName[yyruleno]);
14082 @@ -608,7 +608,7 @@
14083 #ifdef YYERRORSYMBOL
14084 /* A syntax error has occurred.
14085 ** The response to an error depends upon whether or not the
14086 - ** grammar defines an error token "ERROR".
14087 + ** grammar defines an error token "ERROR".
14089 ** This is what we do if the grammar does define ERROR:
14091 --- ../lighttpd-1.4.11/src/log.c 2005-11-07 15:01:35.000000000 +0200
14092 +++ lighttpd-1.4.12/src/log.c 2006-07-18 13:03:40.000000000 +0300
14097 -#include <unistd.h>
14098 #include <string.h>
14099 #include <stdlib.h>
14102 #include "config.h"
14106 +#undef HAVE_SYSLOG_H
14109 #ifdef HAVE_SYSLOG_H
14110 #include <syslog.h>
14116 +#include "sys-files.h"
14118 #ifdef HAVE_VALGRIND_VALGRIND_H
14119 #include <valgrind/valgrind.h>
14121 @@ -31,55 +36,114 @@
14122 # define O_LARGEFILE 0
14127 * open the errorlog
14130 * we have 3 possibilities:
14131 * - stderr (default)
14137 * if the open failed, report to the user and die
14142 -int log_error_open(server *srv) {
14146 + unsigned short use_syslog;
14148 + /* the errorlog */
14150 - int close_stderr = 1;
14151 + enum { ERRORLOG_STDERR, ERRORLOG_FILE, ERRORLOG_SYSLOG } mode;
14154 + time_t cached_ts;
14155 + buffer *cached_ts_str;
14158 +errorlog *myconfig = NULL;
14160 +void log_init(void) {
14164 + err = calloc(1, sizeof(*err));
14167 + err->mode = ERRORLOG_STDERR;
14168 + err->buf = buffer_init();
14169 + err->cached_ts_str = buffer_init();
14174 +void log_free(void) {
14175 + errorlog *err = myconfig;
14177 + if (!err) return;
14179 + TRACE("%s", "server stopped");
14181 + switch(err->mode) {
14182 + case ERRORLOG_FILE:
14185 + case ERRORLOG_SYSLOG:
14186 +#ifdef HAVE_SYSLOG_H
14190 + case ERRORLOG_STDERR:
14194 + buffer_free(err->buf);
14195 + buffer_free(err->cached_ts_str);
14196 + if (err->file) buffer_free(err->file);
14203 +int log_error_open(buffer *file, int use_syslog) {
14205 + int close_stderr = 1;
14207 + errorlog *err = myconfig;
14209 #ifdef HAVE_SYSLOG_H
14210 /* perhaps someone wants to use syslog() */
14211 openlog("lighttpd", LOG_CONS | LOG_PID, LOG_DAEMON);
14213 - srv->errorlog_mode = ERRORLOG_STDERR;
14215 - if (srv->srvconf.errorlog_use_syslog) {
14216 - srv->errorlog_mode = ERRORLOG_SYSLOG;
14217 - } else if (!buffer_is_empty(srv->srvconf.errorlog_file)) {
14218 - const char *logfile = srv->srvconf.errorlog_file->ptr;
14220 - if (-1 == (srv->errorlog_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14221 - log_error_write(srv, __FILE__, __LINE__, "SSSS",
14222 - "opening errorlog '", logfile,
14223 + err->mode = ERRORLOG_STDERR;
14225 + if (use_syslog) {
14226 + err->mode = ERRORLOG_SYSLOG;
14227 + } else if (!buffer_is_empty(file)) {
14228 + if (-1 == (err->fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14229 + log_error_write(NULL, __FILE__, __LINE__, "SBSS",
14230 + "opening errorlog '", file,
14231 "' failed: ", strerror(errno));
14237 /* close fd on exec (cgi) */
14238 - fcntl(srv->errorlog_fd, F_SETFD, FD_CLOEXEC);
14239 + fcntl(err->fd, F_SETFD, FD_CLOEXEC);
14241 - srv->errorlog_mode = ERRORLOG_FILE;
14242 + err->mode = ERRORLOG_FILE;
14245 - log_error_write(srv, __FILE__, __LINE__, "s", "server started");
14248 + TRACE("%s", "server started");
14250 #ifdef HAVE_VALGRIND_VALGRIND_H
14251 /* don't close stderr for debugging purposes if run in valgrind */
14252 if (RUNNING_ON_VALGRIND) close_stderr = 0;
14254 - if (srv->errorlog_mode == ERRORLOG_STDERR) close_stderr = 0;
14256 + if (err->mode == ERRORLOG_STDERR) close_stderr = 0;
14258 /* move stderr to /dev/null */
14259 if (close_stderr &&
14260 -1 != (fd = open("/dev/null", O_WRONLY))) {
14261 @@ -90,167 +154,202 @@
14267 * open the errorlog
14270 * if the open failed, report to the user and die
14271 * if no filename is given, use syslog instead
14276 -int log_error_cycle(server *srv) {
14277 +int log_error_cycle(void) {
14278 /* only cycle if we are not in syslog-mode */
14280 - if (srv->errorlog_mode == ERRORLOG_FILE) {
14281 - const char *logfile = srv->srvconf.errorlog_file->ptr;
14283 + errorlog *err = myconfig;
14285 + if (err->mode == ERRORLOG_FILE) {
14286 + buffer *file = err->file;
14287 /* already check of opening time */
14292 - if (-1 == (new_fd = open(logfile, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14294 + if (-1 == (new_fd = open(file->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
14295 /* write to old log */
14296 - log_error_write(srv, __FILE__, __LINE__, "SSSSS",
14297 - "cycling errorlog '", logfile,
14298 + log_error_write(NULL, __FILE__, __LINE__, "SBSSS",
14299 + "cycling errorlog '", file,
14300 "' failed: ", strerror(errno),
14301 ", falling back to syslog()");
14303 - close(srv->errorlog_fd);
14304 - srv->errorlog_fd = -1;
14305 -#ifdef HAVE_SYSLOG_H
14306 - srv->errorlog_mode = ERRORLOG_SYSLOG;
14310 +#ifdef HAVE_SYSLOG_H
14311 + err->mode = ERRORLOG_SYSLOG;
14314 /* ok, new log is open, close the old one */
14315 - close(srv->errorlog_fd);
14316 - srv->errorlog_fd = new_fd;
14318 + err->fd = new_fd;
14322 - log_error_write(srv, __FILE__, __LINE__, "s", "logfiles cycled");
14327 -int log_error_close(server *srv) {
14328 - log_error_write(srv, __FILE__, __LINE__, "s", "server stopped");
14330 - switch(srv->errorlog_mode) {
14331 - case ERRORLOG_FILE:
14332 - close(srv->errorlog_fd);
14334 - case ERRORLOG_SYSLOG:
14335 -#ifdef HAVE_SYSLOG_H
14339 - case ERRORLOG_STDERR:
14343 + TRACE("%s", "logfiles cycled");
14348 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14349 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...) {
14352 - switch(srv->errorlog_mode) {
14355 + errorlog *err = myconfig;
14357 + switch(err->mode) {
14358 case ERRORLOG_FILE:
14359 case ERRORLOG_STDERR:
14360 /* cache the generated timestamp */
14361 - if (srv->cur_ts != srv->last_generated_debug_ts) {
14362 - buffer_prepare_copy(srv->ts_debug_str, 255);
14363 - strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
14364 - srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;
14366 - srv->last_generated_debug_ts = srv->cur_ts;
14369 + if (t != err->cached_ts) {
14370 + buffer_prepare_copy(err->cached_ts_str, 255);
14371 + strftime(err->cached_ts_str->ptr, err->cached_ts_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(t)));
14372 + err->cached_ts_str->used = strlen(err->cached_ts_str->ptr) + 1;
14373 + err->cached_ts = t;
14376 - buffer_copy_string_buffer(srv->errorlog_buf, srv->ts_debug_str);
14377 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ": (");
14378 + buffer_copy_string_buffer(err->buf, err->cached_ts_str);
14379 + BUFFER_APPEND_STRING_CONST(err->buf, ": (");
14381 case ERRORLOG_SYSLOG:
14382 /* syslog is generating its own timestamps */
14383 - BUFFER_COPY_STRING_CONST(srv->errorlog_buf, "(");
14384 + BUFFER_COPY_STRING_CONST(err->buf, "(");
14388 - buffer_append_string(srv->errorlog_buf, filename);
14389 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ".");
14390 - buffer_append_long(srv->errorlog_buf, line);
14391 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, ") ");
14395 + buffer_append_string(err->buf, filename);
14396 + BUFFER_APPEND_STRING_CONST(err->buf, ".");
14397 + buffer_append_long(err->buf, line);
14398 + BUFFER_APPEND_STRING_CONST(err->buf, ") ");
14400 for(va_start(ap, fmt); *fmt; fmt++) {
14408 case 's': /* string */
14409 s = va_arg(ap, char *);
14410 - buffer_append_string(srv->errorlog_buf, s);
14411 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14412 + buffer_append_string(err->buf, s);
14413 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14415 case 'b': /* buffer */
14416 b = va_arg(ap, buffer *);
14417 - buffer_append_string_buffer(srv->errorlog_buf, b);
14418 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14419 + buffer_append_string_buffer(err->buf, b);
14420 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14422 case 'd': /* int */
14423 d = va_arg(ap, int);
14424 - buffer_append_long(srv->errorlog_buf, d);
14425 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14426 + buffer_append_long(err->buf, d);
14427 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14429 case 'o': /* off_t */
14430 o = va_arg(ap, off_t);
14431 - buffer_append_off_t(srv->errorlog_buf, o);
14432 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14433 + buffer_append_off_t(err->buf, o);
14434 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14436 case 'x': /* int (hex) */
14437 d = va_arg(ap, int);
14438 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "0x");
14439 - buffer_append_long_hex(srv->errorlog_buf, d);
14440 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, " ");
14441 + BUFFER_APPEND_STRING_CONST(err->buf, "0x");
14442 + buffer_append_long_hex(err->buf, d);
14443 + BUFFER_APPEND_STRING_CONST(err->buf, " ");
14445 case 'S': /* string */
14446 s = va_arg(ap, char *);
14447 - buffer_append_string(srv->errorlog_buf, s);
14448 + buffer_append_string(err->buf, s);
14450 case 'B': /* buffer */
14451 b = va_arg(ap, buffer *);
14452 - buffer_append_string_buffer(srv->errorlog_buf, b);
14453 + buffer_append_string_buffer(err->buf, b);
14455 case 'D': /* int */
14456 d = va_arg(ap, int);
14457 - buffer_append_long(srv->errorlog_buf, d);
14458 + buffer_append_long(err->buf, d);
14467 - buffer_append_string_len(srv->errorlog_buf, fmt, 1);
14468 + buffer_append_string_len(err->buf, fmt, 1);
14474 - switch(srv->errorlog_mode) {
14476 + switch(err->mode) {
14477 case ERRORLOG_FILE:
14478 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14479 - write(srv->errorlog_fd, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14480 + BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14481 + write(err->fd, err->buf->ptr, err->buf->used - 1);
14483 case ERRORLOG_STDERR:
14484 - BUFFER_APPEND_STRING_CONST(srv->errorlog_buf, "\n");
14485 - write(STDERR_FILENO, srv->errorlog_buf->ptr, srv->errorlog_buf->used - 1);
14486 + BUFFER_APPEND_STRING_CONST(err->buf, "\n");
14487 + write(STDERR_FILENO, err->buf->ptr, err->buf->used - 1);
14489 +#ifdef HAVE_SYSLOG_H
14490 + case ERRORLOG_SYSLOG:
14491 + syslog(LOG_ERR, "%s", err->buf->ptr);
14499 +static int log_trace_write(const char *fmt, va_list ap) {
14502 + errorlog *err = myconfig;
14504 + b = buffer_init();
14505 + buffer_prepare_copy(b, 1024);
14506 + l = vsnprintf(b->ptr, b->size - 1, fmt, ap);
14508 + b->used = (l > b->size - 1) ? b->size : l + 1;
14512 + switch(err->mode) {
14513 + case ERRORLOG_FILE:
14514 + buffer_append_string(b, "\r\n");
14515 + write(err->fd, b->ptr, b->used - 1);
14517 + case ERRORLOG_STDERR:
14518 + buffer_append_string(b, "\r\n");
14519 + write(STDERR_FILENO, b->ptr, b->used - 1);
14521 +#ifdef HAVE_SYSLOG_H
14522 case ERRORLOG_SYSLOG:
14523 - syslog(LOG_ERR, "%s", srv->errorlog_buf->ptr);
14524 + syslog(LOG_ERR, "%s", b->ptr);
14534 +int log_trace(const char *fmt, ...) {
14537 + va_start(ap, fmt);
14539 + log_trace_write(fmt, ap);
14547 --- ../lighttpd-1.4.11/src/log.h 2005-08-11 01:26:36.000000000 +0300
14548 +++ lighttpd-1.4.12/src/log.h 2006-07-18 13:03:40.000000000 +0300
14553 -#include "server.h"
14554 +#include "buffer.h"
14556 -#define WP() log_error_write(srv, __FILE__, __LINE__, "");
14557 +void log_init(void);
14558 +void log_free(void);
14560 -int log_error_open(server *srv);
14561 -int log_error_close(server *srv);
14562 -int log_error_write(server *srv, const char *filename, unsigned int line, const char *fmt, ...);
14563 -int log_error_cycle(server *srv);
14565 +int log_error_open(buffer *file, int use_syslog);
14566 +int log_error_close();
14567 +int log_error_write(void *srv, const char *filename, unsigned int line, const char *fmt, ...);
14568 +int log_error_cycle();
14570 +#define ERROR(fmt, ...) \
14571 + log_trace("%s.%d: (error) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14573 +#define TRACE(fmt, ...) \
14574 + log_trace("%s.%d: (trace) "fmt, __FILE__, __LINE__, __VA_ARGS__)
14576 +#define SEGFAULT() do { ERROR("%s", "Ooh, Ooh, Ooh. Something is not good ... going down"); abort(); } while(0)
14577 +int log_trace(const char *fmt, ...);
14579 --- ../lighttpd-1.4.11/src/md5.h 2005-11-17 16:20:40.000000000 +0200
14580 +++ lighttpd-1.4.12/src/md5.h 2006-07-16 00:26:04.000000000 +0300
14582 # include <inttypes.h>
14586 +#define UINT4 unsigned __int32
14587 +#define UINT2 unsigned __int16
14588 +#define POINTER unsigned char *
14590 #define UINT4 uint32_t
14591 #define UINT2 uint16_t
14592 #define POINTER unsigned char *
14597 --- ../lighttpd-1.4.11/src/mod_access.c 2006-01-14 19:44:54.000000000 +0200
14598 +++ lighttpd-1.4.12/src/mod_access.c 2006-07-16 00:26:04.000000000 +0300
14599 @@ -8,126 +8,125 @@
14601 #include "plugin.h"
14603 +#include "sys-strings.h"
14606 array *access_deny;
14613 plugin_config **config_storage;
14615 - plugin_config conf;
14617 + plugin_config conf;
14620 INIT_FUNC(mod_access_init) {
14624 p = calloc(1, sizeof(*p));
14630 FREE_FUNC(mod_access_free) {
14631 plugin_data *p = p_d;
14636 if (!p) return HANDLER_GO_ON;
14639 if (p->config_storage) {
14641 for (i = 0; i < srv->config_context->used; i++) {
14642 plugin_config *s = p->config_storage[i];
14645 array_free(s->access_deny);
14650 free(p->config_storage);
14657 return HANDLER_GO_ON;
14660 SETDEFAULTS_FUNC(mod_access_set_defaults) {
14661 plugin_data *p = p_d;
14664 - config_values_t cv[] = {
14666 + config_values_t cv[] = {
14667 { "url.access-deny", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
14668 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
14672 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
14675 for (i = 0; i < srv->config_context->used; i++) {
14679 s = calloc(1, sizeof(plugin_config));
14680 s->access_deny = array_init();
14683 cv[0].destination = s->access_deny;
14686 p->config_storage[i] = s;
14689 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
14690 return HANDLER_ERROR;
14695 return HANDLER_GO_ON;
14698 -#define PATCH(x) \
14699 - p->conf.x = s->x;
14700 static int mod_access_patch_connection(server *srv, connection *con, plugin_data *p) {
14702 plugin_config *s = p->config_storage[0];
14704 - PATCH(access_deny);
14706 + PATCH_OPTION(access_deny);
14708 /* skip the first, the global context */
14709 for (i = 1; i < srv->config_context->used; i++) {
14710 data_config *dc = (data_config *)srv->config_context->data[i];
14711 s = p->config_storage[i];
14714 /* condition didn't match */
14715 if (!config_check_cond(srv, con, dc)) continue;
14719 for (j = 0; j < dc->value->used; j++) {
14720 data_unset *du = dc->value->data[j];
14723 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.access-deny"))) {
14724 - PATCH(access_deny);
14725 + PATCH_OPTION(access_deny);
14735 URIHANDLER_FUNC(mod_access_uri_handler) {
14736 plugin_data *p = p_d;
14741 if (con->uri.path->used == 0) return HANDLER_GO_ON;
14744 mod_access_patch_connection(srv, con, p);
14747 s_len = con->uri.path->used - 1;
14750 for (k = 0; k < p->conf.access_deny->used; k++) {
14751 data_string *ds = (data_string *)p->conf.access_deny->data[k];
14752 int ct_len = ds->value->used - 1;
14755 if (ct_len > s_len) continue;
14758 if (ds->value->used == 0) continue;
14760 /* if we have a case-insensitive FS we have to lower-case the URI here too */
14761 @@ -135,18 +134,18 @@
14762 if (con->conf.force_lowercase_filenames) {
14763 if (0 == strncasecmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14764 con->http_status = 403;
14767 return HANDLER_FINISHED;
14770 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
14771 con->http_status = 403;
14774 return HANDLER_FINISHED;
14781 return HANDLER_GO_ON;
14783 @@ -155,13 +154,13 @@
14784 int mod_access_plugin_init(plugin *p) {
14785 p->version = LIGHTTPD_VERSION_ID;
14786 p->name = buffer_init_string("access");
14789 p->init = mod_access_init;
14790 p->set_defaults = mod_access_set_defaults;
14791 p->handle_uri_clean = mod_access_uri_handler;
14792 p->cleanup = mod_access_free;
14800 --- ../lighttpd-1.4.11/src/mod_accesslog.c 2006-01-31 14:01:43.000000000 +0200
14801 +++ lighttpd-1.4.12/src/mod_accesslog.c 2006-07-16 00:26:04.000000000 +0300
14804 #include <stdlib.h>
14805 #include <string.h>
14806 -#include <fcntl.h>
14807 -#include <unistd.h>
14808 +#include <fcntl.h> /* only the defines on windows */
14813 #include "inet_ntop_cache.h"
14815 #include "sys-socket.h"
14816 +#include "sys-files.h"
14818 #ifdef HAVE_SYSLOG_H
14819 # include <syslog.h>
14827 FORMAT_UNSUPPORTED,
14831 FORMAT_BYTES_OUT_NO_HEADER,
14835 FORMAT_REMOTE_ADDR,
14838 @@ -59,20 +59,20 @@
14839 FORMAT_CONNECTION_STATUS,
14844 FORMAT_RESPONSE_HEADER
14853 * "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""
14858 -const format_mapping fmap[] =
14860 +const format_mapping fmap[] =
14862 { '%', FORMAT_PERCENT },
14863 { 'h', FORMAT_REMOTE_HOST },
14864 { 'l', FORMAT_REMOTE_IDENT },
14866 { 's', FORMAT_STATUS },
14867 { 'b', FORMAT_BYTES_OUT_NO_HEADER },
14868 { 'i', FORMAT_HEADER },
14871 { 'a', FORMAT_REMOTE_ADDR },
14872 { 'A', FORMAT_LOCAL_ADDR },
14873 { 'B', FORMAT_BYTES_OUT_NO_HEADER },
14874 @@ -103,23 +103,23 @@
14875 { 'X', FORMAT_CONNECTION_STATUS },
14876 { 'I', FORMAT_BYTES_IN },
14877 { 'O', FORMAT_BYTES_OUT },
14880 { 'o', FORMAT_RESPONSE_HEADER },
14883 { '\0', FORMAT_UNSET }
14888 enum { FIELD_UNSET, FIELD_STRING, FIELD_FORMAT } type;
14896 format_field **ptr;
14902 @@ -128,39 +128,39 @@
14903 buffer *access_logfile;
14905 unsigned short use_syslog;
14911 time_t last_generated_accesslog_ts;
14912 time_t *last_generated_accesslog_ts_ptr;
14917 buffer *access_logbuffer;
14918 buffer *ts_accesslog_str;
14921 format_fields *parsed_format;
14928 plugin_config **config_storage;
14929 - plugin_config conf;
14930 + plugin_config conf;
14933 INIT_FUNC(mod_accesslog_init) {
14937 p = calloc(1, sizeof(*p));
14943 int accesslog_parse_format(server *srv, format_fields *fields, buffer *format) {
14944 size_t i, j, k = 0, start = 0;
14947 for (i = 0; i < format->used - 1; i++) {
14950 switch(format->ptr[i]) {
14953 @@ -173,19 +173,19 @@
14954 fields->size += 16;
14955 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14959 fields->ptr[fields->used] = malloc(sizeof(format_fields));
14960 fields->ptr[fields->used]->type = FIELD_STRING;
14961 fields->ptr[fields->used]->string = buffer_init();
14964 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
14973 /* we need a new field */
14976 if (fields->size == 0) {
14979 @@ -194,43 +194,43 @@
14980 fields->size += 16;
14981 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
14985 /* search for the terminating command */
14986 switch (format->ptr[i+1]) {
14992 for (j = 0; fmap[j].key != '\0'; j++) {
14993 if (fmap[j].key != format->ptr[i+2]) continue;
14999 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15000 fields->ptr[fields->used]->type = FIELD_FORMAT;
15001 fields->ptr[fields->used]->field = fmap[j].type;
15002 fields->ptr[fields->used]->string = NULL;
15012 if (fmap[j].key == '\0') {
15013 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15023 /* go forward to } */
15026 for (k = i+2; k < format->used - 1; k++) {
15027 if (format->ptr[k] == '}') break;
15031 if (k == format->used - 1) {
15032 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15034 @@ -239,62 +239,62 @@
15035 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15040 for (j = 0; fmap[j].key != '\0'; j++) {
15041 if (fmap[j].key != format->ptr[k+1]) continue;
15047 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15048 fields->ptr[fields->used]->type = FIELD_FORMAT;
15049 fields->ptr[fields->used]->field = fmap[j].type;
15050 fields->ptr[fields->used]->string = buffer_init();
15053 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + i + 2, k - (i + 2));
15063 if (fmap[j].key == '\0') {
15064 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[i+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 = NULL;
15094 if (fmap[j].key == '\0') {
15095 log_error_write(srv, __FILE__, __LINE__, "ss", "config: ", "failed");
15113 /* copy the string */
15114 if (fields->size == 0) {
15115 @@ -305,32 +305,32 @@
15116 fields->size += 16;
15117 fields->ptr = realloc(fields->ptr, fields->size * sizeof(format_fields * ));
15121 fields->ptr[fields->used] = malloc(sizeof(format_fields));
15122 fields->ptr[fields->used]->type = FIELD_STRING;
15123 fields->ptr[fields->used]->string = buffer_init();
15126 buffer_copy_string_len(fields->ptr[fields->used]->string, format->ptr + start, i - start);
15136 FREE_FUNC(mod_accesslog_free) {
15137 plugin_data *p = p_d;
15141 if (!p) return HANDLER_GO_ON;
15144 if (p->config_storage) {
15147 for (i = 0; i < srv->config_context->used; i++) {
15148 plugin_config *s = p->config_storage[i];
15153 if (s->access_logbuffer->used) {
15154 if (s->use_syslog) {
15155 # ifdef HAVE_SYSLOG_H
15156 @@ -342,14 +342,14 @@
15157 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15162 if (s->log_access_fd != -1) close(s->log_access_fd);
15165 buffer_free(s->ts_accesslog_str);
15166 buffer_free(s->access_logbuffer);
15167 buffer_free(s->format);
15168 buffer_free(s->access_logfile);
15171 if (s->parsed_format) {
15173 for (j = 0; j < s->parsed_format->used; j++) {
15174 @@ -359,36 +359,36 @@
15175 free(s->parsed_format->ptr);
15176 free(s->parsed_format);
15184 free(p->config_storage);
15191 return HANDLER_GO_ON;
15194 SETDEFAULTS_FUNC(log_access_open) {
15195 plugin_data *p = p_d;
15198 - config_values_t cv[] = {
15200 + config_values_t cv[] = {
15201 { "accesslog.filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15202 { "accesslog.use-syslog", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
15203 { "accesslog.format", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
15204 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15208 if (!p) return HANDLER_ERROR;
15211 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15214 for (i = 0; i < srv->config_context->used; i++) {
15218 s = calloc(1, sizeof(plugin_config));
15219 s->access_logfile = buffer_init();
15220 s->format = buffer_init();
15221 @@ -397,44 +397,44 @@
15222 s->log_access_fd = -1;
15223 s->last_generated_accesslog_ts = 0;
15224 s->last_generated_accesslog_ts_ptr = &(s->last_generated_accesslog_ts);
15229 cv[0].destination = s->access_logfile;
15230 cv[1].destination = &(s->use_syslog);
15231 cv[2].destination = s->format;
15234 p->config_storage[i] = s;
15237 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15238 return HANDLER_ERROR;
15242 if (i == 0 && buffer_is_empty(s->format)) {
15243 /* set a default logfile string */
15246 buffer_copy_string(s->format, "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"");
15253 if (s->format->used) {
15254 s->parsed_format = calloc(1, sizeof(*(s->parsed_format)));
15257 if (-1 == accesslog_parse_format(srv, s->parsed_format, s->format)) {
15259 - log_error_write(srv, __FILE__, __LINE__, "sb",
15260 + log_error_write(srv, __FILE__, __LINE__, "sb",
15261 "parsing accesslog-definition failed:", s->format);
15263 return HANDLER_ERROR;
15268 for (j = 0; j < s->parsed_format->used; j++) {
15269 switch (s->parsed_format->ptr[j]->type) {
15271 - log_error_write(srv, __FILE__, __LINE__, "ssds",
15272 + log_error_write(srv, __FILE__, __LINE__, "ssds",
15273 "config:", "format", s->parsed_format->ptr[j]->field,
15274 - s->parsed_format->ptr[j]->string ?
15275 + s->parsed_format->ptr[j]->string ?
15276 s->parsed_format->ptr[j]->string->ptr : "" );
15279 @@ -446,52 +446,52 @@
15285 if (s->use_syslog) {
15286 /* ignore the next checks */
15291 if (buffer_is_empty(s->access_logfile)) continue;
15294 if (s->access_logfile->ptr[0] == '|') {
15296 /* create write pipe and spawn process */
15303 if (pipe(to_log_fds)) {
15304 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed: ", strerror(errno));
15305 return HANDLER_ERROR;
15310 switch (pid = fork()) {
15316 close(STDIN_FILENO);
15317 dup2(to_log_fds[0], STDIN_FILENO);
15318 close(to_log_fds[0]);
15320 close(to_log_fds[1]);
15323 /* we don't need the client socket */
15324 for (i = 3; i < 256; i++) {
15328 - /* exec the log-process (skip the | )
15331 + /* exec the log-process (skip the | )
15336 execl("/bin/sh", "sh", "-c", s->access_logfile->ptr + 1, NULL);
15338 - log_error_write(srv, __FILE__, __LINE__, "sss",
15339 - "spawning log-process failed: ", strerror(errno),
15340 + log_error_write(srv, __FILE__, __LINE__, "sss",
15341 + "spawning log-process failed: ", strerror(errno),
15342 s->access_logfile->ptr + 1);
15348 @@ -500,27 +500,28 @@
15351 close(to_log_fds[0]);
15354 s->log_access_fd = to_log_fds[1];
15362 - } else if (-1 == (s->log_access_fd =
15363 + } else if (-1 == (s->log_access_fd =
15364 open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15366 - log_error_write(srv, __FILE__, __LINE__, "ssb",
15367 - "opening access-log failed:",
15369 + log_error_write(srv, __FILE__, __LINE__, "ssb",
15370 + "opening access-log failed:",
15371 strerror(errno), s->access_logfile);
15374 return HANDLER_ERROR;
15377 fcntl(s->log_access_fd, F_SETFD, FD_CLOEXEC);
15383 return HANDLER_GO_ON;
15386 @@ -529,7 +530,7 @@
15389 if (!p->config_storage) return HANDLER_GO_ON;
15392 for (i = 0; i < srv->config_context->used; i++) {
15393 plugin_config *s = p->config_storage[i];
15395 @@ -544,90 +545,87 @@
15396 } else if (s->log_access_fd != -1) {
15397 write(s->log_access_fd, s->access_logbuffer->ptr, s->access_logbuffer->used - 1);
15401 buffer_reset(s->access_logbuffer);
15405 if (s->use_syslog == 0 &&
15406 !buffer_is_empty(s->access_logfile) &&
15407 s->access_logfile->ptr[0] != '|') {
15410 close(s->log_access_fd);
15412 - if (-1 == (s->log_access_fd =
15414 + if (-1 == (s->log_access_fd =
15415 open(s->access_logfile->ptr, O_APPEND | O_WRONLY | O_CREAT | O_LARGEFILE, 0644))) {
15418 log_error_write(srv, __FILE__, __LINE__, "ss", "cycling access-log failed:", strerror(errno));
15421 return HANDLER_ERROR;
15427 return HANDLER_GO_ON;
15430 -#define PATCH(x) \
15431 - p->conf.x = s->x;
15432 static int mod_accesslog_patch_connection(server *srv, connection *con, plugin_data *p) {
15434 plugin_config *s = p->config_storage[0];
15436 - PATCH(access_logfile);
15438 - PATCH(log_access_fd);
15439 - PATCH(last_generated_accesslog_ts_ptr);
15440 - PATCH(access_logbuffer);
15441 - PATCH(ts_accesslog_str);
15442 - PATCH(parsed_format);
15443 - PATCH(use_syslog);
15446 + PATCH_OPTION(access_logfile);
15447 + PATCH_OPTION(format);
15448 + PATCH_OPTION(log_access_fd);
15449 + PATCH_OPTION(last_generated_accesslog_ts_ptr);
15450 + PATCH_OPTION(access_logbuffer);
15451 + PATCH_OPTION(ts_accesslog_str);
15452 + PATCH_OPTION(parsed_format);
15453 + PATCH_OPTION(use_syslog);
15455 /* skip the first, the global context */
15456 for (i = 1; i < srv->config_context->used; i++) {
15457 data_config *dc = (data_config *)srv->config_context->data[i];
15458 s = p->config_storage[i];
15461 /* condition didn't match */
15462 if (!config_check_cond(srv, con, dc)) continue;
15466 for (j = 0; j < dc->value->used; j++) {
15467 data_unset *du = dc->value->data[j];
15470 if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.filename"))) {
15471 - 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_OPTION(access_logfile);
15477 + PATCH_OPTION(log_access_fd);
15478 + PATCH_OPTION(last_generated_accesslog_ts_ptr);
15479 + PATCH_OPTION(access_logbuffer);
15480 + PATCH_OPTION(ts_accesslog_str);
15481 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.format"))) {
15483 - PATCH(parsed_format);
15484 + PATCH_OPTION(format);
15485 + PATCH_OPTION(parsed_format);
15486 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("accesslog.use-syslog"))) {
15487 - PATCH(use_syslog);
15488 + PATCH_OPTION(use_syslog);
15498 REQUESTDONE_FUNC(log_access_write) {
15499 plugin_data *p = p_d;
15508 mod_accesslog_patch_connection(srv, con, p);
15511 b = p->conf.access_logbuffer;
15512 if (b->used == 0) {
15513 buffer_copy_string(b, "");
15517 for (j = 0; j < p->conf.parsed_format->used; j++) {
15518 switch(p->conf.parsed_format->ptr[j]->type) {
15520 @@ -636,14 +634,14 @@
15522 switch(p->conf.parsed_format->ptr[j]->field) {
15523 case FORMAT_TIMESTAMP:
15526 /* cache the generated timestamp */
15527 if (srv->cur_ts != *(p->conf.last_generated_accesslog_ts_ptr)) {
15529 #if defined(HAVE_STRUCT_TM_GMTOFF)
15530 long scd, hrs, min;
15534 buffer_prepare_copy(p->conf.ts_accesslog_str, 255);
15535 #if defined(HAVE_STRUCT_TM_GMTOFF)
15536 # ifdef HAVE_LOCALTIME_R
15537 @@ -653,17 +651,17 @@
15538 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)));
15540 p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15543 buffer_append_string(p->conf.ts_accesslog_str, tm.tm_gmtoff >= 0 ? "+" : "-");
15546 scd = abs(tm.tm_gmtoff);
15548 min = (scd % 3600) / 60;
15552 if (hrs < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15553 buffer_append_long(p->conf.ts_accesslog_str, hrs);
15556 if (min < 10) buffer_append_string(p->conf.ts_accesslog_str, "0");
15557 buffer_append_long(p->conf.ts_accesslog_str, min);
15558 BUFFER_APPEND_STRING_CONST(p->conf.ts_accesslog_str, "]");
15559 @@ -676,20 +674,20 @@
15561 p->conf.ts_accesslog_str->used = strlen(p->conf.ts_accesslog_str->ptr) + 1;
15565 *(p->conf.last_generated_accesslog_ts_ptr) = srv->cur_ts;
15570 buffer_append_string_buffer(b, p->conf.ts_accesslog_str);
15574 case FORMAT_REMOTE_HOST:
15577 /* handle inet_ntop cache */
15580 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
15584 case FORMAT_REMOTE_IDENT:
15586 @@ -710,10 +708,10 @@
15587 case FORMAT_STATUS:
15588 buffer_append_long(b, con->http_status);
15592 case FORMAT_BYTES_OUT_NO_HEADER:
15593 if (con->bytes_written > 0) {
15594 - buffer_append_off_t(b,
15595 + buffer_append_off_t(b,
15596 con->bytes_written - con->bytes_header <= 0 ? 0 : con->bytes_written - con->bytes_header);
15598 BUFFER_APPEND_STRING_CONST(b, "-");
15599 @@ -772,7 +770,7 @@
15602 case FORMAT_REQUEST_PROTOCOL:
15603 - buffer_append_string(b,
15604 + buffer_append_string(b,
15605 con->request.http_version == HTTP_VERSION_1_1 ? "HTTP/1.1" : "HTTP/1.0");
15607 case FORMAT_REQUEST_METHOD:
15608 @@ -801,7 +799,7 @@
15609 { 'D', FORMAT_TIME_USED_MS },
15610 { 'e', FORMAT_ENV },
15617 @@ -809,7 +807,7 @@
15623 BUFFER_APPEND_STRING_CONST(b, "\n");
15625 if (p->conf.use_syslog || /* syslog doesn't cache */
15626 @@ -828,7 +826,7 @@
15632 return HANDLER_GO_ON;
15635 @@ -836,15 +834,15 @@
15636 int mod_accesslog_plugin_init(plugin *p) {
15637 p->version = LIGHTTPD_VERSION_ID;
15638 p->name = buffer_init_string("accesslog");
15641 p->init = mod_accesslog_init;
15642 p->set_defaults= log_access_open;
15643 p->cleanup = mod_accesslog_free;
15646 p->handle_request_done = log_access_write;
15647 p->handle_sighup = log_access_cycle;
15655 --- ../lighttpd-1.4.11/src/mod_alias.c 2006-03-01 23:18:51.000000000 +0200
15656 +++ lighttpd-1.4.12/src/mod_alias.c 2006-07-16 00:26:03.000000000 +0300
15658 #include "buffer.h"
15660 #include "plugin.h"
15661 +#include "sys-strings.h"
15663 /* plugin config for all request/connections */
15665 @@ -16,44 +17,44 @@
15671 plugin_config **config_storage;
15673 - plugin_config conf;
15675 + plugin_config conf;
15678 /* init the plugin data */
15679 INIT_FUNC(mod_alias_init) {
15683 p = calloc(1, sizeof(*p));
15693 /* detroy the plugin data */
15694 FREE_FUNC(mod_alias_free) {
15695 plugin_data *p = p_d;
15698 if (!p) return HANDLER_GO_ON;
15701 if (p->config_storage) {
15705 for (i = 0; i < srv->config_context->used; i++) {
15706 plugin_config *s = p->config_storage[i];
15709 array_free(s->alias);
15714 free(p->config_storage);
15721 return HANDLER_GO_ON;
15724 @@ -62,25 +63,25 @@
15725 SETDEFAULTS_FUNC(mod_alias_set_defaults) {
15726 plugin_data *p = p_d;
15729 - config_values_t cv[] = {
15731 + config_values_t cv[] = {
15732 { "alias.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
15733 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
15737 if (!p) return HANDLER_ERROR;
15740 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
15743 for (i = 0; i < srv->config_context->used; i++) {
15747 s = calloc(1, sizeof(plugin_config));
15748 - s->alias = array_init();
15749 + s->alias = array_init();
15750 cv[0].destination = s->alias;
15753 p->config_storage[i] = s;
15756 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
15757 return HANDLER_ERROR;
15759 @@ -110,76 +111,73 @@
15765 return HANDLER_GO_ON;
15768 -#define PATCH(x) \
15769 - p->conf.x = s->x;
15770 static int mod_alias_patch_connection(server *srv, connection *con, plugin_data *p) {
15772 plugin_config *s = p->config_storage[0];
15777 + PATCH_OPTION(alias);
15779 /* skip the first, the global context */
15780 for (i = 1; i < srv->config_context->used; i++) {
15781 data_config *dc = (data_config *)srv->config_context->data[i];
15782 s = p->config_storage[i];
15785 /* condition didn't match */
15786 if (!config_check_cond(srv, con, dc)) continue;
15790 for (j = 0; j < dc->value->used; j++) {
15791 data_unset *du = dc->value->data[j];
15794 if (buffer_is_equal_string(du->key, CONST_STR_LEN("alias.url"))) {
15796 + PATCH_OPTION(alias);
15806 PHYSICALPATH_FUNC(mod_alias_physical_handler) {
15807 plugin_data *p = p_d;
15808 int uri_len, basedir_len;
15813 if (con->physical.path->used == 0) return HANDLER_GO_ON;
15816 mod_alias_patch_connection(srv, con, p);
15819 /* not to include the tailing slash */
15820 basedir_len = (con->physical.basedir->used - 1) - 1;
15821 uri_len = con->physical.path->used - 1 - basedir_len;
15822 uri_ptr = con->physical.path->ptr + basedir_len;
15825 for (k = 0; k < p->conf.alias->used; k++) {
15826 data_string *ds = (data_string *)p->conf.alias->data[k];
15827 int alias_len = ds->key->used - 1;
15830 if (alias_len > uri_len) continue;
15831 if (ds->key->used == 0) continue;
15834 if (0 == (con->conf.force_lowercase_filenames ?
15835 strncasecmp(uri_ptr, ds->key->ptr, alias_len) :
15836 strncmp(uri_ptr, ds->key->ptr, alias_len))) {
15840 buffer_copy_string_buffer(con->physical.basedir, ds->value);
15841 buffer_copy_string_buffer(srv->tmp_buf, ds->value);
15842 buffer_append_string(srv->tmp_buf, uri_ptr + alias_len);
15843 buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
15846 return HANDLER_GO_ON;
15852 return HANDLER_GO_ON;
15854 @@ -189,13 +187,13 @@
15855 int mod_alias_plugin_init(plugin *p) {
15856 p->version = LIGHTTPD_VERSION_ID;
15857 p->name = buffer_init_string("alias");
15860 p->init = mod_alias_init;
15861 p->handle_physical= mod_alias_physical_handler;
15862 p->set_defaults = mod_alias_set_defaults;
15863 p->cleanup = mod_alias_free;
15871 --- ../lighttpd-1.4.11/src/mod_auth.c 2006-02-15 20:01:31.000000000 +0200
15872 +++ lighttpd-1.4.12/src/mod_auth.c 2006-07-18 13:03:40.000000000 +0300
15873 @@ -5,168 +5,167 @@
15874 #include <string.h>
15877 -#include <unistd.h>
15879 #include "plugin.h"
15880 #include "http_auth.h"
15882 #include "response.h"
15884 +#include "sys-strings.h"
15885 +#include "sys-files.h"
15887 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s);
15891 * the basic and digest auth framework
15894 * - config handling
15895 * - protocol handling
15898 - * http_auth_digest.c
15902 + * http_auth_digest.c
15907 INIT_FUNC(mod_auth_init) {
15908 mod_auth_plugin_data *p;
15911 p = calloc(1, sizeof(*p));
15914 p->tmp_buf = buffer_init();
15917 p->auth_user = buffer_init();
15919 p->ldap_filter = buffer_init();
15926 FREE_FUNC(mod_auth_free) {
15927 mod_auth_plugin_data *p = p_d;
15932 if (!p) return HANDLER_GO_ON;
15935 buffer_free(p->tmp_buf);
15936 buffer_free(p->auth_user);
15938 buffer_free(p->ldap_filter);
15942 if (p->config_storage) {
15944 for (i = 0; i < srv->config_context->used; i++) {
15945 mod_auth_plugin_config *s = p->config_storage[i];
15951 array_free(s->auth_require);
15952 buffer_free(s->auth_plain_groupfile);
15953 buffer_free(s->auth_plain_userfile);
15954 buffer_free(s->auth_htdigest_userfile);
15955 buffer_free(s->auth_htpasswd_userfile);
15956 buffer_free(s->auth_backend_conf);
15959 buffer_free(s->auth_ldap_hostname);
15960 buffer_free(s->auth_ldap_basedn);
15961 buffer_free(s->auth_ldap_binddn);
15962 buffer_free(s->auth_ldap_bindpw);
15963 buffer_free(s->auth_ldap_filter);
15964 buffer_free(s->auth_ldap_cafile);
15968 buffer_free(s->ldap_filter_pre);
15969 buffer_free(s->ldap_filter_post);
15972 if (s->ldap) ldap_unbind_s(s->ldap);
15978 free(p->config_storage);
15985 return HANDLER_GO_ON;
15988 -#define PATCH(x) \
15989 - p->conf.x = s->x;
15990 static int mod_auth_patch_connection(server *srv, connection *con, mod_auth_plugin_data *p) {
15992 mod_auth_plugin_config *s = p->config_storage[0];
15994 - PATCH(auth_backend);
15995 - PATCH(auth_plain_groupfile);
15996 - PATCH(auth_plain_userfile);
15997 - PATCH(auth_htdigest_userfile);
15998 - PATCH(auth_htpasswd_userfile);
15999 - PATCH(auth_require);
16000 - PATCH(auth_debug);
16001 - PATCH(auth_ldap_hostname);
16002 - PATCH(auth_ldap_basedn);
16003 - PATCH(auth_ldap_binddn);
16004 - PATCH(auth_ldap_bindpw);
16005 - PATCH(auth_ldap_filter);
16006 - PATCH(auth_ldap_cafile);
16007 - PATCH(auth_ldap_starttls);
16008 + PATCH_OPTION(auth_backend);
16009 + PATCH_OPTION(auth_plain_groupfile);
16010 + PATCH_OPTION(auth_plain_userfile);
16011 + PATCH_OPTION(auth_htdigest_userfile);
16012 + PATCH_OPTION(auth_htpasswd_userfile);
16013 + PATCH_OPTION(auth_require);
16014 + PATCH_OPTION(auth_debug);
16015 + PATCH_OPTION(auth_ldap_hostname);
16016 + PATCH_OPTION(auth_ldap_basedn);
16017 + PATCH_OPTION(auth_ldap_binddn);
16018 + PATCH_OPTION(auth_ldap_bindpw);
16019 + PATCH_OPTION(auth_ldap_filter);
16020 + PATCH_OPTION(auth_ldap_cafile);
16021 + PATCH_OPTION(auth_ldap_starttls);
16024 - PATCH(ldap_filter_pre);
16025 - PATCH(ldap_filter_post);
16026 + PATCH_OPTION(ldap);
16027 + PATCH_OPTION(ldap_filter_pre);
16028 + PATCH_OPTION(ldap_filter_post);
16032 /* skip the first, the global context */
16033 for (i = 1; i < srv->config_context->used; i++) {
16034 data_config *dc = (data_config *)srv->config_context->data[i];
16035 s = p->config_storage[i];
16038 /* condition didn't match */
16039 if (!config_check_cond(srv, con, dc)) continue;
16043 for (j = 0; j < dc->value->used; j++) {
16044 data_unset *du = dc->value->data[j];
16047 if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend"))) {
16048 - PATCH(auth_backend);
16049 + PATCH_OPTION(auth_backend);
16050 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.groupfile"))) {
16051 - PATCH(auth_plain_groupfile);
16052 + PATCH_OPTION(auth_plain_groupfile);
16053 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.plain.userfile"))) {
16054 - PATCH(auth_plain_userfile);
16055 + PATCH_OPTION(auth_plain_userfile);
16056 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htdigest.userfile"))) {
16057 - PATCH(auth_htdigest_userfile);
16058 + PATCH_OPTION(auth_htdigest_userfile);
16059 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.htpasswd.userfile"))) {
16060 - PATCH(auth_htpasswd_userfile);
16061 + PATCH_OPTION(auth_htpasswd_userfile);
16062 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.require"))) {
16063 - PATCH(auth_require);
16064 + PATCH_OPTION(auth_require);
16065 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.debug"))) {
16066 - PATCH(auth_debug);
16067 + PATCH_OPTION(auth_debug);
16068 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.hostname"))) {
16069 - PATCH(auth_ldap_hostname);
16070 + PATCH_OPTION(auth_ldap_hostname);
16073 - PATCH(ldap_filter_pre);
16074 - PATCH(ldap_filter_post);
16075 + PATCH_OPTION(ldap);
16076 + PATCH_OPTION(ldap_filter_pre);
16077 + PATCH_OPTION(ldap_filter_post);
16079 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.base-dn"))) {
16080 - PATCH(auth_ldap_basedn);
16081 + PATCH_OPTION(auth_ldap_basedn);
16082 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.filter"))) {
16083 - PATCH(auth_ldap_filter);
16084 + PATCH_OPTION(auth_ldap_filter);
16085 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.ca-file"))) {
16086 - PATCH(auth_ldap_cafile);
16087 + PATCH_OPTION(auth_ldap_cafile);
16088 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("auth.backend.ldap.starttls"))) {
16089 - PATCH(auth_ldap_starttls);
16090 + PATCH_OPTION(auth_ldap_starttls);
16100 static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
16102 @@ -175,22 +174,22 @@
16104 mod_auth_plugin_data *p = p_d;
16108 /* select the right config */
16109 mod_auth_patch_connection(srv, con, p);
16112 if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
16122 /* do we have to ask for auth ? */
16126 auth_satisfied = 0;
16129 /* search auth-directives for path */
16130 for (k = 0; k < p->conf.auth_require->used; k++) {
16131 buffer *req = p->conf.auth_require->data[k]->key;
16132 @@ -212,76 +211,76 @@
16138 /* nothing to do for us */
16139 if (auth_required == 0) return HANDLER_GO_ON;
16142 req = ((data_array *)(p->conf.auth_require->data[k]))->value;
16145 /* try to get Authorization-header */
16148 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
16149 http_authorization = ds->value->ptr;
16153 if (ds && ds->value && ds->value->used) {
16155 data_string *method;
16158 method = (data_string *)array_get_element(req, "method");
16161 /* parse auth-header */
16162 if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
16163 int auth_type_len = auth_realm - http_authorization;
16166 if ((auth_type_len == 5) &&
16167 (0 == strncmp(http_authorization, "Basic", auth_type_len))) {
16169 - if (0 == strcmp(method->value->ptr, "basic")) {
16171 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16172 auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
16174 } else if ((auth_type_len == 6) &&
16175 (0 == strncmp(http_authorization, "Digest", auth_type_len))) {
16176 - if (0 == strcmp(method->value->ptr, "digest")) {
16177 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16178 if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
16179 con->http_status = 400;
16182 /* a field was missing */
16185 return HANDLER_FINISHED;
16189 - log_error_write(srv, __FILE__, __LINE__, "ss",
16190 + log_error_write(srv, __FILE__, __LINE__, "ss",
16191 "unknown authentification type:",
16192 http_authorization);
16198 if (!auth_satisfied) {
16199 data_string *method, *realm;
16200 method = (data_string *)array_get_element(req, "method");
16201 realm = (data_string *)array_get_element(req, "realm");
16204 con->http_status = 401;
16206 - if (0 == strcmp(method->value->ptr, "basic")) {
16208 + if (buffer_is_equal_string(method->value, CONST_STR_LEN("basic"))) {
16209 buffer_copy_string(p->tmp_buf, "Basic realm=\"");
16210 buffer_append_string_buffer(p->tmp_buf, realm->value);
16211 buffer_append_string(p->tmp_buf, "\"");
16214 response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16215 - } else if (0 == strcmp(method->value->ptr, "digest")) {
16216 + } else if (buffer_is_equal_string(method->value, CONST_STR_LEN("digest"))) {
16218 http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);
16221 buffer_copy_string(p->tmp_buf, "Digest realm=\"");
16222 buffer_append_string_buffer(p->tmp_buf, realm->value);
16223 buffer_append_string(p->tmp_buf, "\", nonce=\"");
16224 buffer_append_string(p->tmp_buf, hh);
16225 buffer_append_string(p->tmp_buf, "\", qop=\"auth\"");
16228 response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
16231 @@ -289,18 +288,18 @@
16232 return HANDLER_FINISHED;
16234 /* the REMOTE_USER header */
16237 buffer_copy_string_buffer(con->authed_user, p->auth_user);
16241 return HANDLER_GO_ON;
16244 SETDEFAULTS_FUNC(mod_auth_set_defaults) {
16245 mod_auth_plugin_data *p = p_d;
16248 - config_values_t cv[] = {
16250 + config_values_t cv[] = {
16251 { "auth.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16252 { "auth.backend.plain.groupfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16253 { "auth.backend.plain.userfile", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
16254 @@ -317,7 +316,7 @@
16255 { "auth.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
16256 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
16260 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16262 for (i = 0; i < srv->config_context->used; i++) {
16263 @@ -325,14 +324,14 @@
16269 s = calloc(1, sizeof(mod_auth_plugin_config));
16270 s->auth_plain_groupfile = buffer_init();
16271 s->auth_plain_userfile = buffer_init();
16272 s->auth_htdigest_userfile = buffer_init();
16273 s->auth_htpasswd_userfile = buffer_init();
16274 s->auth_backend_conf = buffer_init();
16277 s->auth_ldap_hostname = buffer_init();
16278 s->auth_ldap_basedn = buffer_init();
16279 s->auth_ldap_binddn = buffer_init();
16280 @@ -341,15 +340,15 @@
16281 s->auth_ldap_cafile = buffer_init();
16282 s->auth_ldap_starttls = 0;
16286 s->auth_require = array_init();
16290 s->ldap_filter_pre = buffer_init();
16291 s->ldap_filter_post = buffer_init();
16296 cv[0].destination = s->auth_backend_conf;
16297 cv[1].destination = s->auth_plain_groupfile;
16298 cv[2].destination = s->auth_plain_userfile;
16299 @@ -364,146 +363,148 @@
16300 cv[11].destination = s->auth_htdigest_userfile;
16301 cv[12].destination = s->auth_htpasswd_userfile;
16302 cv[13].destination = &(s->auth_debug);
16305 p->config_storage[i] = s;
16306 ca = ((data_config *)srv->config_context->data[i])->value;
16309 if (0 != config_insert_values_global(srv, ca, cv)) {
16310 return HANDLER_ERROR;
16313 - if (s->auth_backend_conf->used) {
16314 - if (0 == strcmp(s->auth_backend_conf->ptr, "htpasswd")) {
16316 + if (!buffer_is_empty(s->auth_backend_conf)) {
16317 + if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htpasswd"))) {
16318 s->auth_backend = AUTH_BACKEND_HTPASSWD;
16319 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "htdigest")) {
16320 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("htdigest"))) {
16321 s->auth_backend = AUTH_BACKEND_HTDIGEST;
16322 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "plain")) {
16323 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("plain"))) {
16324 s->auth_backend = AUTH_BACKEND_PLAIN;
16325 - } else if (0 == strcmp(s->auth_backend_conf->ptr, "ldap")) {
16326 + } else if (buffer_is_equal_string(s->auth_backend_conf, CONST_STR_LEN("ldap"))) {
16327 s->auth_backend = AUTH_BACKEND_LDAP;
16329 log_error_write(srv, __FILE__, __LINE__, "sb", "auth.backend not supported:", s->auth_backend_conf);
16332 return HANDLER_ERROR;
16336 /* no auth.require for this section */
16337 if (NULL == (da = (data_array *)array_get_element(ca, "auth.require"))) continue;
16340 if (da->type != TYPE_ARRAY) continue;
16343 for (n = 0; n < da->value->used; n++) {
16345 data_array *da_file = (data_array *)da->value->data[n];
16346 - const char *method, *realm, *require;
16348 + buffer *method, *realm, *require;
16350 if (da->value->data[n]->type != TYPE_ARRAY) {
16351 - log_error_write(srv, __FILE__, __LINE__, "ss",
16352 - "auth.require should contain an array as in:",
16353 + log_error_write(srv, __FILE__, __LINE__, "ss",
16354 + "auth.require should contain an array as in:",
16355 "auth.require = ( \"...\" => ( ..., ...) )");
16357 return HANDLER_ERROR;
16361 method = realm = require = NULL;
16364 for (m = 0; m < da_file->value->used; m++) {
16365 - if (da_file->value->data[m]->type == TYPE_STRING) {
16366 - if (0 == strcmp(da_file->value->data[m]->key->ptr, "method")) {
16367 - method = ((data_string *)(da_file->value->data[m]))->value->ptr;
16368 - } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "realm")) {
16369 - realm = ((data_string *)(da_file->value->data[m]))->value->ptr;
16370 - } else if (0 == strcmp(da_file->value->data[m]->key->ptr, "require")) {
16371 - require = ((data_string *)(da_file->value->data[m]))->value->ptr;
16373 - log_error_write(srv, __FILE__, __LINE__, "ssbs",
16374 - "the field is unknown in:",
16375 + data_string *ds_auth_req = (data_string *)da_file->value->data[m];
16377 + if (ds_auth_req->type != TYPE_STRING) {
16378 + log_error_write(srv, __FILE__, __LINE__, "ssbs",
16379 + "a string was expected for:",
16380 + "auth.require = ( \"...\" => ( ..., -> \"",
16381 + ds_auth_req->key,
16382 + "\" <- => \"...\" ) )");
16384 + return HANDLER_ERROR;
16387 + if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("method"))) {
16388 + method = ds_auth_req->value;
16389 + } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("realm"))) {
16390 + realm = ds_auth_req->value;
16391 + } else if (buffer_is_equal_string(ds_auth_req->key, CONST_STR_LEN("require"))) {
16392 + require = ds_auth_req->value;
16394 + log_error_write(srv, __FILE__, __LINE__, "ssbs",
16395 + "the field is unknown in:",
16396 "auth.require = ( \"...\" => ( ..., -> \"",
16397 da_file->value->data[m]->key,
16398 "\" <- => \"...\" ) )");
16400 - return HANDLER_ERROR;
16403 - log_error_write(srv, __FILE__, __LINE__, "ssbs",
16404 - "a string was expected for:",
16405 - "auth.require = ( \"...\" => ( ..., -> \"",
16406 - da_file->value->data[m]->key,
16407 - "\" <- => \"...\" ) )");
16409 return HANDLER_ERROR;
16415 if (method == NULL) {
16416 - log_error_write(srv, __FILE__, __LINE__, "ss",
16417 - "the require field is missing in:",
16418 + log_error_write(srv, __FILE__, __LINE__, "ss",
16419 + "the require field is missing in:",
16420 "auth.require = ( \"...\" => ( ..., \"method\" => \"...\" ) )");
16421 return HANDLER_ERROR;
16423 - if (0 != strcmp(method, "basic") &&
16424 - 0 != strcmp(method, "digest")) {
16425 - log_error_write(srv, __FILE__, __LINE__, "ss",
16426 - "method has to be either \"basic\" or \"digest\" in",
16427 - "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16428 - return HANDLER_ERROR;
16431 + if (!buffer_is_equal_string(method, CONST_STR_LEN("basic")) &&
16432 + !buffer_is_equal_string(method, CONST_STR_LEN("digest"))) {
16433 + log_error_write(srv, __FILE__, __LINE__, "ss",
16434 + "method has to be either \"basic\" or \"digest\" in",
16435 + "auth.require = ( \"...\" => ( ..., \"method\" => \"...\") )");
16436 + return HANDLER_ERROR;
16440 if (realm == NULL) {
16441 - log_error_write(srv, __FILE__, __LINE__, "ss",
16442 - "the require field is missing in:",
16443 + log_error_write(srv, __FILE__, __LINE__, "ss",
16444 + "the require field is missing in:",
16445 "auth.require = ( \"...\" => ( ..., \"realm\" => \"...\" ) )");
16446 return HANDLER_ERROR;
16450 if (require == NULL) {
16451 - log_error_write(srv, __FILE__, __LINE__, "ss",
16452 - "the require field is missing in:",
16453 + log_error_write(srv, __FILE__, __LINE__, "ss",
16454 + "the require field is missing in:",
16455 "auth.require = ( \"...\" => ( ..., \"require\" => \"...\" ) )");
16456 return HANDLER_ERROR;
16460 if (method && realm && require) {
16465 a = data_array_init();
16466 buffer_copy_string_buffer(a->key, da_file->key);
16469 ds = data_string_init();
16472 buffer_copy_string(ds->key, "method");
16473 - buffer_copy_string(ds->value, method);
16475 + buffer_copy_string_buffer(ds->value, method);
16477 array_insert_unique(a->value, (data_unset *)ds);
16480 ds = data_string_init();
16483 buffer_copy_string(ds->key, "realm");
16484 - buffer_copy_string(ds->value, realm);
16486 + buffer_copy_string_buffer(ds->value, realm);
16488 array_insert_unique(a->value, (data_unset *)ds);
16491 ds = data_string_init();
16494 buffer_copy_string(ds->key, "require");
16495 - buffer_copy_string(ds->value, require);
16497 + buffer_copy_string_buffer(ds->value, require);
16499 array_insert_unique(a->value, (data_unset *)ds);
16502 array_insert_unique(s->auth_require, (data_unset *)a);
16507 switch(s->auth_backend) {
16508 case AUTH_BACKEND_PLAIN:
16509 if (s->auth_plain_userfile->used) {
16512 if (-1 == (fd = open(s->auth_plain_userfile->ptr, O_RDONLY))) {
16513 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16514 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16515 "opening auth.backend.plain.userfile:", s->auth_plain_userfile,
16516 "failed:", strerror(errno));
16517 return HANDLER_ERROR;
16518 @@ -516,7 +517,7 @@
16521 if (-1 == (fd = open(s->auth_htpasswd_userfile->ptr, O_RDONLY))) {
16522 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16523 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16524 "opening auth.backend.htpasswd.userfile:", s->auth_htpasswd_userfile,
16525 "failed:", strerror(errno));
16526 return HANDLER_ERROR;
16527 @@ -529,7 +530,7 @@
16530 if (-1 == (fd = open(s->auth_htdigest_userfile->ptr, O_RDONLY))) {
16531 - log_error_write(srv, __FILE__, __LINE__, "sbss",
16532 + log_error_write(srv, __FILE__, __LINE__, "sbss",
16533 "opening auth.backend.htdigest.userfile:", s->auth_htdigest_userfile,
16534 "failed:", strerror(errno));
16535 return HANDLER_ERROR;
16536 @@ -554,75 +555,75 @@
16537 handler_t auth_ldap_init(server *srv, mod_auth_plugin_config *s) {
16542 if (s->auth_ldap_basedn->used == 0) {
16543 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.base-dn has to be set");
16546 return HANDLER_ERROR;
16551 if (s->auth_ldap_filter->used) {
16558 if (NULL == (dollar = strchr(s->auth_ldap_filter->ptr, '$'))) {
16559 log_error_write(srv, __FILE__, __LINE__, "s", "ldap: auth.backend.ldap.filter is missing a replace-operator '$'");
16562 return HANDLER_ERROR;
16566 buffer_copy_string_len(s->ldap_filter_pre, s->auth_ldap_filter->ptr, dollar - s->auth_ldap_filter->ptr);
16567 buffer_copy_string(s->ldap_filter_post, dollar+1);
16571 if (s->auth_ldap_hostname->used) {
16572 if (NULL == (s->ldap = ldap_init(s->auth_ldap_hostname->ptr, LDAP_PORT))) {
16573 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap ...", strerror(errno));
16576 return HANDLER_ERROR;
16580 ret = LDAP_VERSION3;
16581 if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(s->ldap, LDAP_OPT_PROTOCOL_VERSION, &ret))) {
16582 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16585 return HANDLER_ERROR;
16588 if (s->auth_ldap_starttls) {
16589 - /* if no CA file is given, it is ok, as we will use encryption
16590 + /* if no CA file is given, it is ok, as we will use encryption
16591 * if the server requires a CAfile it will tell us */
16592 if (!buffer_is_empty(s->auth_ldap_cafile)) {
16593 - if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16594 + if (LDAP_OPT_SUCCESS != (ret = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE,
16595 s->auth_ldap_cafile->ptr))) {
16596 - log_error_write(srv, __FILE__, __LINE__, "ss",
16597 + log_error_write(srv, __FILE__, __LINE__, "ss",
16598 "Loading CA certificate failed:", ldap_err2string(ret));
16601 return HANDLER_ERROR;
16606 if (LDAP_OPT_SUCCESS != (ret = ldap_start_tls_s(s->ldap, NULL, NULL))) {
16607 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap startTLS failed:", ldap_err2string(ret));
16610 return HANDLER_ERROR;
16618 if (s->auth_ldap_binddn->used) {
16619 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, s->auth_ldap_binddn->ptr, s->auth_ldap_bindpw->ptr))) {
16620 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16623 return HANDLER_ERROR;
16626 if (LDAP_SUCCESS != (ret = ldap_simple_bind_s(s->ldap, NULL, NULL))) {
16627 log_error_write(srv, __FILE__, __LINE__, "ss", "ldap:", ldap_err2string(ret));
16630 return HANDLER_ERROR;
16633 @@ -641,8 +642,8 @@
16634 p->set_defaults = mod_auth_set_defaults;
16635 p->handle_uri_clean = mod_auth_uri_handler;
16636 p->cleanup = mod_auth_free;
16644 --- ../lighttpd-1.4.11/src/mod_cgi.c 2006-02-22 15:15:10.000000000 +0200
16645 +++ lighttpd-1.4.12/src/mod_cgi.c 2006-07-18 13:03:40.000000000 +0300
16647 #include <sys/types.h>
16649 -#include <winsock2.h>
16651 -#include <sys/socket.h>
16652 -#include <sys/wait.h>
16653 -#include <sys/mman.h>
16655 -#include <netinet/in.h>
16657 -#include <arpa/inet.h>
16660 -#include <unistd.h>
16662 #include <stdlib.h>
16663 #include <string.h>
16664 -#include <fdevent.h>
16665 #include <signal.h>
16667 #include <assert.h>
16669 #include "connections.h"
16670 #include "joblist.h"
16671 #include "http_chunk.h"
16672 +#include "fdevent.h"
16674 #include "plugin.h"
16675 +#include "http_resp.h"
16677 +#include "sys-files.h"
16678 +#include "sys-mmap.h"
16679 +#include "sys-socket.h"
16680 +#include "sys-strings.h"
16681 +#include "sys-process.h"
16683 #ifdef HAVE_SYS_FILIO_H
16684 # include <sys/filio.h>
16685 @@ -40,11 +35,12 @@
16699 @@ -58,57 +54,68 @@
16702 buffer_pid_t cgi_pid;
16706 - buffer *parse_response;
16711 plugin_config **config_storage;
16713 - plugin_config conf;
16715 + plugin_config conf;
16720 + CGI_STATE_CONNECTING,
16721 + CGI_STATE_READ_RESPONSE_HEADER,
16722 + CGI_STATE_READ_RESPONSE_CONTENT
16728 - int fde_ndx; /* index into the fd-event buffer */
16730 - connection *remote_conn; /* dumb pointer */
16731 - plugin_data *plugin_data; /* dumb pointer */
16733 - buffer *response;
16734 - buffer *response_header;
16737 -static handler_ctx * cgi_handler_ctx_init() {
16738 - handler_ctx *hctx = calloc(1, sizeof(*hctx));
16743 - hctx->response = buffer_init();
16744 - hctx->response_header = buffer_init();
16751 -static void cgi_handler_ctx_free(handler_ctx *hctx) {
16752 - buffer_free(hctx->response);
16753 - buffer_free(hctx->response_header);
16756 + cgi_state_t state;
16758 + connection *remote_con; /* dumb pointer */
16761 +static cgi_session * cgi_session_init() {
16762 + cgi_session *sess = calloc(1, sizeof(*sess));
16765 + sess->sock = iosocket_init();
16766 + sess->wb = chunkqueue_init();
16767 + sess->rb = chunkqueue_init();
16772 -enum {FDEVENT_HANDLED_UNSET, FDEVENT_HANDLED_FINISHED, FDEVENT_HANDLED_NOT_FINISHED, FDEVENT_HANDLED_ERROR};
16773 +static void cgi_session_free(cgi_session *sess) {
16774 + if (!sess) return;
16776 + iosocket_free(sess->sock);
16778 + chunkqueue_free(sess->wb);
16779 + chunkqueue_free(sess->rb);
16784 INIT_FUNC(mod_cgi_init) {
16788 p = calloc(1, sizeof(*p));
16793 p->tmp_buf = buffer_init();
16794 - p->parse_response = buffer_init();
16796 + p->resp = http_response_init();
16801 @@ -116,62 +123,62 @@
16802 FREE_FUNC(mod_cgi_free) {
16803 plugin_data *p = p_d;
16804 buffer_pid_t *r = &(p->cgi_pid);
16810 if (p->config_storage) {
16812 for (i = 0; i < srv->config_context->used; i++) {
16813 plugin_config *s = p->config_storage[i];
16816 array_free(s->cgi);
16821 free(p->config_storage);
16826 if (r->ptr) free(r->ptr);
16829 buffer_free(p->tmp_buf);
16830 - buffer_free(p->parse_response);
16832 + http_response_free(p->resp);
16837 return HANDLER_GO_ON;
16840 SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
16841 plugin_data *p = p_d;
16844 - config_values_t cv[] = {
16846 + config_values_t cv[] = {
16847 { "cgi.assign", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
16848 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET}
16851 if (!p) return HANDLER_ERROR;
16854 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
16857 for (i = 0; i < srv->config_context->used; i++) {
16861 s = calloc(1, sizeof(plugin_config));
16865 s->cgi = array_init();
16868 cv[0].destination = s->cgi;
16871 p->config_storage[i] = s;
16874 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
16875 return HANDLER_ERROR;
16880 return HANDLER_GO_ON;
16883 @@ -180,13 +187,13 @@
16886 buffer_pid_t *r = &(p->cgi_pid);
16891 for (i = 0; i < r->used; i++) {
16892 if (r->ptr[i] > m) m = r->ptr[i];
16896 if (r->size == 0) {
16898 r->ptr = malloc(sizeof(*r->ptr) * r->size);
16899 @@ -194,321 +201,178 @@
16901 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
16905 r->ptr[r->used++] = pid;
16911 static int cgi_pid_del(server *srv, plugin_data *p, pid_t pid) {
16913 buffer_pid_t *r = &(p->cgi_pid);
16918 for (i = 0; i < r->used; i++) {
16919 if (r->ptr[i] == pid) break;
16923 if (i != r->used) {
16927 if (i != r->used - 1) {
16928 r->ptr[i] = r->ptr[r->used - 1];
16937 -static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
16944 - buffer_copy_string_buffer(p->parse_response, in);
16946 - for (s = p->parse_response->ptr;
16947 - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
16948 - s = ns + (eol == EOL_RN ? 2 : 1), line++) {
16949 - const char *key, *value;
16956 - 0 == strncmp(s, "HTTP/1.", 7)) {
16957 - /* non-parsed header ... we parse them anyway */
16959 - if ((s[7] == '1' ||
16963 - /* after the space should be a status code for us */
16965 - status = strtol(s+9, NULL, 10);
16967 - if (con->http_status >= 100 &&
16968 - con->http_status < 1000) {
16969 - /* we expected 3 digits and didn't got them */
16970 - con->parsed_response |= HTTP_STATUS;
16971 - con->http_status = status;
16977 - if (NULL == (value = strchr(s, ':'))) {
16978 - /* we expect: "<key>: <value>\r\n" */
16982 - key_len = value - key;
16986 - while (*value == ' ' || *value == '\t') value++;
16988 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
16989 - ds = data_response_init();
16991 - buffer_copy_string_len(ds->key, key, key_len);
16992 - buffer_copy_string(ds->value, value);
16994 - array_insert_unique(con->response.headers, (data_unset *)ds);
16996 - switch(key_len) {
16998 - if (0 == strncasecmp(key, "Date", key_len)) {
16999 - con->parsed_response |= HTTP_DATE;
17003 - if (0 == strncasecmp(key, "Status", key_len)) {
17004 - con->http_status = strtol(value, NULL, 10);
17005 - con->parsed_response |= HTTP_STATUS;
17009 - if (0 == strncasecmp(key, "Location", key_len)) {
17010 - con->parsed_response |= HTTP_LOCATION;
17014 - if (0 == strncasecmp(key, "Connection", key_len)) {
17015 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
17016 - con->parsed_response |= HTTP_CONNECTION;
17020 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
17021 - con->response.content_length = strtol(value, NULL, 10);
17022 - con->parsed_response |= HTTP_CONTENT_LENGTH;
17031 - /* CGI/1.1 rev 03 - 7.2.1.2 */
17032 - if ((con->parsed_response & HTTP_LOCATION) &&
17033 - !(con->parsed_response & HTTP_STATUS)) {
17034 - con->http_status = 302;
17035 +static int cgi_demux_response(server *srv, connection *con, plugin_data *p) {
17036 + cgi_session *sess = con->plugin_ctx[p->id];
17039 + switch(srv->network_backend_read(srv, con, sess->sock, sess->rb)) {
17040 + case NETWORK_STATUS_SUCCESS:
17041 + /* we got content */
17043 + case NETWORK_STATUS_WAIT_FOR_EVENT:
17045 + case NETWORK_STATUS_CONNECTION_CLOSE:
17046 + /* this is a bit too early */
17047 + ERROR("%s", "cgi-connection got closed before we read the response-header (CGI died ?)");
17051 + ERROR("%s", "oops, read-pipe-read failed and I don't know why");
17058 + /* looks like we got some content
17060 + * split off the header from the incoming stream
17063 -static int cgi_demux_response(server *srv, handler_ctx *hctx) {
17064 - plugin_data *p = hctx->plugin_data;
17065 - connection *con = hctx->remote_conn;
17070 - buffer_prepare_copy(hctx->response, 1024);
17071 - if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
17072 - if (errno == EAGAIN || errno == EINTR) {
17073 - /* would block, wait for signal */
17074 - return FDEVENT_HANDLED_NOT_FINISHED;
17077 - log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
17078 - return FDEVENT_HANDLED_ERROR;
17082 - /* read finished */
17084 - con->file_finished = 1;
17086 - /* send final chunk */
17087 - http_chunk_append_mem(srv, con, NULL, 0);
17088 - joblist_append(srv, con);
17090 - return FDEVENT_HANDLED_FINISHED;
17093 - hctx->response->ptr[n] = '\0';
17094 - hctx->response->used = n+1;
17096 - /* split header from body */
17098 - if (con->file_started == 0) {
17100 - int in_header = 0;
17101 - int header_end = 0;
17102 - int cp, eol = EOL_UNSET;
17105 - buffer_append_string_buffer(hctx->response_header, hctx->response);
17107 - /* nph (non-parsed headers) */
17108 - if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
17110 - /* search for the \r\n\r\n or \n\n in the string */
17111 - for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
17112 - if (*c == ':') in_header = 1;
17113 - else if (*c == '\n') {
17114 - if (in_header == 0) {
17115 - /* got a response without a response header */
17122 - if (eol == EOL_UNSET) eol = EOL_N;
17124 - if (*(c+1) == '\n') {
17129 - } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
17130 - if (in_header == 0) {
17131 - /* got a response without a response header */
17138 - if (eol == EOL_UNSET) eol = EOL_RN;
17141 - *(c+2) == '\r' &&
17142 - *(c+3) == '\n') {
17147 - /* skip the \n */
17151 + if (con->file_started == 0) {
17153 + int have_content_length = 0;
17155 + http_response_reset(p->resp);
17157 + /* the response header is not fully received yet,
17159 + * extract the http-response header from the rb-cq
17161 + switch (http_response_parse_cq(sess->rb, p->resp)) {
17162 + case PARSE_ERROR:
17163 + /* parsing failed */
17165 + TRACE("%s", "response parser failed");
17167 + con->http_status = 502; /* Bad Gateway */
17169 + case PARSE_NEED_MORE:
17171 + case PARSE_SUCCESS:
17172 + con->http_status = p->resp->status;
17174 + chunkqueue_remove_finished_chunks(sess->rb);
17176 + /* copy the http-headers */
17177 + for (i = 0; i < p->resp->headers->used; i++) {
17178 + const char *ign[] = { "Status", "Connection", NULL };
17182 + data_string *header = (data_string *)p->resp->headers->data[i];
17184 + /* some headers are ignored by default */
17185 + for (j = 0; ign[j]; j++) {
17186 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
17190 - if (header_end) {
17192 - /* no header, but a body */
17194 - if (con->request.http_version == HTTP_VERSION_1_1) {
17195 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17198 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17199 - joblist_append(srv, con);
17201 - size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
17202 - size_t blen = hctx->response_header->used - hlen - 1;
17204 - /* a small hack: terminate after at the second \r */
17205 - hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
17206 - hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
17208 - /* parse the response header */
17209 - cgi_response_parse(srv, con, p, hctx->response_header, eol);
17211 - /* enable chunked-transfer-encoding */
17212 - if (con->request.http_version == HTTP_VERSION_1_1 &&
17213 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
17214 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17217 - if ((hctx->response->used != hlen) && blen > 0) {
17218 - http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
17219 - joblist_append(srv, con);
17221 + if (ign[j]) continue;
17223 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
17224 + /* CGI/1.1 rev 03 - 7.2.1.2 */
17225 + if (con->http_status == 0) con->http_status = 302;
17226 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
17227 + have_content_length = 1;
17230 - con->file_started = 1;
17231 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
17232 + ds = data_response_init();
17234 + buffer_copy_string_buffer(ds->key, header->key);
17235 + buffer_copy_string_buffer(ds->value, header->value);
17237 + array_insert_unique(con->response.headers, (data_unset *)ds);
17240 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
17241 - joblist_append(srv, con);
17243 + con->file_started = 1;
17244 + sess->state = CGI_STATE_READ_RESPONSE_CONTENT;
17246 + if (con->request.http_version == HTTP_VERSION_1_1 &&
17247 + !have_content_length) {
17248 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
17255 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
17259 - return FDEVENT_HANDLED_NOT_FINISHED;
17261 + /* FIXME: pass the response-header to the other plugins to
17262 + * setup the filter-queue
17264 + * - use next-queue instead of con->write_queue
17267 + /* copy the content to the next cq */
17268 + for (c = sess->rb->first; c; c = c->next) {
17269 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17271 + c->offset = c->mem->used - 1;
17274 + chunkqueue_remove_finished_chunks(sess->rb);
17275 + joblist_append(srv, con);
17280 -static handler_t cgi_connection_close(server *srv, handler_ctx *hctx) {
17281 +static handler_t cgi_connection_close(server *srv, connection *con, plugin_data *p) {
17282 + cgi_session *sess = con->plugin_ctx[p->id];
17288 - if (NULL == hctx) return HANDLER_GO_ON;
17290 - p = hctx->plugin_data;
17291 - con = hctx->remote_conn;
17294 + if (NULL == sess) return HANDLER_GO_ON;
17295 if (con->mode != p->id) return HANDLER_GO_ON;
17301 /* the connection to the browser went away, but we still have a connection
17302 - * to the CGI script
17303 + * to the CGI script
17305 * close cgi-connection
17308 - if (hctx->fd != -1) {
17310 + if (sess->sock->fd != -1) {
17311 /* close connection to the cgi-script */
17312 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
17313 - fdevent_unregister(srv->ev, hctx->fd);
17315 - if (close(hctx->fd)) {
17316 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
17320 - hctx->fde_ndx = -1;
17321 + fdevent_event_del(srv->ev, sess->sock);
17322 + fdevent_unregister(srv->ev, sess->sock);
17330 con->plugin_ctx[p->id] = NULL;
17333 /* is this a good idea ? */
17334 - cgi_handler_ctx_free(hctx);
17336 + cgi_session_free(sess);
17338 /* if waitpid hasn't been called by response.c yet, do it here */
17340 /* check if the CGI-script is already gone */
17342 switch(waitpid(pid, &status, WNOHANG)) {
17344 /* not finished yet */
17345 @@ -519,35 +383,35 @@
17348 if (errno == EINTR) break;
17351 - * errno == ECHILD happens if _subrequest catches the process-status before
17354 + * errno == ECHILD happens if _subrequest catches the process-status before
17355 * we have read the response of the cgi process
17359 * -> WAIT_FOR_EVENT
17361 * -> we get here with waitpid == ECHILD
17365 if (errno == ECHILD) return HANDLER_GO_ON;
17368 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
17369 return HANDLER_ERROR;
17371 /* Send an error if we haven't sent any data yet */
17372 if (0 == con->file_started) {
17373 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17374 - con->http_status = 500;
17375 + if (con->http_status == 0) con->http_status = 500;
17376 con->mode = DIRECT;
17380 if (WIFEXITED(status)) {
17382 log_error_write(srv, __FILE__, __LINE__, "sd", "(debug) cgi exited fine, pid:", pid);
17387 return HANDLER_GO_ON;
17389 log_error_write(srv, __FILE__, __LINE__, "sd", "cgi died, pid:", pid);
17390 @@ -555,122 +419,126 @@
17391 return HANDLER_GO_ON;
17398 kill(pid, SIGTERM);
17401 /* cgi-script is still alive, queue the PID for removal */
17402 cgi_pid_add(srv, p, pid);
17406 return HANDLER_GO_ON;
17409 static handler_t cgi_connection_close_callback(server *srv, connection *con, void *p_d) {
17410 plugin_data *p = p_d;
17412 - return cgi_connection_close(srv, con->plugin_ctx[p->id]);
17414 + return cgi_connection_close(srv, con, p);
17418 static handler_t cgi_handle_fdevent(void *s, void *ctx, int revents) {
17419 server *srv = (server *)s;
17420 - handler_ctx *hctx = ctx;
17421 - connection *con = hctx->remote_conn;
17423 - joblist_append(srv, con);
17425 - if (hctx->fd == -1) {
17426 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "invalid cgi-fd");
17428 - return HANDLER_ERROR;
17431 + cgi_session *sess = ctx;
17432 + connection *con = sess->remote_con;
17435 if (revents & FDEVENT_IN) {
17436 - switch (cgi_demux_response(srv, hctx)) {
17437 - case FDEVENT_HANDLED_NOT_FINISHED:
17438 + switch (sess->state) {
17439 + case CGI_STATE_READ_RESPONSE_HEADER:
17440 + /* parse the header and set file-started, the demuxer will care about it */
17441 + joblist_append(srv, con);
17444 - case FDEVENT_HANDLED_FINISHED:
17445 - /* we are done */
17447 + case CGI_STATE_READ_RESPONSE_CONTENT:
17448 + /* just forward the content to the out-going queue */
17450 + chunkqueue_remove_finished_chunks(sess->rb);
17452 + switch (srv->network_backend_read(srv, sess->remote_con, sess->sock, sess->rb)) {
17453 + case NETWORK_STATUS_CONNECTION_CLOSE:
17454 + fdevent_event_del(srv->ev, sess->sock);
17456 + /* the connection is gone
17457 + * make the connect */
17458 + sess->remote_con->file_finished = 1;
17460 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), "finished");
17461 + fdevent_event_del(srv->ev, sess->sock);
17463 - cgi_connection_close(srv, hctx);
17465 - /* if we get a IN|HUP and have read everything don't exec the close twice */
17466 - return HANDLER_FINISHED;
17467 - case FDEVENT_HANDLED_ERROR:
17468 - connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
17469 - con->http_status = 500;
17470 - con->mode = DIRECT;
17472 - log_error_write(srv, __FILE__, __LINE__, "s", "demuxer failed: ");
17473 + case NETWORK_STATUS_SUCCESS:
17474 + /* read even more, do we have all the content */
17476 + /* how much do we want to read ? */
17478 + /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
17480 + chunkqueue_remove_finished_chunks(sess->rb);
17482 + /* copy the content to the next cq */
17483 + for (c = sess->rb->first; c; c = c->next) {
17484 + if (c->mem->used == 0) continue;
17486 + http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
17488 + c->offset = c->mem->used - 1;
17491 + chunkqueue_remove_finished_chunks(sess->rb);
17493 + if (sess->remote_con->file_finished) {
17494 + /* send final HTTP-Chunk packet */
17495 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17500 + ERROR("%s", "oops, we failed to read");
17504 + joblist_append(srv, sess->remote_con);
17507 + TRACE("unexpected state for a FDEVENT_IN: %d", sess->state);
17513 if (revents & FDEVENT_OUT) {
17514 /* nothing to do */
17518 /* perhaps this issue is already handled */
17519 if (revents & FDEVENT_HUP) {
17520 - /* check if we still have a unfinished header package which is a body in reality */
17521 - if (con->file_started == 0 &&
17522 - hctx->response_header->used) {
17523 - con->file_started = 1;
17524 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
17525 - joblist_append(srv, con);
17528 - if (con->file_finished == 0) {
17529 - http_chunk_append_mem(srv, con, NULL, 0);
17530 - joblist_append(srv, con);
17533 con->file_finished = 1;
17535 - if (chunkqueue_is_empty(con->write_queue)) {
17536 - /* there is nothing left to write */
17537 - connection_set_state(srv, con, CON_STATE_RESPONSE_END);
17539 - /* used the write-handler to finish the request on demand */
17544 - log_error_write(srv, __FILE__, __LINE__, "sddd", "got HUP from cgi", con->fd, hctx->fd, revents);
17547 - /* rtsigs didn't liked the close */
17548 - cgi_connection_close(srv, hctx);
17550 + fdevent_event_del(srv->ev, sess->sock);
17552 + /* someone has to close this socket now :) */
17553 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
17554 + joblist_append(srv, sess->remote_con);
17555 } else if (revents & FDEVENT_ERR) {
17556 con->file_finished = 1;
17559 /* kill all connections to the cgi process */
17560 - cgi_connection_close(srv, hctx);
17562 - log_error_write(srv, __FILE__, __LINE__, "s", "cgi-FDEVENT_ERR");
17564 - return HANDLER_ERROR;
17565 + fdevent_event_del(srv->ev, sess->sock);
17569 return HANDLER_FINISHED;
17573 static int cgi_env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
17577 if (!key || !val) return -1;
17580 dst = malloc(key_len + val_len + 3);
17581 memcpy(dst, key, key_len);
17582 dst[key_len] = '=';
17583 /* add the \0 from the value */
17584 memcpy(dst + key_len + 1, val, val_len + 1);
17587 if (env->size == 0) {
17589 env->ptr = malloc(env->size * sizeof(*env->ptr));
17590 @@ -678,45 +546,45 @@
17592 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
17596 env->ptr[env->used++] = dst;
17602 static int cgi_create_env(server *srv, connection *con, plugin_data *p, buffer *cgi_handler) {
17607 char b2[INET6_ADDRSTRLEN + 1];
17612 int from_cgi_fds[2];
17620 if (cgi_handler->used > 1) {
17621 /* stat the exec file */
17622 if (-1 == (stat(cgi_handler->ptr, &st))) {
17623 - log_error_write(srv, __FILE__, __LINE__, "sbss",
17624 + log_error_write(srv, __FILE__, __LINE__, "sbss",
17625 "stat for cgi-handler", cgi_handler,
17626 "failed:", strerror(errno));
17632 if (pipe(to_cgi_fds)) {
17633 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17638 if (pipe(from_cgi_fds)) {
17639 log_error_write(srv, __FILE__, __LINE__, "ss", "pipe failed:", strerror(errno));
17645 switch (pid = fork()) {
17647 @@ -730,44 +598,40 @@
17650 server_socket *srv_sock = con->srv_socket;
17653 /* move stdout to from_cgi_fd[1] */
17654 close(STDOUT_FILENO);
17655 dup2(from_cgi_fds[1], STDOUT_FILENO);
17656 close(from_cgi_fds[1]);
17658 close(from_cgi_fds[0]);
17661 /* move the stdin to to_cgi_fd[0] */
17662 close(STDIN_FILENO);
17663 dup2(to_cgi_fds[0], STDIN_FILENO);
17664 close(to_cgi_fds[0]);
17666 close(to_cgi_fds[1]);
17669 - * this is not nice, but it works
17671 - * we feed the stderr of the CGI to our errorlog, if possible
17674 + * FIXME: add a event-handler for STDERR_FILENO and let it LOG()
17676 - if (srv->errorlog_mode == ERRORLOG_FILE) {
17677 - close(STDERR_FILENO);
17678 - dup2(srv->errorlog_fd, STDERR_FILENO);
17682 + close(STDERR_FILENO);
17684 /* create environment */
17690 cgi_env_add(&env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
17692 if (!buffer_is_empty(con->server_name)) {
17693 cgi_env_add(&env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
17696 - s = inet_ntop(srv_sock->addr.plain.sa_family,
17697 - srv_sock->addr.plain.sa_family == AF_INET6 ?
17698 + s = inet_ntop(srv_sock->addr.plain.sa_family,
17699 + srv_sock->addr.plain.sa_family == AF_INET6 ?
17700 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17701 (const void *) &(srv_sock->addr.ipv4.sin_addr),
17703 @@ -779,10 +643,12 @@
17704 cgi_env_add(&env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
17706 s = get_http_version_name(con->request.http_version);
17709 + TRACE("http-version: %s (%d)", s, con->request.http_version);
17711 cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
17717 ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
17719 @@ -790,10 +656,10 @@
17722 cgi_env_add(&env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
17726 - s = inet_ntop(srv_sock->addr.plain.sa_family,
17727 - srv_sock->addr.plain.sa_family == AF_INET6 ?
17728 + s = inet_ntop(srv_sock->addr.plain.sa_family,
17729 + srv_sock->addr.plain.sa_family == AF_INET6 ?
17730 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
17731 (const void *) &(srv_sock->addr.ipv4.sin_addr),
17733 @@ -811,15 +677,18 @@
17734 cgi_env_add(&env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200"));
17735 if (!buffer_is_empty(con->uri.query)) {
17736 cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_BUF_LEN(con->uri.query));
17738 + /* set a empty QUERY_STRING */
17739 + cgi_env_add(&env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
17741 if (!buffer_is_empty(con->request.orig_uri)) {
17742 cgi_env_add(&env, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
17749 - s = inet_ntop(con->dst_addr.plain.sa_family,
17750 - con->dst_addr.plain.sa_family == AF_INET6 ?
17751 + s = inet_ntop(con->dst_addr.plain.sa_family,
17752 + con->dst_addr.plain.sa_family == AF_INET6 ?
17753 (const void *) &(con->dst_addr.ipv6.sin6_addr) :
17754 (const void *) &(con->dst_addr.ipv4.sin_addr),
17756 @@ -828,7 +697,7 @@
17758 cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
17763 ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
17765 @@ -836,19 +705,19 @@
17768 cgi_env_add(&env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
17771 if (!buffer_is_empty(con->authed_user)) {
17772 cgi_env_add(&env, CONST_STR_LEN("REMOTE_USER"),
17773 CONST_BUF_LEN(con->authed_user));
17777 /* request.content_length < SSIZE_MAX, see request.c */
17778 ltostr(buf, con->request.content_length);
17779 cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
17780 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
17781 cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
17782 cgi_env_add(&env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
17786 if (NULL != (s = getenv("LD_PRELOAD"))) {
17787 cgi_env_add(&env, CONST_STR_LEN("LD_PRELOAD"), s, strlen(s));
17788 @@ -863,24 +732,24 @@
17789 cgi_env_add(&env, CONST_STR_LEN("SYSTEMROOT"), s, strlen(s));
17794 for (n = 0; n < con->request.headers->used; n++) {
17798 ds = (data_string *)con->request.headers->data[n];
17801 if (ds->value->used && ds->key->used) {
17805 buffer_reset(p->tmp_buf);
17808 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
17809 buffer_copy_string(p->tmp_buf, "HTTP_");
17810 p->tmp_buf->used--; /* strip \0 after HTTP_ */
17814 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17817 for (j = 0; j < ds->key->used - 1; j++) {
17819 if (light_isalpha(ds->key->ptr[j])) {
17820 @@ -893,46 +762,46 @@
17821 p->tmp_buf->ptr[p->tmp_buf->used++] = cr;
17823 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17826 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17831 for (n = 0; n < con->environment->used; n++) {
17835 ds = (data_string *)con->environment->data[n];
17838 if (ds->value->used && ds->key->used) {
17842 buffer_reset(p->tmp_buf);
17845 buffer_prepare_append(p->tmp_buf, ds->key->used + 2);
17848 for (j = 0; j < ds->key->used - 1; j++) {
17849 - p->tmp_buf->ptr[p->tmp_buf->used++] =
17850 - isalpha((unsigned char)ds->key->ptr[j]) ?
17851 + p->tmp_buf->ptr[p->tmp_buf->used++] =
17852 + isalpha((unsigned char)ds->key->ptr[j]) ?
17853 toupper((unsigned char)ds->key->ptr[j]) : '_';
17855 p->tmp_buf->ptr[p->tmp_buf->used++] = '\0';
17858 cgi_env_add(&env, CONST_BUF_LEN(p->tmp_buf), CONST_BUF_LEN(ds->value));
17863 if (env.size == env.used) {
17865 env.ptr = realloc(env.ptr, env.size * sizeof(*env.ptr));
17869 env.ptr[env.used] = NULL;
17874 args = malloc(sizeof(*args) * argc);
17878 if (cgi_handler->used > 1) {
17879 args[i++] = cgi_handler->ptr;
17881 @@ -942,7 +811,7 @@
17882 /* search for the last / */
17883 if (NULL != (c = strrchr(con->physical.path->ptr, '/'))) {
17887 /* change to the physical directory */
17888 if (-1 == chdir(con->physical.path->ptr)) {
17889 log_error_write(srv, __FILE__, __LINE__, "ssb", "chdir failed:", strerror(errno), con->physical.path);
17890 @@ -952,14 +821,14 @@
17892 /* we don't need the client socket */
17893 for (i = 3; i < 256; i++) {
17894 - if (i != srv->errorlog_fd) close(i);
17900 execve(args[0], args, env.ptr);
17903 log_error_write(srv, __FILE__, __LINE__, "sss", "CGI failed:", strerror(errno), args[0]);
17909 @@ -969,16 +838,16 @@
17910 log_error_write(srv, __FILE__, __LINE__, "ss", "fork failed:", strerror(errno));
17913 - handler_ctx *hctx;
17914 + cgi_session *sess;
17917 close(from_cgi_fds[1]);
17918 close(to_cgi_fds[0]);
17921 if (con->request.content_length) {
17922 chunkqueue *cq = con->request_content_queue;
17926 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
17928 /* there is content to send */
17929 @@ -993,16 +862,16 @@
17930 if (-1 == c->file.fd && /* open the file if not already open */
17931 -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
17932 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
17935 close(from_cgi_fds[0]);
17936 close(to_cgi_fds[1]);
17940 c->file.mmap.length = c->file.length;
17943 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.mmap.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
17944 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
17945 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
17946 strerror(errno), c->file.name, c->file.fd);
17948 close(from_cgi_fds[0]);
17949 @@ -1012,7 +881,7 @@
17955 /* chunk_reset() or chunk_free() will cleanup for us */
17958 @@ -1020,7 +889,7 @@
17961 con->http_status = 507;
17966 con->http_status = 403;
17967 @@ -1033,7 +902,7 @@
17970 con->http_status = 507;
17975 con->http_status = 403;
17976 @@ -1056,103 +925,95 @@
17979 close(to_cgi_fds[1]);
17982 /* register PID and wait for them asyncronously */
17984 buffer_reset(con->physical.path);
17986 - hctx = cgi_handler_ctx_init();
17988 - hctx->remote_conn = con;
17989 - hctx->plugin_data = p;
17991 - hctx->fd = from_cgi_fds[0];
17992 - hctx->fde_ndx = -1;
17994 - con->plugin_ctx[p->id] = hctx;
17996 - fdevent_register(srv->ev, hctx->fd, cgi_handle_fdevent, hctx);
17997 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
17999 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
18001 + sess = cgi_session_init();
18003 + sess->remote_con = con;
18006 + sess->sock->fd = from_cgi_fds[0];
18007 + sess->sock->type = IOSOCKET_TYPE_PIPE;
18009 + if (-1 == fdevent_fcntl_set(srv->ev, sess->sock)) {
18010 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
18012 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18013 - fdevent_unregister(srv->ev, hctx->fd);
18015 - log_error_write(srv, __FILE__, __LINE__, "sd", "cgi close:", hctx->fd);
18019 - cgi_handler_ctx_free(hctx);
18021 - con->plugin_ctx[p->id] = NULL;
18024 + cgi_session_free(sess);
18030 + con->plugin_ctx[p->id] = sess;
18032 + fdevent_register(srv->ev, sess->sock, cgi_handle_fdevent, sess);
18033 + fdevent_event_add(srv->ev, sess->sock, FDEVENT_IN);
18035 + sess->state = CGI_STATE_READ_RESPONSE_HEADER;
18048 -#define PATCH(x) \
18049 - p->conf.x = s->x;
18050 static int mod_cgi_patch_connection(server *srv, connection *con, plugin_data *p) {
18052 plugin_config *s = p->config_storage[0];
18057 + PATCH_OPTION(cgi);
18059 /* skip the first, the global context */
18060 for (i = 1; i < srv->config_context->used; i++) {
18061 data_config *dc = (data_config *)srv->config_context->data[i];
18062 s = p->config_storage[i];
18065 /* condition didn't match */
18066 if (!config_check_cond(srv, con, dc)) continue;
18070 for (j = 0; j < dc->value->used; j++) {
18071 data_unset *du = dc->value->data[j];
18074 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cgi.assign"))) {
18076 + PATCH_OPTION(cgi);
18086 URIHANDLER_FUNC(cgi_is_handled) {
18088 plugin_data *p = p_d;
18089 buffer *fn = con->physical.path;
18092 if (fn->used == 0) return HANDLER_GO_ON;
18095 + TRACE("http-version: (%d)", con->request.http_version);
18097 mod_cgi_patch_connection(srv, con, p);
18100 s_len = fn->used - 1;
18103 for (k = 0; k < p->conf.cgi->used; k++) {
18104 data_string *ds = (data_string *)p->conf.cgi->data[k];
18105 size_t ct_len = ds->key->used - 1;
18108 if (ds->key->used == 0) continue;
18109 if (s_len < ct_len) continue;
18112 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
18113 if (cgi_create_env(srv, con, p, ds->value)) {
18114 con->http_status = 500;
18117 buffer_reset(con->physical.path);
18118 return HANDLER_FINISHED;
18120 @@ -1160,7 +1021,7 @@
18126 return HANDLER_GO_ON;
18129 @@ -1168,11 +1029,11 @@
18130 plugin_data *p = p_d;
18132 /* the trigger handle only cares about lonely PID which we have to wait for */
18136 for (ndx = 0; ndx < p->cgi_pid.used; ndx++) {
18140 switch(waitpid(p->cgi_pid.ptr[ndx], &status, WNOHANG)) {
18142 /* not finished yet */
18143 @@ -1182,7 +1043,7 @@
18146 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18149 return HANDLER_ERROR;
18152 @@ -1193,96 +1054,103 @@
18154 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18158 cgi_pid_del(srv, p, p->cgi_pid.ptr[ndx]);
18159 - /* del modified the buffer structure
18160 + /* del modified the buffer structure
18161 * and copies the last entry to the current one
18162 * -> recheck the current index
18169 return HANDLER_GO_ON;
18172 SUBREQUEST_FUNC(mod_cgi_handle_subrequest) {
18174 plugin_data *p = p_d;
18175 - handler_ctx *hctx = con->plugin_ctx[p->id];
18177 + cgi_session *sess = con->plugin_ctx[p->id];
18179 if (con->mode != p->id) return HANDLER_GO_ON;
18180 - if (NULL == hctx) return HANDLER_GO_ON;
18182 + if (NULL == sess) return HANDLER_GO_ON;
18184 + switch (cgi_demux_response(srv, con, p)) {
18188 + cgi_connection_close(srv, con, p);
18190 + /* if we get a IN|HUP and have read everything don't exec the close twice */
18191 + return HANDLER_FINISHED;
18193 + cgi_connection_close(srv, con, p);
18195 + if (0 == con->http_status) con->http_status = 500;
18196 + connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
18197 + con->mode = DIRECT;
18199 + return HANDLER_FINISHED;
18203 - log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", hctx, hctx->pid);
18205 - if (hctx->pid == 0) return HANDLER_FINISHED;
18207 - switch(waitpid(hctx->pid, &status, WNOHANG)) {
18208 + log_error_write(srv, __FILE__, __LINE__, "sdd", "subrequest, pid =", sess, sess->pid);
18210 + if (sess->pid == 0) return HANDLER_FINISHED;
18212 + switch(waitpid(sess->pid, &status, WNOHANG)) {
18214 /* we only have for events here if we don't have the header yet,
18215 * otherwise the event-handler will send us the incoming data */
18216 - if (con->file_started) return HANDLER_FINISHED;
18218 - return HANDLER_WAIT_FOR_EVENT;
18219 + if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18220 + if (con->file_finished) return HANDLER_FINISHED;
18222 + return HANDLER_GO_ON;
18224 if (errno == EINTR) return HANDLER_WAIT_FOR_EVENT;
18227 if (errno == ECHILD && con->file_started == 0) {
18229 - * second round but still not response
18230 + * second round but still not response
18232 - return HANDLER_WAIT_FOR_EVENT;
18233 + return HANDLER_WAIT_FOR_EVENT;
18237 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed: ", strerror(errno));
18238 con->mode = DIRECT;
18239 con->http_status = 500;
18243 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18244 - fdevent_unregister(srv->ev, hctx->fd);
18246 - if (close(hctx->fd)) {
18247 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18250 - cgi_handler_ctx_free(hctx);
18255 + fdevent_event_del(srv->ev, sess->sock);
18256 + fdevent_unregister(srv->ev, sess->sock);
18258 + cgi_session_free(sess);
18260 con->plugin_ctx[p->id] = NULL;
18263 return HANDLER_FINISHED;
18265 - /* cgi process exited cleanly
18267 - * check if we already got the response
18270 - if (!con->file_started) return HANDLER_WAIT_FOR_EVENT;
18272 + con->file_finished = 1;
18274 if (WIFEXITED(status)) {
18277 log_error_write(srv, __FILE__, __LINE__, "s", "cgi died ?");
18280 con->mode = DIRECT;
18281 con->http_status = 500;
18288 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
18289 - fdevent_unregister(srv->ev, hctx->fd);
18291 - if (close(hctx->fd)) {
18292 - log_error_write(srv, __FILE__, __LINE__, "sds", "cgi close failed ", hctx->fd, strerror(errno));
18295 - cgi_handler_ctx_free(hctx);
18300 + fdevent_event_del(srv->ev, sess->sock);
18301 + fdevent_unregister(srv->ev, sess->sock);
18303 + cgi_session_free(sess);
18305 con->plugin_ctx[p->id] = NULL;
18306 return HANDLER_FINISHED;
18308 @@ -1306,8 +1174,8 @@
18309 p->init = mod_cgi_init;
18310 p->cleanup = mod_cgi_free;
18311 p->set_defaults = mod_fastcgi_set_defaults;
18319 --- ../lighttpd-1.4.11/src/mod_cml.c 2006-01-30 13:51:48.000000000 +0200
18320 +++ lighttpd-1.4.12/src/mod_cml.c 2006-07-16 00:26:03.000000000 +0300
18322 #include <stdlib.h>
18323 #include <string.h>
18325 -#include <unistd.h>
18328 #include "buffer.h"
18329 @@ -20,50 +19,50 @@
18330 /* init the plugin data */
18331 INIT_FUNC(mod_cml_init) {
18335 p = calloc(1, sizeof(*p));
18338 p->basedir = buffer_init();
18339 p->baseurl = buffer_init();
18340 p->trigger_handler = buffer_init();
18346 /* detroy the plugin data */
18347 FREE_FUNC(mod_cml_free) {
18348 plugin_data *p = p_d;
18353 if (!p) return HANDLER_GO_ON;
18356 if (p->config_storage) {
18358 for (i = 0; i < srv->config_context->used; i++) {
18359 plugin_config *s = p->config_storage[i];
18362 buffer_free(s->ext);
18365 buffer_free(s->mc_namespace);
18366 buffer_free(s->power_magnet);
18367 array_free(s->mc_hosts);
18370 #if defined(HAVE_MEMCACHE_H)
18371 if (s->mc) mc_free(s->mc);
18377 free(p->config_storage);
18381 buffer_free(p->trigger_handler);
18382 buffer_free(p->basedir);
18383 buffer_free(p->baseurl);
18389 return HANDLER_GO_ON;
18392 @@ -72,22 +71,22 @@
18393 SETDEFAULTS_FUNC(mod_cml_set_defaults) {
18394 plugin_data *p = p_d;
18397 - config_values_t cv[] = {
18399 + config_values_t cv[] = {
18400 { "cml.extension", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
18401 { "cml.memcache-hosts", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
18402 { "cml.memcache-namespace", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
18403 { "cml.power-magnet", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
18404 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
18408 if (!p) return HANDLER_ERROR;
18411 p->config_storage = malloc(srv->config_context->used * sizeof(specific_config *));
18414 for (i = 0; i < srv->config_context->used; i++) {
18418 s = malloc(sizeof(plugin_config));
18419 s->ext = buffer_init();
18420 s->mc_hosts = array_init();
18421 @@ -96,87 +95,84 @@
18422 #if defined(HAVE_MEMCACHE_H)
18427 cv[0].destination = s->ext;
18428 cv[1].destination = s->mc_hosts;
18429 cv[2].destination = s->mc_namespace;
18430 cv[3].destination = s->power_magnet;
18433 p->config_storage[i] = s;
18436 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
18437 return HANDLER_ERROR;
18441 if (s->mc_hosts->used) {
18442 #if defined(HAVE_MEMCACHE_H)
18447 for (k = 0; k < s->mc_hosts->used; k++) {
18448 data_string *ds = (data_string *)s->mc_hosts->data[k];
18451 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
18452 - log_error_write(srv, __FILE__, __LINE__, "sb",
18453 - "connection to host failed:",
18454 + log_error_write(srv, __FILE__, __LINE__, "sb",
18455 + "connection to host failed:",
18459 return HANDLER_ERROR;
18463 - log_error_write(srv, __FILE__, __LINE__, "s",
18464 + log_error_write(srv, __FILE__, __LINE__, "s",
18465 "memcache support is not compiled in but cml.memcache-hosts is set, aborting");
18466 return HANDLER_ERROR;
18472 return HANDLER_GO_ON;
18475 -#define PATCH(x) \
18476 - p->conf.x = s->x;
18477 static int mod_cml_patch_connection(server *srv, connection *con, plugin_data *p) {
18479 plugin_config *s = p->config_storage[0];
18483 + PATCH_OPTION(ext);
18484 #if defined(HAVE_MEMCACHE_H)
18486 + PATCH_OPTION(mc);
18488 - PATCH(mc_namespace);
18489 - PATCH(power_magnet);
18491 + PATCH_OPTION(mc_namespace);
18492 + PATCH_OPTION(power_magnet);
18494 /* skip the first, the global context */
18495 for (i = 1; i < srv->config_context->used; i++) {
18496 data_config *dc = (data_config *)srv->config_context->data[i];
18497 s = p->config_storage[i];
18500 /* condition didn't match */
18501 if (!config_check_cond(srv, con, dc)) continue;
18505 for (j = 0; j < dc->value->used; j++) {
18506 data_unset *du = dc->value->data[j];
18509 if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.extension"))) {
18511 + PATCH_OPTION(ext);
18512 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-hosts"))) {
18513 #if defined(HAVE_MEMCACHE_H)
18515 + PATCH_OPTION(mc);
18517 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.memcache-namespace"))) {
18518 - PATCH(mc_namespace);
18519 + PATCH_OPTION(mc_namespace);
18520 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("cml.power-magnet"))) {
18521 - PATCH(power_magnet);
18522 + PATCH_OPTION(power_magnet);
18532 int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
18534 @@ -187,57 +183,57 @@
18536 buffer_copy_string_buffer(b, con->uri.path);
18537 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18541 b->used = c - b->ptr + 2;
18547 buffer_copy_string_buffer(b, con->physical.path);
18548 for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);
18552 b->used = c - b->ptr + 2;
18558 /* prepare variables
18560 * - get-param-based
18564 return cache_parse_lua(srv, con, p, cml_file);
18569 URIHANDLER_FUNC(mod_cml_power_magnet) {
18570 plugin_data *p = p_d;
18573 mod_cml_patch_connection(srv, con, p);
18576 buffer_reset(p->basedir);
18577 buffer_reset(p->baseurl);
18578 buffer_reset(p->trigger_handler);
18580 if (buffer_is_empty(p->conf.power_magnet)) return HANDLER_GO_ON;
18586 * cml.power-magnet = server.docroot + "/rewrite.cml"
18588 * is called on EACH request, take the original REQUEST_URI and modifies the
18589 - * request header as neccesary.
18590 + * request header as neccesary.
18593 * if file_exists("/maintainance.html") {
18594 * output_include = ( "/maintainance.html" )
18595 - * return CACHE_HIT
18596 + * return CACHE_HIT
18599 * as we only want to rewrite HTML like requests we should cover it in a conditional
18604 switch(cache_call_lua(srv, con, p, p->conf.power_magnet)) {
18605 @@ -266,20 +262,20 @@
18607 URIHANDLER_FUNC(mod_cml_is_handled) {
18608 plugin_data *p = p_d;
18611 if (buffer_is_empty(con->physical.path)) return HANDLER_ERROR;
18614 mod_cml_patch_connection(srv, con, p);
18617 buffer_reset(p->basedir);
18618 buffer_reset(p->baseurl);
18619 buffer_reset(p->trigger_handler);
18621 if (buffer_is_empty(p->conf.ext)) return HANDLER_GO_ON;
18624 if (!buffer_is_equal_right_len(con->physical.path, p->conf.ext, p->conf.ext->used - 1)) {
18625 return HANDLER_GO_ON;
18629 switch(cache_call_lua(srv, con, p, con->physical.path)) {
18631 @@ -311,15 +307,15 @@
18632 int mod_cml_plugin_init(plugin *p) {
18633 p->version = LIGHTTPD_VERSION_ID;
18634 p->name = buffer_init_string("cache");
18637 p->init = mod_cml_init;
18638 p->cleanup = mod_cml_free;
18639 p->set_defaults = mod_cml_set_defaults;
18642 p->handle_subrequest_start = mod_cml_is_handled;
18643 p->handle_physical = mod_cml_power_magnet;
18651 --- ../lighttpd-1.4.11/src/mod_cml.h 2006-01-30 13:51:35.000000000 +0200
18652 +++ lighttpd-1.4.12/src/mod_cml.h 2006-07-16 00:26:03.000000000 +0300
18653 @@ -16,10 +16,10 @@
18660 buffer *mc_namespace;
18661 -#if defined(HAVE_MEMCACHE_H)
18662 +#if defined(HAVE_MEMCACHE_H)
18663 struct memcache *mc;
18665 buffer *power_magnet;
18666 @@ -27,15 +27,15 @@
18676 buffer *trigger_handler;
18679 plugin_config **config_storage;
18681 - plugin_config conf;
18683 + plugin_config conf;
18686 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn);
18687 --- ../lighttpd-1.4.11/src/mod_cml_funcs.c 2005-11-17 16:15:08.000000000 +0200
18688 +++ lighttpd-1.4.12/src/mod_cml_funcs.c 2006-07-16 00:26:04.000000000 +0300
18690 #include <stdlib.h>
18691 #include <string.h>
18693 -#include <unistd.h>
18694 -#include <dirent.h>
18698 #include "buffer.h"
18701 #include "plugin.h"
18702 #include "response.h"
18703 +#include "sys-files.h"
18705 #include "mod_cml.h"
18706 #include "mod_cml_funcs.h"
18716 @@ -42,29 +42,29 @@
18719 int n = lua_gettop(L);
18724 b.size = sizeof(hex);
18728 lua_pushstring(L, "md5: expected one argument");
18733 if (!lua_isstring(L, 1)) {
18734 lua_pushstring(L, "md5: argument has to be a string");
18740 MD5_Update(&Md5Ctx, (unsigned char *)lua_tostring(L, 1), lua_strlen(L, 1));
18741 MD5_Final(HA1, &Md5Ctx);
18744 buffer_copy_string_hex(&b, (char *)HA1, 16);
18747 lua_pushstring(L, b.ptr);
18753 @@ -72,37 +72,37 @@
18754 int f_file_mtime(lua_State *L) {
18756 int n = lua_gettop(L);
18760 lua_pushstring(L, "file_mtime: expected one argument");
18765 if (!lua_isstring(L, 1)) {
18766 lua_pushstring(L, "file_mtime: argument has to be a string");
18771 if (-1 == stat(lua_tostring(L, 1), &st)) {
18777 lua_pushnumber(L, st.st_mtime);
18784 int f_dir_files_iter(lua_State *L) {
18789 d = lua_touserdata(L, lua_upvalueindex(1));
18792 if (NULL == (de = readdir(d))) {
18799 lua_pushstring(L, de->d_name);
18800 @@ -113,75 +113,75 @@
18801 int f_dir_files(lua_State *L) {
18803 int n = lua_gettop(L);
18807 lua_pushstring(L, "dir_files: expected one argument");
18812 if (!lua_isstring(L, 1)) {
18813 lua_pushstring(L, "dir_files: argument has to be a string");
18817 - /* check if there is a valid DIR handle on the stack */
18819 + /* check if there is a valid DIR handle on the stack */
18820 if (NULL == (d = opendir(lua_tostring(L, 1)))) {
18826 /* push d into registry */
18827 lua_pushlightuserdata(L, d);
18828 lua_pushcclosure(L, f_dir_files_iter, 1);
18835 int f_file_isreg(lua_State *L) {
18837 int n = lua_gettop(L);
18841 lua_pushstring(L, "file_isreg: expected one argument");
18846 if (!lua_isstring(L, 1)) {
18847 lua_pushstring(L, "file_isreg: argument has to be a string");
18852 if (-1 == stat(lua_tostring(L, 1), &st)) {
18858 lua_pushnumber(L, S_ISREG(st.st_mode));
18864 int f_file_isdir(lua_State *L) {
18866 int n = lua_gettop(L);
18870 lua_pushstring(L, "file_isreg: expected one argument");
18875 if (!lua_isstring(L, 1)) {
18876 lua_pushstring(L, "file_isreg: argument has to be a string");
18881 if (-1 == stat(lua_tostring(L, 1), &st)) {
18887 lua_pushnumber(L, S_ISDIR(st.st_mode));
18893 @@ -192,33 +192,33 @@
18895 int n = lua_gettop(L);
18896 struct memcache *mc;
18899 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18900 lua_pushstring(L, "where is my userdata ?");
18905 mc = lua_touserdata(L, lua_upvalueindex(1));
18909 lua_pushstring(L, "expected one argument");
18914 if (!lua_isstring(L, 1)) {
18915 lua_pushstring(L, "argument has to be a string");
18919 - if (NULL == (r = mc_aget(mc,
18921 + if (NULL == (r = mc_aget(mc,
18922 lua_tostring(L, 1), lua_strlen(L, 1)))) {
18925 lua_pushboolean(L, 0);
18933 lua_pushboolean(L, 1);
18936 @@ -226,74 +226,74 @@
18937 int f_memcache_get_string(lua_State *L) {
18939 int n = lua_gettop(L);
18942 struct memcache *mc;
18945 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18946 lua_pushstring(L, "where is my userdata ?");
18951 mc = lua_touserdata(L, lua_upvalueindex(1));
18957 lua_pushstring(L, "expected one argument");
18962 if (!lua_isstring(L, 1)) {
18963 lua_pushstring(L, "argument has to be a string");
18967 - if (NULL == (r = mc_aget(mc,
18969 + if (NULL == (r = mc_aget(mc,
18970 lua_tostring(L, 1), lua_strlen(L, 1)))) {
18976 lua_pushstring(L, r);
18985 int f_memcache_get_long(lua_State *L) {
18987 int n = lua_gettop(L);
18990 struct memcache *mc;
18993 if (!lua_islightuserdata(L, lua_upvalueindex(1))) {
18994 lua_pushstring(L, "where is my userdata ?");
18999 mc = lua_touserdata(L, lua_upvalueindex(1));
19005 lua_pushstring(L, "expected one argument");
19010 if (!lua_isstring(L, 1)) {
19011 lua_pushstring(L, "argument has to be a string");
19015 - if (NULL == (r = mc_aget(mc,
19017 + if (NULL == (r = mc_aget(mc,
19018 lua_tostring(L, 1), lua_strlen(L, 1)))) {
19024 lua_pushnumber(L, strtol(r, NULL, 10));
19033 --- ../lighttpd-1.4.11/src/mod_cml_lua.c 2006-01-30 13:56:40.000000000 +0200
19034 +++ lighttpd-1.4.12/src/mod_cml_lua.c 2006-07-16 00:26:04.000000000 +0300
19047 #include <lualib.h>
19048 +#include <lauxlib.h>
19052 @@ -39,11 +40,11 @@
19054 static const char * load_file(lua_State *L, void *data, size_t *size) {
19061 if (rm->done) return 0;
19064 *size = rm->st.size;
19066 return rm->st.start;
19067 @@ -51,47 +52,47 @@
19069 static int lua_to_c_get_string(lua_State *L, const char *varname, buffer *b) {
19073 lua_pushstring(L, varname);
19076 curelem = lua_gettop(L);
19077 lua_gettable(L, LUA_GLOBALSINDEX);
19080 /* it should be a table */
19081 if (!lua_isstring(L, curelem)) {
19082 lua_settop(L, curelem - 1);
19089 buffer_copy_string(b, lua_tostring(L, curelem));
19095 assert(curelem - 1 == lua_gettop(L));
19101 static int lua_to_c_is_table(lua_State *L, const char *varname) {
19105 lua_pushstring(L, varname);
19108 curelem = lua_gettop(L);
19109 lua_gettable(L, LUA_GLOBALSINDEX);
19112 /* it should be a table */
19113 if (!lua_istable(L, curelem)) {
19114 lua_settop(L, curelem - 1);
19121 lua_settop(L, curelem - 1);
19124 assert(curelem - 1 == lua_gettop(L));
19131 lua_pushlstring(L, key, key_len);
19132 lua_pushlstring(L, val, val_len);
19133 lua_settable(L, tbl);
19139 @@ -108,21 +109,21 @@
19142 char *key = NULL, *val = NULL;
19148 /* we need the \0 */
19149 for (i = 0; i < qrystr->used; i++) {
19150 switch(qrystr->ptr[i]) {
19153 val = qrystr->ptr + i + 1;
19156 qrystr->ptr[i] = '\0';
19165 case '\0': /* fin symbol */
19166 @@ -131,19 +132,19 @@
19168 /* terminate the value */
19169 qrystr->ptr[i] = '\0';
19171 - c_to_lua_push(L, tbl,
19173 + c_to_lua_push(L, tbl,
19179 key = qrystr->ptr + i + 1;
19190 @@ -151,21 +152,21 @@
19196 if (NULL != (d = array_get_element(con->request.headers, "Cookie"))) {
19197 data_string *ds = (data_string *)d;
19198 size_t key = 0, value = 0;
19199 size_t is_key = 1, is_sid = 0;
19204 if (!DATA_IS_STRING(d)) return -1;
19205 if (ds->value->used == 0) return -1;
19208 if (ds->value->ptr[0] == '\0' ||
19209 ds->value->ptr[0] == '=' ||
19210 ds->value->ptr[0] == ';') return -1;
19213 buffer_reset(p->session_id);
19214 for (i = 0; i < ds->value->used; i++) {
19215 switch(ds->value->ptr[i]) {
19216 @@ -176,16 +177,16 @@
19229 buffer_copy_string_len(p->session_id, ds->value->ptr + value, i - value);
19236 @@ -204,48 +205,43 @@
19246 int cache_parse_lua(server *srv, connection *con, plugin_data *p, buffer *fn) {
19251 buffer *b = buffer_init();
19252 int header_tbl = 0;
19256 stream_open(&rm.st, fn);
19259 /* push the lua file to the interpreter and see what happends */
19263 - luaopen_table(L);
19264 - luaopen_string(L);
19268 + L = luaL_newstate();
19269 + luaL_openlibs(L);
19271 /* register functions */
19272 lua_register(L, "md5", f_crypto_md5);
19273 lua_register(L, "file_mtime", f_file_mtime);
19274 lua_register(L, "file_isreg", f_file_isreg);
19275 lua_register(L, "file_isdir", f_file_isreg);
19276 lua_register(L, "dir_files", f_dir_files);
19279 #ifdef HAVE_MEMCACHE_H
19280 lua_pushliteral(L, "memcache_get_long");
19281 lua_pushlightuserdata(L, p->conf.mc);
19282 lua_pushcclosure(L, f_memcache_get_long, 1);
19283 lua_settable(L, LUA_GLOBALSINDEX);
19286 lua_pushliteral(L, "memcache_get_string");
19287 lua_pushlightuserdata(L, p->conf.mc);
19288 lua_pushcclosure(L, f_memcache_get_string, 1);
19289 lua_settable(L, LUA_GLOBALSINDEX);
19292 lua_pushliteral(L, "memcache_exists");
19293 lua_pushlightuserdata(L, p->conf.mc);
19294 lua_pushcclosure(L, f_memcache_exists, 1);
19295 @@ -255,11 +251,11 @@
19296 lua_pushliteral(L, "request");
19298 lua_settable(L, LUA_GLOBALSINDEX);
19301 lua_pushliteral(L, "request");
19302 header_tbl = lua_gettop(L);
19303 lua_gettable(L, LUA_GLOBALSINDEX);
19306 c_to_lua_push(L, header_tbl, CONST_STR_LEN("REQUEST_URI"), CONST_BUF_LEN(con->request.orig_uri));
19307 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
19308 c_to_lua_push(L, header_tbl, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
19309 @@ -267,84 +263,84 @@
19310 if (!buffer_is_empty(con->request.pathinfo)) {
19311 c_to_lua_push(L, header_tbl, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
19315 c_to_lua_push(L, header_tbl, CONST_STR_LEN("CWD"), CONST_BUF_LEN(p->basedir));
19316 c_to_lua_push(L, header_tbl, CONST_STR_LEN("BASEURL"), CONST_BUF_LEN(p->baseurl));
19319 /* register GET parameter */
19320 lua_pushliteral(L, "get");
19322 lua_settable(L, LUA_GLOBALSINDEX);
19325 lua_pushliteral(L, "get");
19326 header_tbl = lua_gettop(L);
19327 lua_gettable(L, LUA_GLOBALSINDEX);
19330 buffer_copy_string_buffer(b, con->uri.query);
19331 cache_export_get_params(L, header_tbl, b);
19334 - /* 2 default constants */
19335 + /* 2 default constants */
19336 lua_pushliteral(L, "CACHE_HIT");
19337 lua_pushboolean(L, 0);
19338 lua_settable(L, LUA_GLOBALSINDEX);
19341 lua_pushliteral(L, "CACHE_MISS");
19342 lua_pushboolean(L, 1);
19343 lua_settable(L, LUA_GLOBALSINDEX);
19346 /* load lua program */
19347 if (lua_load(L, load_file, &rm, fn->ptr) || lua_pcall(L,0,1,0)) {
19348 log_error_write(srv, __FILE__, __LINE__, "s",
19349 lua_tostring(L,-1));
19356 /* get return value */
19357 ret = (int)lua_tonumber(L, -1);
19360 - /* fetch the data from lua */
19362 + /* fetch the data from lua */
19363 lua_to_c_get_string(L, "trigger_handler", p->trigger_handler);
19366 if (0 == lua_to_c_get_string(L, "output_contenttype", b)) {
19367 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(b));
19372 /* up to now it is a cache-hit, check if all files exist */
19379 if (!lua_to_c_is_table(L, "output_include")) {
19380 log_error_write(srv, __FILE__, __LINE__, "s",
19381 "output_include is missing or not a table");
19389 lua_pushstring(L, "output_include");
19392 curelem = lua_gettop(L);
19393 lua_gettable(L, LUA_GLOBALSINDEX);
19395 /* HOW-TO build a etag ?
19396 - * as we don't just have one file we have to take the stat()
19397 + * as we don't just have one file we have to take the stat()
19398 * from all base files, merge them and build the etag from
19402 * The mtime of the content is the mtime of the freshest base file
19408 lua_pushnil(L); /* first key */
19409 while (lua_next(L, curelem) != 0) {
19410 stat_cache_entry *sce = NULL;
19411 /* key' is at index -2 and value' at index -1 */
19414 if (lua_isstring(L, -1)) {
19415 const char *s = lua_tostring(L, -1);
19417 @@ -364,18 +360,18 @@
19418 /* a file is missing, call the handler to generate it */
19419 if (!buffer_is_empty(p->trigger_handler)) {
19420 ret = 1; /* cache-miss */
19423 log_error_write(srv, __FILE__, __LINE__, "s",
19424 "a file is missing, calling handler");
19429 /* handler not set -> 500 */
19433 log_error_write(srv, __FILE__, __LINE__, "s",
19434 "a file missing and no handler set");
19440 @@ -393,12 +389,12 @@
19446 lua_pop(L, 1); /* removes value'; keeps key' for next iteration */
19450 lua_settop(L, curelem - 1);
19455 char timebuf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")];
19456 @@ -410,9 +406,9 @@
19458 /* no Last-Modified specified */
19459 if ((mtime) && (NULL == ds)) {
19462 strftime(timebuf, sizeof(timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime(&mtime));
19465 response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), timebuf, sizeof(timebuf) - 1);
19468 @@ -428,9 +424,9 @@
19474 if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, &tbuf)) {
19475 - /* ok, the client already has our content,
19476 + /* ok, the client already has our content,
19477 * no need to send it again */
19479 chunkqueue_reset(con->write_queue);
19480 @@ -440,24 +436,24 @@
19481 chunkqueue_reset(con->write_queue);
19486 if (ret == 1 && !buffer_is_empty(p->trigger_handler)) {
19488 buffer_copy_string_buffer(con->uri.path, p->baseurl);
19489 buffer_append_string_buffer(con->uri.path, p->trigger_handler);
19492 buffer_copy_string_buffer(con->physical.path, p->basedir);
19493 buffer_append_string_buffer(con->physical.path, p->trigger_handler);
19496 chunkqueue_reset(con->write_queue);
19504 stream_close(&rm.st);
19508 return ret /* cache-error */;
19511 --- ../lighttpd-1.4.11/src/mod_compress.c 2005-11-18 13:49:14.000000000 +0200
19512 +++ lighttpd-1.4.12/src/mod_compress.c 2006-07-16 00:26:04.000000000 +0300
19514 #include <sys/stat.h>
19517 -#include <unistd.h>
19519 #include <stdlib.h>
19520 #include <string.h>
19522 #include "buffer.h"
19523 #include "response.h"
19524 #include "stat_cache.h"
19525 +#include "http_chunk.h"
19527 #include "plugin.h"
19532 #include "sys-mmap.h"
19533 +#include "sys-files.h"
19535 /* request: accept-encoding */
19536 #define HTTP_ACCEPT_ENCODING_IDENTITY BV(0)
19537 @@ -55,97 +56,127 @@
19543 plugin_config **config_storage;
19544 - plugin_config conf;
19545 + plugin_config conf;
19548 INIT_FUNC(mod_compress_init) {
19552 p = calloc(1, sizeof(*p));
19555 p->ofn = buffer_init();
19556 p->b = buffer_init();
19562 FREE_FUNC(mod_compress_free) {
19563 plugin_data *p = p_d;
19568 if (!p) return HANDLER_GO_ON;
19571 buffer_free(p->ofn);
19575 if (p->config_storage) {
19577 for (i = 0; i < srv->config_context->used; i++) {
19578 plugin_config *s = p->config_storage[i];
19583 array_free(s->compress);
19584 buffer_free(s->compress_cache_dir);
19589 free(p->config_storage);
19598 return HANDLER_GO_ON;
19601 +void mkdir_recursive(const char *dir) {
19603 + char dir_copy[256];
19604 + char *p = dir_copy;
19606 + if (!dir || !dir[0])
19609 + strncpy(dir_copy, dir, sizeof(dir_copy) / sizeof(dir_copy[0]));
19611 + while ((p = strchr(p + 1, '/')) != NULL) {
19614 + if ((mkdir(dir_copy, 0700) != 0) && (errno != EEXIST))
19620 + mkdir(dir, 0700);
19623 SETDEFAULTS_FUNC(mod_compress_setdefaults) {
19624 plugin_data *p = p_d;
19627 - config_values_t cv[] = {
19629 + config_values_t cv[] = {
19630 { "compress.cache-dir", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
19631 { "compress.filetype", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION },
19632 { "compress.max-filesize", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
19633 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
19637 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
19640 for (i = 0; i < srv->config_context->used; i++) {
19644 s = calloc(1, sizeof(plugin_config));
19645 s->compress_cache_dir = buffer_init();
19646 s->compress = array_init();
19647 s->compress_max_filesize = 0;
19650 cv[0].destination = s->compress_cache_dir;
19651 cv[1].destination = s->compress;
19652 cv[2].destination = &(s->compress_max_filesize);
19655 p->config_storage[i] = s;
19658 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
19659 return HANDLER_ERROR;
19663 if (!buffer_is_empty(s->compress_cache_dir)) {
19665 if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19666 - log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir",
19668 + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, attempting to create",
19669 s->compress_cache_dir, strerror(errno));
19671 - return HANDLER_ERROR;
19672 + mkdir_recursive(s->compress_cache_dir->ptr);
19674 + if (0 != stat(s->compress_cache_dir->ptr, &st)) {
19676 + log_error_write(srv, __FILE__, __LINE__, "sbs", "can't stat compress.cache-dir, create failed",
19677 + s->compress_cache_dir, strerror(errno));
19679 + return HANDLER_ERROR;
19686 return HANDLER_GO_ON;
19692 @@ -153,32 +184,32 @@
19705 - if (Z_OK != deflateInit2(&z,
19707 + if (Z_OK != deflateInit2(&z,
19708 Z_DEFAULT_COMPRESSION,
19711 -MAX_WBITS, /* supress zlib-header */
19713 Z_DEFAULT_STRATEGY)) {
19718 z.next_in = (unsigned char *)start;
19719 z.avail_in = st_size;
19725 buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12 + 18);
19728 /* write gzip header */
19731 c = (unsigned char *)p->b->ptr;
19734 @@ -190,24 +221,24 @@
19735 c[7] = (mtime >> 24) & 0xff;
19736 c[8] = 0x00; /* extra flags */
19737 c[9] = 0x03; /* UNIX */
19741 z.next_out = (unsigned char *)p->b->ptr + p->b->used;
19742 z.avail_out = p->b->size - p->b->used - 8;
19746 if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19753 p->b->used += z.total_out;
19756 crc = generate_crc32c(start, st_size);
19759 c = (unsigned char *)p->b->ptr + p->b->used;
19762 c[0] = (crc >> 0) & 0xff;
19763 c[1] = (crc >> 8) & 0xff;
19764 c[2] = (crc >> 16) & 0xff;
19765 @@ -221,51 +252,51 @@
19766 if (Z_OK != deflateEnd(&z)) {
19774 static int deflate_file_to_buffer_deflate(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19785 - if (Z_OK != deflateInit2(&z,
19787 + if (Z_OK != deflateInit2(&z,
19788 Z_DEFAULT_COMPRESSION,
19791 -MAX_WBITS, /* supress zlib-header */
19793 Z_DEFAULT_STRATEGY)) {
19799 z.avail_in = st_size;
19803 buffer_prepare_copy(p->b, (z.avail_in * 1.1) + 12);
19806 z.next_out = (unsigned char *)p->b->ptr;
19807 z.avail_out = p->b->size;
19811 if (Z_STREAM_END != deflate(&z, Z_FINISH)) {
19818 p->b->used += z.total_out;
19821 if (Z_OK != deflateEnd(&z)) {
19829 @@ -274,48 +305,48 @@
19831 static int deflate_file_to_buffer_bzip2(server *srv, connection *con, plugin_data *p, unsigned char *start, off_t st_size) {
19842 - if (BZ_OK != BZ2_bzCompressInit(&bz,
19844 + if (BZ_OK != BZ2_bzCompressInit(&bz,
19845 9, /* blocksize = 900k */
19847 0)) { /* workFactor: default */
19852 bz.next_in = (char *)start;
19853 bz.avail_in = st_size;
19854 bz.total_in_lo32 = 0;
19855 bz.total_in_hi32 = 0;
19858 buffer_prepare_copy(p->b, (bz.avail_in * 1.1) + 12);
19861 bz.next_out = p->b->ptr;
19862 bz.avail_out = p->b->size;
19863 bz.total_out_lo32 = 0;
19864 bz.total_out_hi32 = 0;
19867 if (BZ_STREAM_END != BZ2_bzCompress(&bz, BZ_FINISH)) {
19868 BZ2_bzCompressEnd(&bz);
19873 /* file is too large for now */
19874 if (bz.total_out_hi32) return -1;
19878 p->b->used = bz.total_out_lo32;
19881 if (BZ_OK != BZ2_bzCompressEnd(&bz)) {
19889 @@ -326,47 +357,50 @@
19891 const char *filename = fn->ptr;
19894 + stat_cache_entry *compressed_sce = NULL;
19896 + if (buffer_is_empty(p->conf.compress_cache_dir)) return -1;
19899 if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
19901 - /* don't mmap files > 128Mb
19904 + /* don't mmap files > 128Mb
19906 * we could use a sliding window, but currently there is no need for it
19910 if (sce->st.st_size > 128 * 1024 * 1024) return -1;
19913 buffer_reset(p->ofn);
19914 buffer_copy_string_buffer(p->ofn, p->conf.compress_cache_dir);
19915 - BUFFER_APPEND_SLASH(p->ofn);
19917 + PATHNAME_APPEND_SLASH(p->ofn);
19919 if (0 == strncmp(con->physical.path->ptr, con->physical.doc_root->ptr, con->physical.doc_root->used-1)) {
19920 size_t offset = p->ofn->used - 1;
19921 char *dir, *nextdir;
19924 buffer_append_string(p->ofn, con->physical.path->ptr + con->physical.doc_root->used - 1);
19927 buffer_copy_string_buffer(p->b, p->ofn);
19931 for (dir = p->b->ptr + offset; NULL != (nextdir = strchr(dir, '/')); dir = nextdir + 1) {
19935 if (-1 == mkdir(p->b->ptr, 0700)) {
19936 if (errno != EEXIST) {
19937 log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cache-directory", p->b, "failed", strerror(errno));
19948 buffer_append_string_buffer(p->ofn, con->uri.path);
19953 case HTTP_ACCEPT_ENCODING_GZIP:
19954 buffer_append_string(p->ofn, "-gzip-");
19955 @@ -381,55 +415,64 @@
19956 log_error_write(srv, __FILE__, __LINE__, "sd", "unknown compression type", type);
19961 buffer_append_string_buffer(p->ofn, sce->etag);
19965 + if (HANDLER_ERROR != stat_cache_get_entry(srv, con, p->ofn, &compressed_sce)) {
19966 + /* file exists */
19968 + http_chunk_append_file(srv, con, p->ofn, 0, compressed_sce->st.st_size);
19969 + con->file_finished = 1;
19974 if (-1 == (ofd = open(p->ofn->ptr, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0600))) {
19975 if (errno == EEXIST) {
19976 /* cache-entry exists */
19978 - log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache hit");
19980 - buffer_copy_string_buffer(con->physical.path, p->ofn);
19986 - log_error_write(srv, __FILE__, __LINE__, "sbss", "creating cachefile", p->ofn, "failed", strerror(errno));
19989 + log_error_write(srv, __FILE__, __LINE__, "sbss",
19990 + "creating cachefile", p->ofn,
19991 + "failed", strerror(errno));
19996 - log_error_write(srv, __FILE__, __LINE__, "bs", p->ofn, "compress-cache miss");
19999 if (-1 == (ifd = open(filename, O_RDONLY | O_BINARY))) {
20000 - log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20002 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20003 + "opening plain-file", fn,
20004 + "failed", strerror(errno));
20015 if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20016 - log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20018 + log_error_write(srv, __FILE__, __LINE__, "sbss",
20020 + "failed", strerror(errno));
20030 - case HTTP_ACCEPT_ENCODING_GZIP:
20031 + case HTTP_ACCEPT_ENCODING_GZIP:
20032 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20034 - case HTTP_ACCEPT_ENCODING_DEFLATE:
20035 + case HTTP_ACCEPT_ENCODING_DEFLATE:
20036 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20040 - case HTTP_ACCEPT_ENCODING_BZIP2:
20041 + case HTTP_ACCEPT_ENCODING_BZIP2:
20042 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20045 @@ -437,26 +480,27 @@
20051 if (-1 == (r = write(ofd, p->b->ptr, p->b->used))) {
20052 - munmap(start, sce->st.st_size);
20053 + munmap(start, sce->st.st_size);
20060 if ((size_t)r != p->b->used) {
20066 munmap(start, sce->st.st_size);
20071 if (ret != 0) return -1;
20073 - buffer_copy_string_buffer(con->physical.path, p->ofn);
20076 + http_chunk_append_file(srv, con, p->ofn, 0, r);
20077 + con->file_finished = 1;
20082 @@ -465,43 +509,44 @@
20089 if ((off_t)(sce->st.st_size * 1.1) < sce->st.st_size) return -1;
20092 /* don't mmap files > 128M
20095 * we could use a sliding window, but currently there is no need for it
20099 if (sce->st.st_size > 128 * 1024 * 1024) return -1;
20103 if (-1 == (ifd = open(fn->ptr, O_RDONLY | O_BINARY))) {
20104 log_error_write(srv, __FILE__, __LINE__, "sbss", "opening plain-file", fn, "failed", strerror(errno));
20111 - if (MAP_FAILED == (start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
20113 + start = mmap(NULL, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0);
20117 + if (MAP_FAILED == start) {
20118 log_error_write(srv, __FILE__, __LINE__, "sbss", "mmaping", fn, "failed", strerror(errno));
20128 - case HTTP_ACCEPT_ENCODING_GZIP:
20129 + case HTTP_ACCEPT_ENCODING_GZIP:
20130 ret = deflate_file_to_buffer_gzip(srv, con, p, start, sce->st.st_size, sce->st.st_mtime);
20132 - case HTTP_ACCEPT_ENCODING_DEFLATE:
20133 + case HTTP_ACCEPT_ENCODING_DEFLATE:
20134 ret = deflate_file_to_buffer_deflate(srv, con, p, start, sce->st.st_size);
20138 - case HTTP_ACCEPT_ENCODING_BZIP2:
20139 + case HTTP_ACCEPT_ENCODING_BZIP2:
20140 ret = deflate_file_to_buffer_bzip2(srv, con, p, start, sce->st.st_size);
20143 @@ -509,69 +554,64 @@
20149 munmap(start, sce->st.st_size);
20153 if (ret != 0) return -1;
20156 chunkqueue_reset(con->write_queue);
20157 b = chunkqueue_get_append_buffer(con->write_queue);
20158 buffer_copy_memory(b, p->b->ptr, p->b->used + 1);
20161 buffer_reset(con->physical.path);
20164 con->file_finished = 1;
20165 con->file_started = 1;
20172 -#define PATCH(x) \
20173 - p->conf.x = s->x;
20174 static int mod_compress_patch_connection(server *srv, connection *con, plugin_data *p) {
20176 plugin_config *s = p->config_storage[0];
20178 - PATCH(compress_cache_dir);
20180 - PATCH(compress_max_filesize);
20182 + PATCH_OPTION(compress_cache_dir);
20183 + PATCH_OPTION(compress);
20184 + PATCH_OPTION(compress_max_filesize);
20186 /* skip the first, the global context */
20187 for (i = 1; i < srv->config_context->used; i++) {
20188 data_config *dc = (data_config *)srv->config_context->data[i];
20189 s = p->config_storage[i];
20192 /* condition didn't match */
20193 if (!config_check_cond(srv, con, dc)) continue;
20197 for (j = 0; j < dc->value->used; j++) {
20198 data_unset *du = dc->value->data[j];
20201 if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.cache-dir"))) {
20202 - PATCH(compress_cache_dir);
20203 + PATCH_OPTION(compress_cache_dir);
20204 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.filetype"))) {
20206 + PATCH_OPTION(compress);
20207 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("compress.max-filesize"))) {
20208 - PATCH(compress_max_filesize);
20209 + PATCH_OPTION(compress_max_filesize);
20219 PHYSICALPATH_FUNC(mod_compress_physical) {
20220 plugin_data *p = p_d;
20223 stat_cache_entry *sce = NULL;
20226 /* only GET and POST can get compressed */
20227 - if (con->request.http_method != HTTP_METHOD_GET &&
20228 + if (con->request.http_method != HTTP_METHOD_GET &&
20229 con->request.http_method != HTTP_METHOD_POST) {
20230 return HANDLER_GO_ON;
20232 @@ -579,46 +619,49 @@
20233 if (buffer_is_empty(con->physical.path)) {
20234 return HANDLER_GO_ON;
20238 mod_compress_patch_connection(srv, con, p);
20241 max_fsize = p->conf.compress_max_filesize;
20243 stat_cache_get_entry(srv, con, con->physical.path, &sce);
20245 /* don't compress files that are too large as we need to much time to handle them */
20246 if (max_fsize && (sce->st.st_size >> 10) > max_fsize) return HANDLER_GO_ON;
20249 + /* compressing the file might lead to larger files instead */
20250 + if (sce->st.st_size < 128) return HANDLER_GO_ON;
20252 /* check if mimetype is in compress-config */
20253 for (m = 0; m < p->conf.compress->used; m++) {
20254 data_string *compress_ds = (data_string *)p->conf.compress->data[m];
20257 if (!compress_ds) {
20258 log_error_write(srv, __FILE__, __LINE__, "sbb", "evil", con->physical.path, con->uri.path);
20261 return HANDLER_GO_ON;
20265 if (buffer_is_equal(compress_ds->value, sce->content_type)) {
20266 /* mimetype found */
20270 /* the response might change according to Accept-Encoding */
20271 response_header_insert(srv, con, CONST_STR_LEN("Vary"), CONST_STR_LEN("Accept-Encoding"));
20274 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Accept-Encoding"))) {
20275 int accept_encoding = 0;
20276 char *value = ds->value->ptr;
20277 int srv_encodings = 0;
20278 int matched_encodings = 0;
20281 /* get client side support encodings */
20282 if (NULL != strstr(value, "gzip")) accept_encoding |= HTTP_ACCEPT_ENCODING_GZIP;
20283 if (NULL != strstr(value, "deflate")) accept_encoding |= HTTP_ACCEPT_ENCODING_DEFLATE;
20284 if (NULL != strstr(value, "compress")) accept_encoding |= HTTP_ACCEPT_ENCODING_COMPRESS;
20285 if (NULL != strstr(value, "bzip2")) accept_encoding |= HTTP_ACCEPT_ENCODING_BZIP2;
20286 if (NULL != strstr(value, "identity")) accept_encoding |= HTTP_ACCEPT_ENCODING_IDENTITY;
20289 /* get server side supported ones */
20291 srv_encodings |= HTTP_ACCEPT_ENCODING_BZIP2;
20292 @@ -627,18 +670,31 @@
20293 srv_encodings |= HTTP_ACCEPT_ENCODING_GZIP;
20294 srv_encodings |= HTTP_ACCEPT_ENCODING_DEFLATE;
20298 /* find matching entries */
20299 matched_encodings = accept_encoding & srv_encodings;
20302 if (matched_encodings) {
20303 const char *dflt_gzip = "gzip";
20304 const char *dflt_deflate = "deflate";
20305 const char *dflt_bzip2 = "bzip2";
20308 const char *compression_name = NULL;
20309 int compression_type = 0;
20313 + mtime = strftime_cache_get(srv, sce->st.st_mtime);
20314 + etag_mutate(con->physical.etag, sce->etag);
20316 + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20317 + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20319 + /* perhaps we don't even have to compress the file as the browser still has the
20320 + * current version */
20321 + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20322 + return HANDLER_FINISHED;
20325 /* select best matching encoding */
20326 if (matched_encodings & HTTP_ACCEPT_ENCODING_BZIP2) {
20327 compression_type = HTTP_ACCEPT_ENCODING_BZIP2;
20328 @@ -650,31 +706,21 @@
20329 compression_type = HTTP_ACCEPT_ENCODING_DEFLATE;
20330 compression_name = dflt_deflate;
20334 - if (p->conf.compress_cache_dir->used) {
20335 - if (0 == deflate_file_to_file(srv, con, p,
20336 - con->physical.path, sce, compression_type)) {
20339 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20341 - mtime = strftime_cache_get(srv, sce->st.st_mtime);
20342 - response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20344 - etag_mutate(con->physical.etag, sce->etag);
20345 - response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20347 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20349 - return HANDLER_GO_ON;
20351 - } else if (0 == deflate_file_to_buffer(srv, con, p,
20352 - con->physical.path, sce, compression_type)) {
20354 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Encoding"), compression_name, strlen(compression_name));
20355 - response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
20358 + /* deflate it to file (cached) or to memory */
20359 + if (0 == deflate_file_to_file(srv, con, p,
20360 + con->physical.path, sce, compression_type) ||
20361 + 0 == deflate_file_to_buffer(srv, con, p,
20362 + con->physical.path, sce, compression_type)) {
20364 + response_header_overwrite(srv, con,
20365 + CONST_STR_LEN("Content-Encoding"),
20366 + compression_name, strlen(compression_name));
20368 + response_header_overwrite(srv, con,
20369 + CONST_STR_LEN("Content-Type"),
20370 + CONST_BUF_LEN(sce->content_type));
20372 return HANDLER_FINISHED;
20375 @@ -682,20 +728,20 @@
20381 return HANDLER_GO_ON;
20384 int mod_compress_plugin_init(plugin *p) {
20385 p->version = LIGHTTPD_VERSION_ID;
20386 p->name = buffer_init_string("compress");
20389 p->init = mod_compress_init;
20390 p->set_defaults = mod_compress_setdefaults;
20391 p->handle_subrequest_start = mod_compress_physical;
20392 p->cleanup = mod_compress_free;
20400 --- ../lighttpd-1.4.11/src/mod_dirlisting.c 2006-01-13 00:00:45.000000000 +0200
20401 +++ lighttpd-1.4.12/src/mod_dirlisting.c 2006-07-16 00:26:04.000000000 +0300
20404 #include <stdlib.h>
20405 #include <string.h>
20406 -#include <dirent.h>
20407 #include <assert.h>
20410 -#include <unistd.h>
20415 #include "response.h"
20416 #include "stat_cache.h"
20417 #include "stream.h"
20420 +#include "sys-strings.h"
20423 * this is a dirlisting for a lighttpd plugin
20424 @@ -27,10 +28,13 @@
20425 #include <sys/syslimits.h>
20428 -#ifdef HAVE_ATTR_ATTRIBUTES_H
20430 #include <attr/attributes.h>
20433 +#include "sys-files.h"
20434 +#include "sys-strings.h"
20436 /* plugin config for all request/connections */
20440 unsigned short hide_readme_file;
20441 unsigned short show_header;
20442 unsigned short hide_header_file;
20445 excludes_buffer *excludes;
20447 buffer *external_css;
20448 @@ -63,13 +67,14 @@
20455 buffer *content_charset;
20459 plugin_config **config_storage;
20461 - plugin_config conf;
20463 + plugin_config conf;
20466 excludes_buffer *excludes_buffer_init(void) {
20467 @@ -146,44 +151,46 @@
20468 /* init the plugin data */
20469 INIT_FUNC(mod_dirlisting_init) {
20473 p = calloc(1, sizeof(*p));
20475 p->tmp_buf = buffer_init();
20476 p->content_charset = buffer_init();
20478 + p->path = buffer_init();
20483 /* detroy the plugin data */
20484 FREE_FUNC(mod_dirlisting_free) {
20485 plugin_data *p = p_d;
20490 if (!p) return HANDLER_GO_ON;
20493 if (p->config_storage) {
20495 for (i = 0; i < srv->config_context->used; i++) {
20496 plugin_config *s = p->config_storage[i];
20502 excludes_buffer_free(s->excludes);
20503 buffer_free(s->external_css);
20504 buffer_free(s->encoding);
20509 free(p->config_storage);
20513 buffer_free(p->tmp_buf);
20514 + buffer_free(p->path);
20515 buffer_free(p->content_charset);
20521 return HANDLER_GO_ON;
20524 @@ -215,10 +222,10 @@
20525 if (0 != excludes_buffer_append(s->excludes,
20526 ((data_string *)(da->value->data[j]))->value)) {
20528 - log_error_write(srv, __FILE__, __LINE__, "sb",
20529 + log_error_write(srv, __FILE__, __LINE__, "sb",
20530 "pcre-compile failed for", ((data_string *)(da->value->data[j]))->value);
20532 - log_error_write(srv, __FILE__, __LINE__, "s",
20533 + log_error_write(srv, __FILE__, __LINE__, "s",
20534 "pcre support is missing, please install libpcre and the headers");
20537 @@ -233,8 +240,8 @@
20538 SETDEFAULTS_FUNC(mod_dirlisting_set_defaults) {
20539 plugin_data *p = p_d;
20542 - config_values_t cv[] = {
20544 + config_values_t cv[] = {
20545 { "dir-listing.exclude", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
20546 { "dir-listing.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
20547 { "dir-listing.hide-dotfiles", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
20548 @@ -245,18 +252,18 @@
20549 { "dir-listing.show-header", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
20550 { "dir-listing.hide-header-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
20551 { "server.dir-listing", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
20554 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
20558 if (!p) return HANDLER_ERROR;
20561 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
20564 for (i = 0; i < srv->config_context->used; i++) {
20569 s = calloc(1, sizeof(plugin_config));
20570 s->excludes = excludes_buffer_init();
20571 s->dir_listing = 0;
20572 @@ -267,7 +274,7 @@
20573 s->show_header = 0;
20574 s->hide_header_file = 0;
20575 s->encoding = buffer_init();
20578 cv[0].destination = s->excludes;
20579 cv[1].destination = &(s->dir_listing);
20580 cv[2].destination = &(s->hide_dot_files);
20581 @@ -292,60 +299,57 @@
20582 return HANDLER_GO_ON;
20585 -#define PATCH(x) \
20586 - p->conf.x = s->x;
20587 static int mod_dirlisting_patch_connection(server *srv, connection *con, plugin_data *p) {
20589 plugin_config *s = p->config_storage[0];
20591 - PATCH(dir_listing);
20592 - PATCH(external_css);
20593 - PATCH(hide_dot_files);
20595 - PATCH(show_readme);
20596 - PATCH(hide_readme_file);
20597 - PATCH(show_header);
20598 - PATCH(hide_header_file);
20601 + PATCH_OPTION(dir_listing);
20602 + PATCH_OPTION(external_css);
20603 + PATCH_OPTION(hide_dot_files);
20604 + PATCH_OPTION(encoding);
20605 + PATCH_OPTION(show_readme);
20606 + PATCH_OPTION(hide_readme_file);
20607 + PATCH_OPTION(show_header);
20608 + PATCH_OPTION(hide_header_file);
20609 + PATCH_OPTION(excludes);
20611 /* skip the first, the global context */
20612 for (i = 1; i < srv->config_context->used; i++) {
20613 data_config *dc = (data_config *)srv->config_context->data[i];
20614 s = p->config_storage[i];
20617 /* condition didn't match */
20618 if (!config_check_cond(srv, con, dc)) continue;
20622 for (j = 0; j < dc->value->used; j++) {
20623 data_unset *du = dc->value->data[j];
20626 if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.activate")) ||
20627 buffer_is_equal_string(du->key, CONST_STR_LEN("server.dir-listing"))) {
20628 - PATCH(dir_listing);
20629 + PATCH_OPTION(dir_listing);
20630 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-dotfiles"))) {
20631 - PATCH(hide_dot_files);
20632 + PATCH_OPTION(hide_dot_files);
20633 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.external-css"))) {
20634 - PATCH(external_css);
20635 + PATCH_OPTION(external_css);
20636 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.encoding"))) {
20638 + PATCH_OPTION(encoding);
20639 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-readme"))) {
20640 - PATCH(show_readme);
20641 + PATCH_OPTION(show_readme);
20642 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-readme-file"))) {
20643 - PATCH(hide_readme_file);
20644 + PATCH_OPTION(hide_readme_file);
20645 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.show-header"))) {
20646 - PATCH(show_header);
20647 + PATCH_OPTION(show_header);
20648 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.hide-header-file"))) {
20649 - PATCH(hide_header_file);
20650 + PATCH_OPTION(hide_header_file);
20651 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("dir-listing.excludes"))) {
20653 + PATCH_OPTION(excludes);
20665 @@ -432,7 +436,7 @@
20667 static void http_list_directory_header(server *srv, connection *con, plugin_data *p, buffer *out) {
20671 BUFFER_APPEND_STRING_CONST(out,
20672 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
20673 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\n"
20674 @@ -492,11 +496,11 @@
20675 if (p->conf.show_header) {
20677 /* if we have a HEADER file, display it in <pre class="header"></pre> */
20680 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20681 - BUFFER_APPEND_SLASH(p->tmp_buf);
20682 + PATHNAME_APPEND_SLASH(p->tmp_buf);
20683 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "HEADER.txt");
20686 if (-1 != stream_open(&s, p->tmp_buf)) {
20687 BUFFER_APPEND_STRING_CONST(out, "<pre class=\"header\">");
20688 buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20689 @@ -531,21 +535,21 @@
20691 static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
20695 BUFFER_APPEND_STRING_CONST(out,
20702 if (p->conf.show_readme) {
20704 /* if we have a README file, display it in <pre class="readme"></pre> */
20707 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
20708 - BUFFER_APPEND_SLASH(p->tmp_buf);
20709 + PATHNAME_APPEND_SLASH(p->tmp_buf);
20710 BUFFER_APPEND_STRING_CONST(p->tmp_buf, "README.txt");
20713 if (-1 != stream_open(&s, p->tmp_buf)) {
20714 BUFFER_APPEND_STRING_CONST(out, "<pre class=\"readme\">");
20715 buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
20716 @@ -553,7 +557,7 @@
20722 BUFFER_APPEND_STRING_CONST(out,
20723 "<div class=\"foot\">"
20725 @@ -576,7 +580,6 @@
20727 struct dirent *dent;
20729 - char *path, *path_file;
20731 int hide_dotfiles = p->conf.hide_dot_files;
20732 dirls_list_t dirs, files, *list;
20733 @@ -586,6 +589,7 @@
20735 const char *content_type;
20741 @@ -594,10 +598,10 @@
20745 - if (dir->used == 0) return -1;
20747 - i = dir->used - 1;
20748 + /* empty pathname, never ... */
20749 + if (buffer_is_empty(dir)) return -1;
20751 + /* max-length for the opendir */
20752 #ifdef HAVE_PATHCONF
20753 if (-1 == (name_max = pathconf(dir->ptr, _PC_NAME_MAX))) {
20755 @@ -606,22 +610,24 @@
20756 name_max = 256; /* stupid default */
20759 -#elif defined __WIN32
20760 +#elif defined _WIN32
20761 name_max = FILENAME_MAX;
20763 name_max = NAME_MAX;
20766 - path = malloc(dir->used + name_max);
20768 - strcpy(path, dir->ptr);
20769 - path_file = path + i;
20771 - if (NULL == (dp = opendir(path))) {
20772 - log_error_write(srv, __FILE__, __LINE__, "sbs",
20773 + buffer_copy_string_buffer(p->path, dir);
20774 + PATHNAME_APPEND_SLASH(p->path);
20777 + /* append *.* to the path */
20778 + buffer_append_string(path, "*.*");
20781 + if (NULL == (dp = opendir(p->path->ptr))) {
20782 + log_error_write(srv, __FILE__, __LINE__, "sbs",
20783 "opendir failed:", dir, strerror(errno));
20789 @@ -633,7 +639,7 @@
20791 files.size = DIRLIST_BLOB_SIZE;
20795 while ((dent = readdir(dp)) != NULL) {
20796 unsigned short exclude_match = 0;
20798 @@ -686,15 +692,21 @@
20801 i = strlen(dent->d_name);
20804 /* NOTE: the manual says, d_name is never more than NAME_MAX
20805 * so this should actually not be a buffer-overflow-risk
20807 if (i > (size_t)name_max) continue;
20809 - memcpy(path_file, dent->d_name, i + 1);
20810 - if (stat(path, &st) != 0)
20812 + /* build the dirname */
20813 + buffer_copy_string_buffer(p->path, dir);
20814 + PATHNAME_APPEND_SLASH(p->path);
20815 + buffer_append_string(p->path, dent->d_name);
20817 + if (stat(p->path->ptr, &st) != 0) {
20818 + fprintf(stderr, "%s.%d: %s, %s\r\n", __FILE__, __LINE__, p->path->ptr, strerror(errno));
20823 if (S_ISDIR(st.st_mode))
20824 @@ -740,7 +752,7 @@
20826 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", localtime(&(tmp->mtime)));
20830 BUFFER_APPEND_STRING_CONST(out, "<tr><td class=\"n\"><a href=\"");
20831 buffer_append_string_encoded(out, DIRLIST_ENT_NAME(tmp), tmp->namelen, ENCODING_REL_URI_PART);
20832 BUFFER_APPEND_STRING_CONST(out, "/\">");
20833 @@ -757,18 +769,22 @@
20834 tmp = files.ent[i];
20836 content_type = NULL;
20840 if (con->conf.use_xattr) {
20841 - memcpy(path_file, DIRLIST_ENT_NAME(tmp), tmp->namelen + 1);
20842 + /* build the dirname */
20843 + buffer_copy_string_buffer(p->path, dir);
20844 + PATHNAME_APPEND_SLASH(p->path);
20845 + buffer_append_string_len(p->path, DIRLIST_ENT_NAME(tmp), tmp->namelen);
20847 attrlen = sizeof(attrval) - 1;
20848 - if (attr_get(path, "Content-Type", attrval, &attrlen, 0) == 0) {
20849 + if (attr_get(p->path->ptr, "Content-Type", attrval, &attrlen, 0) == 0) {
20850 attrval[attrlen] = '\0';
20851 content_type = attrval;
20857 if (content_type == NULL) {
20858 content_type = "application/octet-stream";
20859 for (k = 0; k < con->conf.mimetypes->used; k++) {
20860 @@ -788,7 +804,7 @@
20866 #ifdef HAVE_LOCALTIME_R
20867 localtime_r(&(tmp->mtime), &tm);
20868 strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm);
20869 @@ -814,7 +830,6 @@
20875 http_list_directory_footer(srv, con, p, out);
20877 @@ -837,36 +852,55 @@
20878 URIHANDLER_FUNC(mod_dirlisting_subrequest) {
20879 plugin_data *p = p_d;
20880 stat_cache_entry *sce = NULL;
20884 - if (con->physical.path->used == 0) return HANDLER_GO_ON;
20885 - if (con->uri.path->used == 0) return HANDLER_GO_ON;
20889 + if (con->uri.path->used < 2) return HANDLER_GO_ON;
20890 if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
20892 + if (con->physical.path->used == 0) return HANDLER_GO_ON;
20894 mod_dirlisting_patch_connection(srv, con, p);
20896 if (!p->conf.dir_listing) return HANDLER_GO_ON;
20899 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20900 + /* just a second ago the file was still there */
20901 + return HANDLER_GO_ON;
20904 + if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20906 if (con->conf.log_request_handling) {
20907 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Dir-Listing");
20908 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
20911 - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
20912 - fprintf(stderr, "%s.%d: %s\n", __FILE__, __LINE__, con->physical.path->ptr);
20915 + /* perhaps this a cachable request
20916 + * - we use the etag of the directory
20919 + etag_mutate(con->physical.etag, sce->etag);
20920 + response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
20922 + /* prepare header */
20923 + if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
20924 + mtime = strftime_cache_get(srv, sce->st.st_mtime);
20925 + response_header_overwrite(srv, con, CONST_STR_LEN("Last-Modified"), CONST_BUF_LEN(mtime));
20927 + mtime = ds->value;
20930 - if (!S_ISDIR(sce->st.st_mode)) return HANDLER_GO_ON;
20933 + if (HANDLER_FINISHED == http_response_handle_cachable(srv, con, mtime)) {
20934 + return HANDLER_FINISHED;
20937 if (http_list_directory(srv, con, p, con->physical.path)) {
20938 /* dirlisting failed */
20939 con->http_status = 403;
20943 buffer_reset(con->physical.path);
20947 return HANDLER_FINISHED;
20949 @@ -876,13 +910,13 @@
20950 int mod_dirlisting_plugin_init(plugin *p) {
20951 p->version = LIGHTTPD_VERSION_ID;
20952 p->name = buffer_init_string("dirlisting");
20955 p->init = mod_dirlisting_init;
20956 p->handle_subrequest_start = mod_dirlisting_subrequest;
20957 p->set_defaults = mod_dirlisting_set_defaults;
20958 p->cleanup = mod_dirlisting_free;
20966 --- ../lighttpd-1.4.11/src/mod_evasive.c 2006-01-04 15:24:51.000000000 +0200
20967 +++ lighttpd-1.4.12/src/mod_evasive.c 2006-07-16 00:26:04.000000000 +0300
20968 @@ -31,100 +31,97 @@
20974 plugin_config **config_storage;
20976 - plugin_config conf;
20978 + plugin_config conf;
20981 INIT_FUNC(mod_evasive_init) {
20985 p = calloc(1, sizeof(*p));
20991 FREE_FUNC(mod_evasive_free) {
20992 plugin_data *p = p_d;
20997 if (!p) return HANDLER_GO_ON;
21000 if (p->config_storage) {
21002 for (i = 0; i < srv->config_context->used; i++) {
21003 plugin_config *s = p->config_storage[i];
21008 free(p->config_storage);
21015 return HANDLER_GO_ON;
21018 SETDEFAULTS_FUNC(mod_evasive_set_defaults) {
21019 plugin_data *p = p_d;
21022 - config_values_t cv[] = {
21024 + config_values_t cv[] = {
21025 { "evasive.max-conns-per-ip", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
21026 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21030 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21033 for (i = 0; i < srv->config_context->used; i++) {
21037 s = calloc(1, sizeof(plugin_config));
21041 cv[0].destination = &(s->max_conns);
21044 p->config_storage[i] = s;
21047 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21048 return HANDLER_ERROR;
21053 return HANDLER_GO_ON;
21056 -#define PATCH(x) \
21057 - p->conf.x = s->x;
21058 static int mod_evasive_patch_connection(server *srv, connection *con, plugin_data *p) {
21060 plugin_config *s = p->config_storage[0];
21062 - PATCH(max_conns);
21064 + PATCH_OPTION(max_conns);
21066 /* skip the first, the global context */
21067 for (i = 1; i < srv->config_context->used; i++) {
21068 data_config *dc = (data_config *)srv->config_context->data[i];
21069 s = p->config_storage[i];
21072 /* condition didn't match */
21073 if (!config_check_cond(srv, con, dc)) continue;
21077 for (j = 0; j < dc->value->used; j++) {
21078 data_unset *du = dc->value->data[j];
21081 if (buffer_is_equal_string(du->key, CONST_STR_LEN("evasive.max-conns-per-ip"))) {
21082 - PATCH(max_conns);
21083 + PATCH_OPTION(max_conns);
21093 URIHANDLER_FUNC(mod_evasive_uri_handler) {
21094 plugin_data *p = p_d;
21095 @@ -132,10 +129,10 @@
21098 if (con->uri.path->used == 0) return HANDLER_GO_ON;
21101 mod_evasive_patch_connection(srv, con, p);
21103 - /* no limit set, nothing to block */
21105 + /* no limit set, nothing to block */
21106 if (p->conf.max_conns == 0) return HANDLER_GO_ON;
21108 for (j = 0; j < srv->conns->used; j++) {
21109 @@ -147,7 +144,7 @@
21110 if (c->dst_addr.ipv4.sin_addr.s_addr == con->dst_addr.ipv4.sin_addr.s_addr &&
21111 c->state > CON_STATE_REQUEST_END) {
21115 if (conns_by_ip > p->conf.max_conns) {
21116 log_error_write(srv, __FILE__, __LINE__, "ss",
21117 inet_ntop_cache_get_ip(srv, &(con->dst_addr)),
21118 @@ -158,7 +155,7 @@
21124 return HANDLER_GO_ON;
21127 @@ -166,13 +163,13 @@
21128 int mod_evasive_plugin_init(plugin *p) {
21129 p->version = LIGHTTPD_VERSION_ID;
21130 p->name = buffer_init_string("evasive");
21133 p->init = mod_evasive_init;
21134 p->set_defaults = mod_evasive_set_defaults;
21135 p->handle_uri_clean = mod_evasive_uri_handler;
21136 p->cleanup = mod_evasive_free;
21144 --- ../lighttpd-1.4.11/src/mod_evhost.c 2005-08-17 10:42:03.000000000 +0300
21145 +++ lighttpd-1.4.12/src/mod_evhost.c 2006-07-16 00:26:03.000000000 +0300
21147 #include "response.h"
21148 #include "stat_cache.h"
21150 +#include "sys-files.h"
21153 /* unparsed pieces */
21154 buffer *path_pieces_raw;
21157 /* pieces for path creation */
21159 buffer **path_pieces;
21160 @@ -21,14 +23,14 @@
21163 plugin_config **config_storage;
21164 - plugin_config conf;
21165 + plugin_config conf;
21168 INIT_FUNC(mod_evhost_init) {
21172 p = calloc(1, sizeof(*p));
21175 p->tmp_buf = buffer_init();
21178 @@ -36,34 +38,34 @@
21180 FREE_FUNC(mod_evhost_free) {
21181 plugin_data *p = p_d;
21186 if (!p) return HANDLER_GO_ON;
21189 if (p->config_storage) {
21191 for (i = 0; i < srv->config_context->used; i++) {
21192 plugin_config *s = p->config_storage[i];
21197 if(s->path_pieces) {
21199 for (j = 0; j < s->len; j++) {
21200 buffer_free(s->path_pieces[j]);
21204 free(s->path_pieces);
21208 buffer_free(s->path_pieces_raw);
21213 free(p->config_storage);
21217 buffer_free(p->tmp_buf);
21220 @@ -73,30 +75,30 @@
21222 static void mod_evhost_parse_pattern(plugin_config *s) {
21223 char *ptr = s->path_pieces_raw->ptr,*pos;
21226 s->path_pieces = NULL;
21229 for(pos=ptr;*ptr;ptr++) {
21231 s->path_pieces = realloc(s->path_pieces,(s->len+2) * sizeof(*s->path_pieces));
21232 s->path_pieces[s->len] = buffer_init();
21233 s->path_pieces[s->len+1] = buffer_init();
21236 buffer_copy_string_len(s->path_pieces[s->len],pos,ptr-pos);
21240 buffer_copy_string_len(s->path_pieces[s->len+1],ptr++,2);
21249 s->path_pieces = realloc(s->path_pieces,(s->len+1) * sizeof(*s->path_pieces));
21250 s->path_pieces[s->len] = buffer_init();
21253 buffer_append_memory(s->path_pieces[s->len],pos,ptr-pos);
21259 @@ -104,9 +106,9 @@
21260 SETDEFAULTS_FUNC(mod_evhost_set_defaults) {
21261 plugin_data *p = p_d;
21269 * # define a pattern for the host url finding
21271 @@ -117,39 +119,39 @@
21272 * # %4 => subdomain 2 name
21274 * evhost.path-pattern = "/home/ckruse/dev/www/%3/htdocs/"
21279 - config_values_t cv[] = {
21281 + config_values_t cv[] = {
21282 { "evhost.path-pattern", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
21283 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21287 if (!p) return HANDLER_ERROR;
21290 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21293 for (i = 0; i < srv->config_context->used; i++) {
21297 s = calloc(1, sizeof(plugin_config));
21298 s->path_pieces_raw = buffer_init();
21299 s->path_pieces = NULL;
21303 cv[0].destination = s->path_pieces_raw;
21306 p->config_storage[i] = s;
21309 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21310 return HANDLER_ERROR;
21314 if (s->path_pieces_raw->used != 0) {
21315 mod_evhost_parse_pattern(s);
21320 return HANDLER_GO_ON;
21323 @@ -158,7 +160,7 @@
21324 * - %0 - full hostname (authority w/o port)
21326 * - %2 - domain.tld
21331 static int mod_evhost_parse_host(connection *con,array *host) {
21332 @@ -168,7 +170,7 @@
21338 /* first, find the domain + tld */
21339 for(;ptr > con->uri.authority->ptr;ptr--) {
21341 @@ -179,18 +181,18 @@
21347 ds = data_string_init();
21348 buffer_copy_string(ds->key,"%0");
21351 /* if we stopped at a dot, skip the dot */
21352 if (*ptr == '.') ptr++;
21353 buffer_copy_string_len(ds->value, ptr, colon-ptr);
21356 array_insert_unique(host,(data_unset *)ds);
21359 /* if the : is not the start of the authority, go on parsing the hostname */
21362 if (colon != con->uri.authority->ptr) {
21363 for(ptr = colon - 1, i = 1; ptr > con->uri.authority->ptr; ptr--) {
21365 @@ -200,59 +202,55 @@
21366 buffer_copy_string(ds->key,"%");
21367 buffer_append_long(ds->key, i++);
21368 buffer_copy_string_len(ds->value,ptr+1,colon-ptr-1);
21371 array_insert_unique(host,(data_unset *)ds);
21378 /* if the . is not the first charactor of the hostname */
21379 if (colon != ptr) {
21380 ds = data_string_init();
21381 buffer_copy_string(ds->key,"%");
21382 buffer_append_long(ds->key, i++);
21383 buffer_copy_string_len(ds->value,ptr,colon-ptr);
21386 array_insert_unique(host,(data_unset *)ds);
21394 -#define PATCH(x) \
21395 - p->conf.x = s->x;
21396 static int mod_evhost_patch_connection(server *srv, connection *con, plugin_data *p) {
21398 plugin_config *s = p->config_storage[0];
21400 - PATCH(path_pieces);
21404 + PATCH_OPTION(path_pieces);
21405 + PATCH_OPTION(len);
21407 /* skip the first, the global context */
21408 for (i = 1; i < srv->config_context->used; i++) {
21409 data_config *dc = (data_config *)srv->config_context->data[i];
21410 s = p->config_storage[i];
21413 /* condition didn't match */
21414 if (!config_check_cond(srv, con, dc)) continue;
21418 for (j = 0; j < dc->value->used; j++) {
21419 data_unset *du = dc->value->data[j];
21422 if (buffer_is_equal_string(du->key, CONST_STR_LEN("evhost.path-pattern"))) {
21423 - PATCH(path_pieces);
21425 + PATCH_OPTION(path_pieces);
21426 + PATCH_OPTION(len);
21437 static handler_t mod_evhost_uri_handler(server *srv, connection *con, void *p_d) {
21438 plugin_data *p = p_d;
21439 @@ -261,29 +259,29 @@
21440 register char *ptr;
21442 stat_cache_entry *sce = NULL;
21445 /* not authority set */
21446 if (con->uri.authority->used == 0) return HANDLER_GO_ON;
21449 mod_evhost_patch_connection(srv, con, p);
21452 /* missing even default(global) conf */
21453 if (0 == p->conf.len) {
21454 return HANDLER_GO_ON;
21457 parsed_host = array_init();
21460 mod_evhost_parse_host(con, parsed_host);
21463 /* build document-root */
21464 buffer_reset(p->tmp_buf);
21467 for (i = 0; i < p->conf.len; i++) {
21468 ptr = p->conf.path_pieces[i]->ptr;
21473 if (*(ptr+1) == '%') {
21475 BUFFER_APPEND_STRING_CONST(p->tmp_buf,"%");
21476 @@ -298,11 +296,11 @@
21477 buffer_append_string_buffer(p->tmp_buf,p->conf.path_pieces[i]);
21481 - BUFFER_APPEND_SLASH(p->tmp_buf);
21484 + PATHNAME_APPEND_SLASH(p->tmp_buf);
21486 array_free(parsed_host);
21489 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
21490 log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
21492 @@ -310,11 +308,11 @@
21493 log_error_write(srv, __FILE__, __LINE__, "sb", "not a directory:", p->tmp_buf);
21499 buffer_copy_string_buffer(con->physical.doc_root, p->tmp_buf);
21503 return HANDLER_GO_ON;
21506 @@ -325,9 +323,9 @@
21507 p->set_defaults = mod_evhost_set_defaults;
21508 p->handle_docroot = mod_evhost_uri_handler;
21509 p->cleanup = mod_evhost_free;
21518 --- ../lighttpd-1.4.11/src/mod_expire.c 2005-11-03 09:52:13.000000000 +0200
21519 +++ lighttpd-1.4.12/src/mod_expire.c 2006-07-16 00:26:04.000000000 +0300
21521 #include "stat_cache.h"
21524 - * this is a expire module for a lighttpd
21526 + * this is a expire module for a lighttpd
21528 * set 'Expires:' HTTP Headers on demand
21531 @@ -27,51 +27,51 @@
21537 buffer *expire_tstmp;
21540 plugin_config **config_storage;
21542 - plugin_config conf;
21544 + plugin_config conf;
21547 /* init the plugin data */
21548 INIT_FUNC(mod_expire_init) {
21552 p = calloc(1, sizeof(*p));
21555 p->expire_tstmp = buffer_init();
21558 buffer_prepare_copy(p->expire_tstmp, 255);
21564 /* detroy the plugin data */
21565 FREE_FUNC(mod_expire_free) {
21566 plugin_data *p = p_d;
21571 if (!p) return HANDLER_GO_ON;
21574 buffer_free(p->expire_tstmp);
21577 if (p->config_storage) {
21579 for (i = 0; i < srv->config_context->used; i++) {
21580 plugin_config *s = p->config_storage[i];
21583 array_free(s->expire_url);
21588 free(p->config_storage);
21595 return HANDLER_GO_ON;
21598 @@ -79,25 +79,25 @@
21611 * '(access|modification) [plus] {<num> <type>}*'
21614 * e.g. 'access 1 years'
21618 if (expire->used == 0) {
21619 - log_error_write(srv, __FILE__, __LINE__, "s",
21620 + log_error_write(srv, __FILE__, __LINE__, "s",
21629 if (0 == strncmp(ts, "access ", 7)) {
21632 @@ -110,39 +110,39 @@
21633 "invalid <base>:", ts);
21638 if (0 == strncmp(ts, "plus ", 5)) {
21639 /* skip the optional plus */
21644 /* the rest is just <number> (years|months|days|hours|minutes|seconds) */
21650 if (NULL == (space = strchr(ts, ' '))) {
21651 - log_error_write(srv, __FILE__, __LINE__, "ss",
21652 + log_error_write(srv, __FILE__, __LINE__, "ss",
21653 "missing space after <num>:", ts);
21658 num = strtol(ts, &err, 10);
21660 - log_error_write(srv, __FILE__, __LINE__, "ss",
21661 + log_error_write(srv, __FILE__, __LINE__, "ss",
21662 "missing <type> after <num>:", ts);
21670 if (NULL != (space = strchr(ts, ' '))) {
21680 0 == strncmp(ts, "years", slen)) {
21681 num *= 60 * 60 * 24 * 30 * 12;
21682 } else if (slen == 6 &&
21683 @@ -161,13 +161,13 @@
21684 0 == strncmp(ts, "seconds", slen)) {
21687 - log_error_write(srv, __FILE__, __LINE__, "ss",
21688 + log_error_write(srv, __FILE__, __LINE__, "ss",
21689 "unknown type:", ts);
21699 if (0 == strcmp(ts, "years")) {
21700 @@ -183,19 +183,19 @@
21701 } else if (0 == strcmp(ts, "seconds")) {
21704 - log_error_write(srv, __FILE__, __LINE__, "ss",
21705 + log_error_write(srv, __FILE__, __LINE__, "ss",
21706 "unknown type:", ts);
21719 if (offset != NULL) *offset = retts;
21725 @@ -205,102 +205,99 @@
21726 SETDEFAULTS_FUNC(mod_expire_set_defaults) {
21727 plugin_data *p = p_d;
21730 - config_values_t cv[] = {
21732 + config_values_t cv[] = {
21733 { "expire.url", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
21734 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
21738 if (!p) return HANDLER_ERROR;
21741 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
21744 for (i = 0; i < srv->config_context->used; i++) {
21748 s = calloc(1, sizeof(plugin_config));
21749 s->expire_url = array_init();
21752 cv[0].destination = s->expire_url;
21755 p->config_storage[i] = s;
21758 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
21759 return HANDLER_ERROR;
21763 for (k = 0; k < s->expire_url->used; k++) {
21764 data_string *ds = (data_string *)s->expire_url->data[k];
21768 if (-1 == mod_expire_get_offset(srv, p, ds->value, NULL)) {
21769 - log_error_write(srv, __FILE__, __LINE__, "sb",
21770 + log_error_write(srv, __FILE__, __LINE__, "sb",
21771 "parsing expire.url failed:", ds->value);
21772 return HANDLER_ERROR;
21780 return HANDLER_GO_ON;
21783 -#define PATCH(x) \
21784 - p->conf.x = s->x;
21785 static int mod_expire_patch_connection(server *srv, connection *con, plugin_data *p) {
21787 plugin_config *s = p->config_storage[0];
21789 - PATCH(expire_url);
21792 + PATCH_OPTION(expire_url);
21794 /* skip the first, the global context */
21795 for (i = 1; i < srv->config_context->used; i++) {
21796 data_config *dc = (data_config *)srv->config_context->data[i];
21797 s = p->config_storage[i];
21800 /* condition didn't match */
21801 if (!config_check_cond(srv, con, dc)) continue;
21805 for (j = 0; j < dc->value->used; j++) {
21806 data_unset *du = dc->value->data[j];
21809 if (buffer_is_equal_string(du->key, CONST_STR_LEN("expire.url"))) {
21810 - PATCH(expire_url);
21811 + PATCH_OPTION(expire_url);
21821 URIHANDLER_FUNC(mod_expire_path_handler) {
21822 plugin_data *p = p_d;
21827 if (con->uri.path->used == 0) return HANDLER_GO_ON;
21830 mod_expire_patch_connection(srv, con, p);
21833 s_len = con->uri.path->used - 1;
21836 for (k = 0; k < p->conf.expire_url->used; k++) {
21837 data_string *ds = (data_string *)p->conf.expire_url->data[k];
21838 int ct_len = ds->key->used - 1;
21841 if (ct_len > s_len) continue;
21842 if (ds->key->used == 0) continue;
21845 if (0 == strncmp(con->uri.path->ptr, ds->key->ptr, ct_len)) {
21849 stat_cache_entry *sce = NULL;
21852 stat_cache_get_entry(srv, con, con->physical.path, &sce);
21855 switch(mod_expire_get_offset(srv, p, ds->value, &ts)) {
21858 @@ -308,38 +305,38 @@
21864 t = (ts + sce->st.st_mtime);
21867 /* -1 is handled at parse-time */
21872 - if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21875 + if (0 == (len = strftime(p->expire_tstmp->ptr, p->expire_tstmp->size - 1,
21876 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(t))))) {
21877 /* could not set expire header, out of mem */
21880 return HANDLER_GO_ON;
21886 p->expire_tstmp->used = len + 1;
21891 response_header_overwrite(srv, con, CONST_STR_LEN("Expires"), CONST_BUF_LEN(p->expire_tstmp));
21895 buffer_copy_string(p->expire_tstmp, "max-age=");
21896 buffer_append_long(p->expire_tstmp, ts);
21899 response_header_overwrite(srv, con, CONST_STR_LEN("Cache-Control"), CONST_BUF_LEN(p->expire_tstmp));
21902 return HANDLER_GO_ON;
21908 return HANDLER_GO_ON;
21910 @@ -349,13 +346,13 @@
21911 int mod_expire_plugin_init(plugin *p) {
21912 p->version = LIGHTTPD_VERSION_ID;
21913 p->name = buffer_init_string("expire");
21916 p->init = mod_expire_init;
21917 p->handle_subrequest_start = mod_expire_path_handler;
21918 p->set_defaults = mod_expire_set_defaults;
21919 p->cleanup = mod_expire_free;
21927 --- ../lighttpd-1.4.11/src/mod_fastcgi.c 2006-03-09 13:18:39.000000000 +0200
21928 +++ lighttpd-1.4.12/src/mod_fastcgi.c 2006-07-18 13:03:40.000000000 +0300
21930 #include <sys/types.h>
21931 -#include <unistd.h>
21934 #include <string.h>
21936 #include "inet_ntop_cache.h"
21937 #include "stat_cache.h"
21939 -#include <fastcgi.h>
21940 +#include "fastcgi.h"
21943 #ifdef HAVE_SYS_FILIO_H
21947 #include "sys-socket.h"
21948 +#include "sys-files.h"
21949 +#include "sys-strings.h"
21950 +#include "sys-process.h"
21952 +#include "http_resp.h"
21954 #ifndef UNIX_PATH_MAX
21955 # define UNIX_PATH_MAX 108
21956 @@ -45,14 +48,13 @@
21957 #include <sys/wait.h>
21967 * - add timeout for a connect to a non-fastcgi process
21968 * (use state_timestamp + state)
21973 typedef struct fcgi_proc {
21975 unsigned port; /* config.port + pno */
21977 buffer *connection_name; /* either tcp:<host>:<port> or unix:<socket> for debuggin purposes */
21980 pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
21983 @@ -70,20 +72,20 @@
21984 time_t last_used; /* see idle_timeout */
21985 size_t requests; /* see max_requests */
21986 struct fcgi_proc *prev, *next; /* see first */
21989 time_t disabled_until; /* this proc is disabled until, use something else until than */
21996 PROC_STATE_UNSET, /* init-phase */
21997 PROC_STATE_RUNNING, /* alive */
21998 - PROC_STATE_OVERLOADED, /* listen-queue is full,
21999 + PROC_STATE_OVERLOADED, /* listen-queue is full,
22000 don't send something to this proc for the next 2 seconds */
22001 PROC_STATE_DIED_WAIT_FOR_PID, /* */
22002 PROC_STATE_DIED, /* marked as dead, should be restarted */
22003 PROC_STATE_KILLED /* was killed as we don't have the load anymore */
22009 @@ -94,20 +96,20 @@
22010 * sorted by lowest load
22012 * whenever a job is done move it up in the list
22013 - * until it is sorted, move it down as soon as the
22014 + * until it is sorted, move it down as soon as the
22017 - fcgi_proc *first;
22018 - fcgi_proc *unused_procs;
22019 + fcgi_proc *first;
22020 + fcgi_proc *unused_procs;
22024 * spawn at least min_procs, at max_procs.
22026 - * as soon as the load of the first entry
22027 + * as soon as the load of the first entry
22028 * is max_load_per_proc we spawn a new one
22029 - * and add it to the first entry and give it
22030 + * and add it to the first entry and give it
22036 unsigned short min_procs;
22037 @@ -119,44 +121,44 @@
22040 * kick the process from the list if it was not
22041 - * used for idle_timeout until min_procs is
22042 + * used for idle_timeout until min_procs is
22043 * reached. this helps to get the processlist
22044 * small again we had a small peak load.
22049 unsigned short idle_timeout;
22053 * time after a disabled remote connection is tried to be re-enabled
22061 unsigned short disable_time;
22064 * same fastcgi processes get a little bit larger
22065 - * than wanted. max_requests_per_proc kills a
22066 + * than wanted. max_requests_per_proc kills a
22067 * process after a number of handled requests.
22070 size_t max_requests_per_proc;
22081 - * if host is one of the local IP adresses the
22082 + * if host is one of the local IP adresses the
22083 * whole connection is local
22085 * if tcp/ip should be used host AND port have
22086 - * to be specified
22090 + * to be specified
22094 unsigned short port;
22097 @@ -169,7 +171,7 @@
22099 buffer *unixsocket;
22101 - /* if socket is local we can start the fastcgi
22102 + /* if socket is local we can start the fastcgi
22105 * bin-path is the path to the binary
22106 @@ -177,19 +179,19 @@
22107 * check min_procs and max_procs for the number
22108 * of process to start-up
22110 - buffer *bin_path;
22112 - /* bin-path is set bin-environment is taken to
22113 + buffer *bin_path;
22115 + /* bin-path is set bin-environment is taken to
22116 * create the environement before starting the
22124 array *bin_env_copy;
22128 - * docroot-translation between URL->phys and the
22129 + * docroot-translation between URL->phys and the
22133 @@ -208,7 +210,7 @@
22134 unsigned short mode;
22137 - * check_local tell you if the phys file is stat()ed
22138 + * check_local tell you if the phys file is stat()ed
22139 * or not. FastCGI doesn't care if the service is
22140 * remote. If the web-server side doesn't contain
22141 * the fastcgi-files we should not stat() for them
22142 @@ -218,11 +220,11 @@
22145 * append PATH_INFO to SCRIPT_FILENAME
22148 * php needs this if cgi.fix_pathinfo is provied
22154 unsigned short break_scriptfilename_for_php;
22157 @@ -231,12 +233,12 @@
22160 unsigned short allow_xsendfile;
22163 ssize_t load; /* replace by host->load */
22165 size_t max_id; /* corresponds most of the time to
22169 only if a process is killed max_id waits for the process itself
22170 to die and decrements its afterwards */
22172 @@ -245,17 +247,17 @@
22175 * one extension can have multiple hosts assigned
22176 - * one host can spawn additional processes on the same
22177 + * one host can spawn additional processes on the same
22178 * socket (if we control it)
22180 * ext -> host -> procs
22183 - * if the fastcgi process is remote that whole goes down
22184 + * if the fastcgi process is remote that whole goes down
22187 * ext -> host -> procs
22191 * in case of PHP and FCGI_CHILDREN we have again a procs
22192 * but we don't control it directly.
22193 @@ -268,7 +270,7 @@
22196 fcgi_extension_host **hosts;
22202 @@ -282,10 +284,10 @@
22209 array *ext_mapping;
22215 @@ -297,7 +299,7 @@
22224 @@ -306,55 +308,54 @@
22227 buffer_uint fcgi_request_id;
22234 - buffer *parse_response;
22241 plugin_config **config_storage;
22244 plugin_config conf; /* this is only used as long as no handler_ctx is setup */
22247 /* connection specific data */
22252 - FCGI_STATE_CONNECT_DELAYED,
22253 - FCGI_STATE_PREPARE_WRITE,
22254 - FCGI_STATE_WRITE,
22257 + FCGI_STATE_CONNECT_DELAYED,
22258 + FCGI_STATE_PREPARE_WRITE,
22259 + FCGI_STATE_WRITE,
22261 } fcgi_connection_state_t;
22265 fcgi_extension_host *host;
22266 fcgi_extension *ext;
22269 fcgi_connection_state_t state;
22270 time_t state_timestamp;
22273 int reconnects; /* number of reconnect attempts */
22275 - chunkqueue *rb; /* read queue */
22277 + chunkqueue *rb; /* the raw fcgi read-queue */
22278 + chunkqueue *http_rb; /* the decoded read-queue for http-parsing */
22279 chunkqueue *wb; /* write queue */
22281 - buffer *response_header;
22285 - int fd; /* fd to the fastcgi process */
22286 - int fde_ndx; /* index into the fd-event buffer */
22292 int send_content_body;
22295 plugin_config conf;
22298 connection *remote_conn; /* dumb pointer */
22299 plugin_data *plugin_data; /* dumb pointer */
22301 @@ -380,7 +381,7 @@
22305 -/* dummies of the statistic framework functions
22306 +/* dummies of the statistic framework functions
22307 * they will be moved to a statistics.c later */
22308 int status_counter_inc(server *srv, const char *s, size_t len) {
22309 data_integer *di = status_counter_get_counter(srv, s, len);
22310 @@ -429,7 +430,7 @@
22311 CLEAN(".connected");
22318 fastcgi_status_copy_procname(b, host, NULL); \
22319 @@ -438,33 +439,30 @@
22329 static handler_ctx * handler_ctx_init() {
22330 handler_ctx * hctx;
22333 hctx = calloc(1, sizeof(*hctx));
22336 - hctx->fde_ndx = -1;
22338 - hctx->response_header = buffer_init();
22341 hctx->request_id = 0;
22342 hctx->state = FCGI_STATE_INIT;
22348 + hctx->sock = iosocket_init();
22350 hctx->reconnects = 0;
22351 hctx->send_content_body = 1;
22353 hctx->rb = chunkqueue_init();
22354 + hctx->http_rb = chunkqueue_init();
22355 hctx->wb = chunkqueue_init();
22361 @@ -473,12 +471,13 @@
22362 hctx->host->load--;
22366 - buffer_free(hctx->response_header);
22368 chunkqueue_free(hctx->rb);
22369 + chunkqueue_free(hctx->http_rb);
22370 chunkqueue_free(hctx->wb);
22372 + iosocket_free(hctx->sock);
22377 @@ -488,21 +487,21 @@
22378 f = calloc(1, sizeof(*f));
22379 f->unixsocket = buffer_init();
22380 f->connection_name = buffer_init();
22390 void fastcgi_process_free(fcgi_proc *f) {
22394 fastcgi_process_free(f->next);
22397 buffer_free(f->unixsocket);
22398 buffer_free(f->connection_name);
22404 @@ -519,13 +518,13 @@
22405 f->bin_env = array_init();
22406 f->bin_env_copy = array_init();
22407 f->strip_request_uri = buffer_init();
22413 void fastcgi_host_free(fcgi_extension_host *h) {
22417 buffer_free(h->id);
22418 buffer_free(h->host);
22419 buffer_free(h->unixsocket);
22420 @@ -534,49 +533,49 @@
22421 buffer_free(h->strip_request_uri);
22422 array_free(h->bin_env);
22423 array_free(h->bin_env_copy);
22426 fastcgi_process_free(h->first);
22427 fastcgi_process_free(h->unused_procs);
22435 fcgi_exts *fastcgi_extensions_init() {
22438 f = calloc(1, sizeof(*f));
22444 void fastcgi_extensions_free(fcgi_exts *f) {
22451 for (i = 0; i < f->used; i++) {
22452 fcgi_extension *fe;
22459 for (j = 0; j < fe->used; j++) {
22460 fcgi_extension_host *h;
22466 fastcgi_host_free(h);
22470 buffer_free(fe->key);
22484 @@ -625,24 +624,25 @@
22488 - fe->hosts[fe->used++] = fh;
22489 + fe->hosts[fe->used++] = fh;
22496 INIT_FUNC(mod_fastcgi_init) {
22500 p = calloc(1, sizeof(*p));
22503 p->fcgi_env = buffer_init();
22506 p->path = buffer_init();
22507 - p->parse_response = buffer_init();
22509 + p->resp = http_response_init();
22511 p->statuskey = buffer_init();
22517 @@ -650,81 +650,82 @@
22518 FREE_FUNC(mod_fastcgi_free) {
22519 plugin_data *p = p_d;
22520 buffer_uint *r = &(p->fcgi_request_id);
22525 if (r->ptr) free(r->ptr);
22528 buffer_free(p->fcgi_env);
22529 buffer_free(p->path);
22530 - buffer_free(p->parse_response);
22531 buffer_free(p->statuskey);
22534 + http_response_free(p->resp);
22536 if (p->config_storage) {
22538 for (i = 0; i < srv->config_context->used; i++) {
22539 plugin_config *s = p->config_storage[i];
22548 for (j = 0; j < exts->used; j++) {
22549 fcgi_extension *ex;
22552 ex = exts->exts[j];
22555 for (n = 0; n < ex->used; n++) {
22557 fcgi_extension_host *host;
22560 host = ex->hosts[n];
22563 for (proc = host->first; proc; proc = proc->next) {
22564 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22566 - if (proc->is_local &&
22568 + if (proc->is_local &&
22569 !buffer_is_empty(proc->unixsocket)) {
22570 unlink(proc->unixsocket->ptr);
22575 for (proc = host->unused_procs; proc; proc = proc->next) {
22576 if (proc->pid != 0) kill(proc->pid, SIGTERM);
22578 - if (proc->is_local &&
22580 + if (proc->is_local &&
22581 !buffer_is_empty(proc->unixsocket)) {
22582 unlink(proc->unixsocket->ptr);
22589 fastcgi_extensions_free(s->exts);
22590 array_free(s->ext_mapping);
22595 free(p->config_storage);
22602 return HANDLER_GO_ON;
22605 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
22609 if (!key || !val) return -1;
22612 dst = malloc(key_len + val_len + 3);
22613 memcpy(dst, key, key_len);
22614 dst[key_len] = '=';
22615 /* add the \0 from the value */
22616 memcpy(dst + key_len + 1, val, val_len + 1);
22619 if (env->size == 0) {
22621 env->ptr = malloc(env->size * sizeof(*env->ptr));
22622 @@ -732,9 +733,9 @@
22624 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22628 env->ptr[env->used++] = dst;
22634 @@ -753,15 +754,15 @@
22635 if (env->size == 0) {
22637 env->ptr = malloc(env->size * sizeof(*env->ptr));
22638 - } else if (env->size == env->used) {
22639 + } else if (env->size == env->used) {
22641 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
22647 env->ptr[env->used++] = start;
22650 start = b->ptr + i + 1;
22653 @@ -794,7 +795,7 @@
22657 -static int fcgi_spawn_connection(server *srv,
22658 +static int fcgi_spawn_connection(server *srv,
22660 fcgi_extension_host *host,
22662 @@ -806,31 +807,27 @@
22664 struct sockaddr_in fcgi_addr_in;
22665 struct sockaddr *fcgi_addr;
22676 if (p->conf.debug) {
22677 log_error_write(srv, __FILE__, __LINE__, "sdb",
22678 "new proc, socket:", proc->port, proc->unixsocket);
22682 if (!buffer_is_empty(proc->unixsocket)) {
22683 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
22686 #ifdef HAVE_SYS_UN_H
22687 fcgi_addr_un.sun_family = AF_UNIX;
22688 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
22692 servlen = SUN_LEN(&fcgi_addr_un);
22694 - /* stevens says: */
22695 - servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
22698 socket_type = AF_UNIX;
22699 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
22701 @@ -844,108 +841,108 @@
22704 fcgi_addr_in.sin_family = AF_INET;
22707 if (buffer_is_empty(host->host)) {
22708 fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22710 struct hostent *he;
22713 /* set a usefull default */
22714 fcgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
22719 if (NULL == (he = gethostbyname(host->host->ptr))) {
22720 - log_error_write(srv, __FILE__, __LINE__,
22721 - "sdb", "gethostbyname failed: ",
22722 + log_error_write(srv, __FILE__, __LINE__,
22723 + "sdb", "gethostbyname failed: ",
22724 h_errno, host->host);
22729 if (he->h_addrtype != AF_INET) {
22730 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
22735 if (he->h_length != sizeof(struct in_addr)) {
22736 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
22741 memcpy(&(fcgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
22745 fcgi_addr_in.sin_port = htons(proc->port);
22746 servlen = sizeof(fcgi_addr_in);
22749 socket_type = AF_INET;
22750 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
22753 buffer_copy_string(proc->connection_name, "tcp:");
22754 buffer_append_string_buffer(proc->connection_name, host->host);
22755 buffer_append_string(proc->connection_name, ":");
22756 buffer_append_long(proc->connection_name, proc->port);
22760 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22761 - log_error_write(srv, __FILE__, __LINE__, "ss",
22762 + log_error_write(srv, __FILE__, __LINE__, "ss",
22763 "failed:", strerror(errno));
22768 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
22769 /* server is not up, spawn in */
22773 - if (errno != ENOENT &&
22775 + if (errno != ENOENT &&
22776 !buffer_is_empty(proc->unixsocket)) {
22777 unlink(proc->unixsocket->ptr);
22784 /* reopen socket */
22785 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
22786 - log_error_write(srv, __FILE__, __LINE__, "ss",
22787 + log_error_write(srv, __FILE__, __LINE__, "ss",
22788 "socket failed:", strerror(errno));
22794 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
22795 - log_error_write(srv, __FILE__, __LINE__, "ss",
22796 + log_error_write(srv, __FILE__, __LINE__, "ss",
22797 "socketsockopt failed:", strerror(errno));
22802 /* create socket */
22803 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
22804 - log_error_write(srv, __FILE__, __LINE__, "sbs",
22805 - "bind failed for:",
22806 + log_error_write(srv, __FILE__, __LINE__, "sbs",
22807 + "bind failed for:",
22808 proc->connection_name,
22814 if (-1 == listen(fcgi_fd, 1024)) {
22815 - log_error_write(srv, __FILE__, __LINE__, "ss",
22816 + log_error_write(srv, __FILE__, __LINE__, "ss",
22817 "listen failed:", strerror(errno));
22824 switch ((child = fork())) {
22832 /* create environment */
22841 @@ -955,18 +952,18 @@
22842 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
22847 /* we don't need the client socket */
22848 for (i = 3; i < 256; i++) {
22853 /* build clean environment */
22854 if (host->bin_env_copy->used) {
22855 for (i = 0; i < host->bin_env_copy->used; i++) {
22856 data_string *ds = (data_string *)host->bin_env_copy->data[i];
22860 if (NULL != (ge = getenv(ds->value->ptr))) {
22861 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
22863 @@ -974,39 +971,39 @@
22865 for (i = 0; environ[i]; i++) {
22869 if (NULL != (eq = strchr(environ[i], '='))) {
22870 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
22876 /* create environment */
22877 for (i = 0; i < host->bin_env->used; i++) {
22878 data_string *ds = (data_string *)host->bin_env->data[i];
22881 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
22885 for (i = 0; i < env.used; i++) {
22886 /* search for PHP_FCGI_CHILDREN */
22887 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
22891 /* not found, add a default */
22892 if (i == env.used) {
22893 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
22897 env.ptr[env.used] = NULL;
22899 parse_binpath(&arg, host->bin_path);
22902 /* chdir into the base of the bin-path,
22903 * search for the last / */
22904 if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
22908 /* change to the physical directory */
22909 if (-1 == chdir(arg.ptr[0])) {
22911 @@ -1018,12 +1015,12 @@
22914 execve(arg.ptr[0], arg.ptr, env.ptr);
22916 - log_error_write(srv, __FILE__, __LINE__, "sbs",
22918 + log_error_write(srv, __FILE__, __LINE__, "sbs",
22919 "execve failed for:", host->bin_path, strerror(errno));
22928 @@ -1031,17 +1028,17 @@
22935 select(0, NULL, NULL, NULL, &tv);
22938 switch (waitpid(child, &status, WNOHANG)) {
22940 /* child still running after timeout, good */
22943 /* no PID found ? should never happen */
22944 - log_error_write(srv, __FILE__, __LINE__, "ss",
22945 + log_error_write(srv, __FILE__, __LINE__, "ss",
22946 "pid not found:", strerror(errno));
22949 @@ -1049,10 +1046,10 @@
22950 "the fastcgi-backend", host->bin_path, "failed to start:");
22951 /* the child should not terminate at all */
22952 if (WIFEXITED(status)) {
22953 - log_error_write(srv, __FILE__, __LINE__, "sdb",
22954 - "child exited with status",
22955 + log_error_write(srv, __FILE__, __LINE__, "sdb",
22956 + "child exited with status",
22957 WEXITSTATUS(status), host->bin_path);
22958 - log_error_write(srv, __FILE__, __LINE__, "s",
22959 + log_error_write(srv, __FILE__, __LINE__, "s",
22960 "if you try do run PHP as FastCGI backend make sure you use the FastCGI enabled version.\n"
22961 "You can find out if it is the right one by executing 'php -v' and it should display '(cgi-fcgi)' "
22962 "in the output, NOT (cgi) NOR (cli)\n"
22963 @@ -1060,8 +1057,8 @@
22964 log_error_write(srv, __FILE__, __LINE__, "s",
22965 "If this is PHP on Gentoo add fastcgi to the USE flags");
22966 } else if (WIFSIGNALED(status)) {
22967 - log_error_write(srv, __FILE__, __LINE__, "sd",
22968 - "terminated by signal:",
22969 + log_error_write(srv, __FILE__, __LINE__, "sd",
22970 + "terminated by signal:",
22973 if (WTERMSIG(status) == 11) {
22974 @@ -1071,8 +1068,8 @@
22975 "If this is PHP try to remove the byte-code caches for now and try again.");
22978 - log_error_write(srv, __FILE__, __LINE__, "sd",
22979 - "child died somehow:",
22980 + log_error_write(srv, __FILE__, __LINE__, "sd",
22981 + "child died somehow:",
22985 @@ -1082,26 +1079,26 @@
22987 proc->last_used = srv->cur_ts;
22988 proc->is_local = 1;
22995 proc->is_local = 0;
22999 if (p->conf.debug) {
23000 log_error_write(srv, __FILE__, __LINE__, "sb",
23001 "(debug) socket is already used, won't spawn:",
23002 proc->connection_name);
23007 proc->state = PROC_STATE_RUNNING;
23008 host->active_procs++;
23017 @@ -1111,93 +1108,93 @@
23020 buffer *fcgi_mode = buffer_init();
23022 - config_values_t cv[] = {
23024 + config_values_t cv[] = {
23025 { "fastcgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
23026 { "fastcgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
23027 { "fastcgi.map-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
23028 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23032 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
23035 for (i = 0; i < srv->config_context->used; i++) {
23040 s = malloc(sizeof(plugin_config));
23041 s->exts = fastcgi_extensions_init();
23043 s->ext_mapping = array_init();
23046 cv[0].destination = s->exts;
23047 cv[1].destination = &(s->debug);
23048 cv[2].destination = s->ext_mapping;
23051 p->config_storage[i] = s;
23052 ca = ((data_config *)srv->config_context->data[i])->value;
23055 if (0 != config_insert_values_global(srv, ca, cv)) {
23056 return HANDLER_ERROR;
23066 if (NULL != (du = array_get_element(ca, "fastcgi.server"))) {
23068 data_array *da = (data_array *)du;
23071 if (du->type != TYPE_ARRAY) {
23072 - log_error_write(srv, __FILE__, __LINE__, "sss",
23073 + log_error_write(srv, __FILE__, __LINE__, "sss",
23074 "unexpected type for key: ", "fastcgi.server", "array of strings");
23077 return HANDLER_ERROR;
23082 - * fastcgi.server = ( "<ext>" => ( ... ),
23086 + * fastcgi.server = ( "<ext>" => ( ... ),
23087 * "<ext>" => ( ... ) )
23091 for (j = 0; j < da->value->used; j++) {
23093 data_array *da_ext = (data_array *)da->value->data[j];
23096 if (da->value->data[j]->type != TYPE_ARRAY) {
23097 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
23098 - "unexpected type for key: ", "fastcgi.server",
23099 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
23100 + "unexpected type for key: ", "fastcgi.server",
23101 "[", da->value->data[j]->key, "](string)");
23104 return HANDLER_ERROR;
23108 - * da_ext->key == name of the extension
23111 + * da_ext->key == name of the extension
23115 - * fastcgi.server = ( "<ext>" =>
23116 - * ( "<host>" => ( ... ),
23119 + * fastcgi.server = ( "<ext>" =>
23120 + * ( "<host>" => ( ... ),
23121 * "<host>" => ( ... )
23128 for (n = 0; n < da_ext->value->used; n++) {
23129 data_array *da_host = (data_array *)da_ext->value->data[n];
23132 fcgi_extension_host *host;
23134 - config_values_t fcv[] = {
23136 + config_values_t fcv[] = {
23137 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
23138 { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
23139 { "mode", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
23140 { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
23141 { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
23144 { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
23145 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 6 */
23146 { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
23147 @@ -1205,28 +1202,28 @@
23148 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
23149 { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
23150 { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
23153 { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
23154 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 13 */
23157 { "broken-scriptfilename", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 14 */
23158 { "allow-x-send-file", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 15 */
23159 { "strip-request-uri", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 16 */
23162 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
23166 if (da_host->type != TYPE_ARRAY) {
23167 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23168 - "unexpected type for key:",
23169 - "fastcgi.server",
23170 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
23171 + "unexpected type for key:",
23172 + "fastcgi.server",
23173 "[", da_host->key, "](string)");
23176 return HANDLER_ERROR;
23180 host = fastcgi_host_init();
23183 buffer_copy_string_buffer(host->id, da_host->key);
23185 host->check_local = 1;
23186 @@ -1238,13 +1235,13 @@
23187 host->disable_time = 60;
23188 host->break_scriptfilename_for_php = 0;
23189 host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
23192 fcv[0].destination = host->host;
23193 fcv[1].destination = host->docroot;
23194 fcv[2].destination = fcgi_mode;
23195 fcv[3].destination = host->unixsocket;
23196 fcv[4].destination = host->bin_path;
23199 fcv[5].destination = &(host->check_local);
23200 fcv[6].destination = &(host->port);
23201 fcv[7].destination = &(host->min_procs);
23202 @@ -1252,35 +1249,35 @@
23203 fcv[9].destination = &(host->max_load_per_proc);
23204 fcv[10].destination = &(host->idle_timeout);
23205 fcv[11].destination = &(host->disable_time);
23208 fcv[12].destination = host->bin_env;
23209 fcv[13].destination = host->bin_env_copy;
23210 fcv[14].destination = &(host->break_scriptfilename_for_php);
23211 fcv[15].destination = &(host->allow_xsendfile);
23212 fcv[16].destination = host->strip_request_uri;
23215 if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
23216 return HANDLER_ERROR;
23219 - if ((!buffer_is_empty(host->host) || host->port) &&
23221 + if ((!buffer_is_empty(host->host) || host->port) &&
23222 !buffer_is_empty(host->unixsocket)) {
23223 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23224 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23225 "either host/port or socket have to be set in:",
23228 da_ext->key, " => (",
23229 da_host->key, " ( ...");
23231 return HANDLER_ERROR;
23235 if (!buffer_is_empty(host->unixsocket)) {
23236 /* unix domain socket */
23239 if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
23240 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23241 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23242 "unixsocket is too long in:",
23245 da_ext->key, " => (",
23246 da_host->key, " ( ...");
23248 @@ -1288,37 +1285,37 @@
23253 - if (buffer_is_empty(host->host) &&
23255 + if (buffer_is_empty(host->host) &&
23256 buffer_is_empty(host->bin_path)) {
23257 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23258 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23259 "host or binpath have to be set in:",
23262 da_ext->key, " => (",
23263 da_host->key, " ( ...");
23266 return HANDLER_ERROR;
23267 } else if (host->port == 0) {
23268 - log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23269 + log_error_write(srv, __FILE__, __LINE__, "sbsbsbs",
23270 "port has to be set in:",
23273 da_ext->key, " => (",
23274 da_host->key, " ( ...");
23276 return HANDLER_ERROR;
23280 - if (!buffer_is_empty(host->bin_path)) {
23282 + if (!buffer_is_empty(host->bin_path)) {
23283 /* a local socket + self spawning */
23286 /* HACK: just to make sure the adaptive spawing is disabled */
23287 host->min_procs = host->max_procs;
23290 if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
23291 if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
23295 log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
23296 "--- fastcgi spawning local",
23297 @@ -1328,7 +1325,7 @@
23298 "\n\tmin-procs:", host->min_procs,
23299 "\n\tmax-procs:", host->max_procs);
23303 for (pno = 0; pno < host->min_procs; pno++) {
23306 @@ -1343,7 +1340,7 @@
23307 buffer_append_string(proc->unixsocket, "-");
23308 buffer_append_long(proc->unixsocket, pno);
23313 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
23314 "--- fastcgi spawning",
23315 @@ -1351,7 +1348,7 @@
23316 "\n\tsocket", host->unixsocket,
23317 "\n\tcurrent:", pno, "/", host->min_procs);
23321 if (fcgi_spawn_connection(srv, p, host, proc)) {
23322 log_error_write(srv, __FILE__, __LINE__, "s",
23323 "[ERROR]: spawning fcgi failed.");
23324 @@ -1359,35 +1356,35 @@
23327 fastcgi_status_init(srv, p->statuskey, host, proc);
23330 proc->next = host->first;
23331 if (host->first) host->first->prev = proc;
23334 host->first = proc;
23340 proc = fastcgi_process_init();
23341 proc->id = host->num_procs++;
23343 host->active_procs++;
23344 proc->state = PROC_STATE_RUNNING;
23347 if (buffer_is_empty(host->unixsocket)) {
23348 proc->port = host->port;
23350 buffer_copy_string_buffer(proc->unixsocket, host->unixsocket);
23354 fastcgi_status_init(srv, p->statuskey, host, proc);
23356 host->first = proc;
23359 host->min_procs = 1;
23360 host->max_procs = 1;
23364 if (!buffer_is_empty(fcgi_mode)) {
23365 if (strcmp(fcgi_mode->ptr, "responder") == 0) {
23366 host->mode = FCGI_RESPONDER;
23367 @@ -1411,16 +1408,16 @@
23373 buffer_free(fcgi_mode);
23376 return HANDLER_GO_ON;
23379 static int fcgi_set_state(server *srv, handler_ctx *hctx, fcgi_connection_state_t state) {
23380 hctx->state = state;
23381 hctx->state_timestamp = srv->cur_ts;
23387 @@ -1429,13 +1426,13 @@
23390 buffer_uint *r = &(p->fcgi_request_id);
23395 for (i = 0; i < r->used; i++) {
23396 if (r->ptr[i] > m) m = r->ptr[i];
23400 if (r->size == 0) {
23402 r->ptr = malloc(sizeof(*r->ptr) * r->size);
23403 @@ -1443,54 +1440,55 @@
23405 r->ptr = realloc(r->ptr, sizeof(*r->ptr) * r->size);
23409 r->ptr[r->used++] = ++m;
23415 static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
23417 buffer_uint *r = &(p->fcgi_request_id);
23422 for (i = 0; i < r->used; i++) {
23423 if (r->ptr[i] == request_id) break;
23427 if (i != r->used) {
23431 if (i != r->used - 1) {
23432 r->ptr[i] = r->ptr[r->used - 1];
23440 void fcgi_connection_close(server *srv, handler_ctx *hctx) {
23445 if (NULL == hctx) return;
23448 p = hctx->plugin_data;
23449 con = hctx->remote_conn;
23452 if (con->mode != p->id) {
23457 - if (hctx->fd != -1) {
23458 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23459 - fdevent_unregister(srv->ev, hctx->fd);
23463 + if (hctx->sock->fd != -1) {
23464 + fdevent_event_del(srv->ev, hctx->sock);
23465 + fdevent_unregister(srv->ev, hctx->sock);
23466 + closesocket(hctx->sock->fd);
23467 + hctx->sock->fd = -1;
23473 if (hctx->request_id != 0) {
23474 fcgi_requestid_del(srv, p, hctx->request_id);
23476 @@ -1499,7 +1497,7 @@
23477 if (hctx->got_proc) {
23478 /* after the connect the process gets a load */
23479 hctx->proc->load--;
23482 status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
23484 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
23485 @@ -1509,101 +1507,101 @@
23487 if (p->conf.debug) {
23488 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
23489 - "released proc:",
23490 - "pid:", hctx->proc->pid,
23491 - "socket:", hctx->proc->connection_name,
23492 + "released proc:",
23493 + "pid:", hctx->proc->pid,
23494 + "socket:", hctx->proc->connection_name,
23495 "load:", hctx->proc->load);
23502 handler_ctx_free(hctx);
23503 - con->plugin_ctx[p->id] = NULL;
23504 + con->plugin_ctx[p->id] = NULL;
23507 static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
23508 plugin_data *p = hctx->plugin_data;
23519 * connect was ok, connection was accepted
23520 * but the php accept loop checks after the accept if it should die or not.
23522 - * if yes we can only detect it at a write()
23525 + * if yes we can only detect it at a write()
23527 * next step is resetting this attemp and setup a connection again
23530 * if we have more then 5 reconnects for the same request, die
23537 * we have a connection but the child died by some other reason
23542 - if (hctx->fd != -1) {
23543 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
23544 - fdevent_unregister(srv->ev, hctx->fd);
23546 + if (hctx->sock->fd != -1) {
23547 + fdevent_event_del(srv->ev, hctx->sock);
23548 + fdevent_unregister(srv->ev, hctx->sock);
23549 + close(hctx->sock->fd);
23552 + hctx->sock->fd = -1;
23556 fcgi_requestid_del(srv, p, hctx->request_id);
23559 fcgi_set_state(srv, hctx, FCGI_STATE_INIT);
23562 hctx->request_id = 0;
23563 hctx->reconnects++;
23566 if (p->conf.debug > 2) {
23568 log_error_write(srv, __FILE__, __LINE__, "sdb",
23569 - "release proc for reconnect:",
23570 + "release proc for reconnect:",
23571 hctx->proc->pid, hctx->proc->connection_name);
23573 log_error_write(srv, __FILE__, __LINE__, "sb",
23574 - "release proc for reconnect:",
23575 + "release proc for reconnect:",
23576 hctx->host->unixsocket);
23580 - if (hctx->proc && hctx->got_proc) {
23581 + if (hctx->proc && hctx->got_proc) {
23582 hctx->proc->load--;
23585 /* perhaps another host gives us more luck */
23586 hctx->host->load--;
23594 static handler_t fcgi_connection_reset(server *srv, connection *con, void *p_d) {
23595 plugin_data *p = p_d;
23598 fcgi_connection_close(srv, con->plugin_ctx[p->id]);
23601 return HANDLER_GO_ON;
23605 static int fcgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
23609 if (!key || !val) return -1;
23612 len = key_len + val_len;
23615 len += key_len > 127 ? 4 : 1;
23616 len += val_len > 127 ? 4 : 1;
23619 buffer_prepare_append(env, len);
23622 if (key_len > 127) {
23623 env->ptr[env->used++] = ((key_len >> 24) & 0xff) | 0x80;
23624 env->ptr[env->used++] = (key_len >> 16) & 0xff;
23625 @@ -1612,7 +1610,7 @@
23627 env->ptr[env->used++] = (key_len >> 0) & 0xff;
23631 if (val_len > 127) {
23632 env->ptr[env->used++] = ((val_len >> 24) & 0xff) | 0x80;
23633 env->ptr[env->used++] = (val_len >> 16) & 0xff;
23634 @@ -1621,12 +1619,12 @@
23636 env->ptr[env->used++] = (val_len >> 0) & 0xff;
23640 memcpy(env->ptr + env->used, key, key_len);
23641 env->used += key_len;
23642 memcpy(env->ptr + env->used, val, val_len);
23643 env->used += val_len;
23649 @@ -1639,11 +1637,11 @@
23650 header->contentLengthB1 = (contentLength >> 8) & 0xff;
23651 header->paddingLength = paddingLength;
23652 header->reserved = 0;
23663 @@ -1665,26 +1663,23 @@
23664 struct sockaddr_un fcgi_addr_un;
23669 fcgi_extension_host *host = hctx->host;
23670 fcgi_proc *proc = hctx->proc;
23671 - int fcgi_fd = hctx->fd;
23673 + int fcgi_fd = hctx->sock->fd;
23675 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
23678 if (!buffer_is_empty(proc->unixsocket)) {
23679 #ifdef HAVE_SYS_UN_H
23680 /* use the unix domain socket */
23681 fcgi_addr_un.sun_family = AF_UNIX;
23682 strcpy(fcgi_addr_un.sun_path, proc->unixsocket->ptr);
23685 servlen = SUN_LEN(&fcgi_addr_un);
23687 - /* stevens says: */
23688 - servlen = proc->unixsocket->used + sizeof(fcgi_addr_un.sun_family);
23691 fcgi_addr = (struct sockaddr *) &fcgi_addr_un;
23694 if (buffer_is_empty(proc->connection_name)) {
23695 /* on remote spawing we have to set the connection-name now */
23696 buffer_copy_string(proc->connection_name, "unix:");
23697 @@ -1695,16 +1690,18 @@
23700 fcgi_addr_in.sin_family = AF_INET;
23702 if (0 == inet_aton(host->host->ptr, &(fcgi_addr_in.sin_addr))) {
23703 - log_error_write(srv, __FILE__, __LINE__, "sbs",
23704 - "converting IP-adress failed for", host->host,
23705 + log_error_write(srv, __FILE__, __LINE__, "sbs",
23706 + "converting IP-adress failed for", host->host,
23707 "\nBe sure to specify an IP address here");
23713 fcgi_addr_in.sin_port = htons(proc->port);
23714 servlen = sizeof(fcgi_addr_in);
23717 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
23719 if (buffer_is_empty(proc->connection_name)) {
23720 @@ -1715,20 +1712,20 @@
23721 buffer_append_long(proc->connection_name, proc->port);
23726 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
23727 - if (errno == EINPROGRESS ||
23728 + if (errno == EINPROGRESS ||
23729 errno == EALREADY ||
23731 if (hctx->conf.debug > 2) {
23732 - log_error_write(srv, __FILE__, __LINE__, "sb",
23733 + log_error_write(srv, __FILE__, __LINE__, "sb",
23734 "connect delayed, will continue later:", proc->connection_name);
23738 return CONNECTION_DELAYED;
23739 } else if (errno == EAGAIN) {
23740 if (hctx->conf.debug) {
23741 - log_error_write(srv, __FILE__, __LINE__, "sbsd",
23742 + log_error_write(srv, __FILE__, __LINE__, "sbsd",
23743 "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
23744 "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
23745 "The load for this fastcgi backend", proc->connection_name, "is", proc->load);
23746 @@ -1736,8 +1733,8 @@
23748 return CONNECTION_OVERLOADED;
23750 - log_error_write(srv, __FILE__, __LINE__, "sssb",
23751 - "connect failed:",
23752 + log_error_write(srv, __FILE__, __LINE__, "sssb",
23753 + "connect failed:",
23754 strerror(errno), "on",
23755 proc->connection_name);
23757 @@ -1747,7 +1744,7 @@
23759 hctx->reconnects = 0;
23760 if (hctx->conf.debug > 1) {
23761 - log_error_write(srv, __FILE__, __LINE__, "sd",
23762 + log_error_write(srv, __FILE__, __LINE__, "sd",
23763 "connect succeeded: ", fcgi_fd);
23766 @@ -1756,21 +1753,21 @@
23768 static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
23772 for (i = 0; i < con->request.headers->used; i++) {
23776 ds = (data_string *)con->request.headers->data[i];
23779 if (ds->value->used && ds->key->used) {
23781 buffer_reset(srv->tmp_buf);
23784 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
23785 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
23786 srv->tmp_buf->used--;
23790 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23791 for (j = 0; j < ds->key->used - 1; j++) {
23793 @@ -1784,20 +1781,20 @@
23794 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23796 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23799 fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23804 for (i = 0; i < con->environment->used; i++) {
23808 ds = (data_string *)con->environment->data[i];
23811 if (ds->value->used && ds->key->used) {
23813 buffer_reset(srv->tmp_buf);
23816 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
23817 for (j = 0; j < ds->key->used - 1; j++) {
23819 @@ -1811,11 +1808,11 @@
23820 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
23822 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
23825 fcgi_env_add(p->fcgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
23833 @@ -1824,24 +1821,24 @@
23834 FCGI_BeginRequestRecord beginRecord;
23835 FCGI_Header header;
23842 char b2[INET6_ADDRSTRLEN + 1];
23846 plugin_data *p = hctx->plugin_data;
23847 fcgi_extension_host *host= hctx->host;
23849 connection *con = hctx->remote_conn;
23850 server_socket *srv_sock = con->srv_socket;
23853 sock_addr our_addr;
23854 socklen_t our_addr_len;
23857 /* send FCGI_BEGIN_REQUEST */
23860 fcgi_header(&(beginRecord.header), FCGI_BEGIN_REQUEST, request_id, sizeof(beginRecord.body), 0);
23861 beginRecord.body.roleB0 = host->mode;
23862 beginRecord.body.roleB1 = 0;
23863 @@ -1849,21 +1846,21 @@
23864 memset(beginRecord.body.reserved, 0, sizeof(beginRecord.body.reserved));
23866 b = chunkqueue_get_append_buffer(hctx->wb);
23869 buffer_copy_memory(b, (const char *)&beginRecord, sizeof(beginRecord));
23872 /* send FCGI_PARAMS */
23873 buffer_prepare_copy(p->fcgi_env, 1024);
23876 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
23879 if (con->server_name->used) {
23880 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
23883 - s = inet_ntop(srv_sock->addr.plain.sa_family,
23884 - srv_sock->addr.plain.sa_family == AF_INET6 ?
23885 + s = inet_ntop(srv_sock->addr.plain.sa_family,
23886 + srv_sock->addr.plain.sa_family == AF_INET6 ?
23887 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
23888 (const void *) &(srv_sock->addr.ipv4.sin_addr),
23890 @@ -1872,50 +1869,50 @@
23892 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
23896 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
23902 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
23904 ntohs(srv_sock->addr.ipv4.sin_port)
23909 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
23912 /* get the server-side of the connection to the client */
23913 our_addr_len = sizeof(our_addr);
23915 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
23917 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
23918 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
23920 s = inet_ntop_cache_get_ip(srv, &(our_addr));
23922 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
23928 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
23930 ntohs(con->dst_addr.ipv4.sin_port)
23935 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
23938 s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
23939 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
23942 if (!buffer_is_empty(con->authed_user)) {
23943 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REMOTE_USER"),
23944 CONST_BUF_LEN(con->authed_user));
23948 if (con->request.content_length > 0 && host->mode != FCGI_AUTHORIZER) {
23949 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
23952 /* request.content_length < SSIZE_MAX, see request.c */
23953 ltostr(buf, con->request.content_length);
23954 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
23955 @@ -1930,12 +1927,12 @@
23958 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
23961 if (!buffer_is_empty(con->request.pathinfo)) {
23962 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
23965 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
23968 if (!buffer_is_empty(host->docroot)) {
23969 buffer_copy_string_buffer(p->path, host->docroot);
23971 @@ -1957,27 +1954,27 @@
23974 if (!buffer_is_empty(host->docroot)) {
23976 - * rewrite SCRIPT_FILENAME
23979 + * rewrite SCRIPT_FILENAME
23984 buffer_copy_string_buffer(p->path, host->docroot);
23985 buffer_append_string_buffer(p->path, con->uri.path);
23988 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
23989 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
23991 buffer_copy_string_buffer(p->path, con->physical.path);
23993 - /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
23996 + /* cgi.fix_pathinfo need a broken SCRIPT_FILENAME to find out what PATH_INFO is itself
23998 * see src/sapi/cgi_main.c, init_request_info()
24000 if (host->break_scriptfilename_for_php) {
24001 buffer_append_string_buffer(p->path, con->request.pathinfo);
24005 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
24006 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
24008 @@ -1987,7 +1984,7 @@
24012 - * stripping /app1 or /app1/ should lead to
24013 + * stripping /app1 or /app1/ should lead to
24017 @@ -2001,7 +1998,7 @@
24018 0 == strncmp(con->request.orig_uri->ptr, host->strip_request_uri->ptr, host->strip_request_uri->used - 1)) {
24019 /* the left is the same */
24021 - fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24022 + fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_URI"),
24023 con->request.orig_uri->ptr + (host->strip_request_uri->used - 2),
24024 con->request.orig_uri->used - (host->strip_request_uri->used - 2));
24026 @@ -2018,26 +2015,26 @@
24028 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
24032 s = get_http_method_name(con->request.http_method);
24033 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
24034 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
24035 s = get_http_version_name(con->request.http_version);
24036 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
24040 if (srv_sock->is_ssl) {
24041 fcgi_env_add(p->fcgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
24048 fcgi_env_add_request_headers(srv, con, p);
24051 fcgi_header(&(header), FCGI_PARAMS, request_id, p->fcgi_env->used, 0);
24052 buffer_append_memory(b, (const char *)&header, sizeof(header));
24053 buffer_append_memory(b, (const char *)p->fcgi_env->ptr, p->fcgi_env->used);
24056 fcgi_header(&(header), FCGI_PARAMS, request_id, 0, 0);
24057 buffer_append_memory(b, (const char *)&header, sizeof(header));
24059 @@ -2057,7 +2054,7 @@
24061 /* we announce toWrite octects
24062 * now take all the request_content chunk that we need to fill this request
24066 b = chunkqueue_get_append_buffer(hctx->wb);
24067 fcgi_header(&(header), FCGI_STDIN, request_id, weWant, 0);
24068 @@ -2080,16 +2077,16 @@
24069 if (weHave > weWant - written) weHave = weWant - written;
24071 if (p->conf.debug > 10) {
24072 - fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24073 - __FILE__, __LINE__,
24076 - req_c->file.length,
24077 + fprintf(stderr, "%s.%d: sending %lld bytes from (%lld / %lld) %s\n",
24078 + __FILE__, __LINE__,
24081 + req_c->file.length,
24082 req_c->file.name->ptr);
24085 assert(weHave != 0);
24088 chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);
24090 req_c->offset += weHave;
24091 @@ -2104,7 +2101,7 @@
24092 * - we reference the tempfile from the request-content-queue several times
24093 * if the req_c is larger than FCGI_MAX_LENGTH
24094 * - we can't simply cleanup the request-content-queue as soon as possible
24095 - * as it would remove the tempfiles
24096 + * as it would remove the tempfiles
24097 * - the idea is to 'steal' the tempfiles and attach the is_temp flag to the last
24098 * referencing chunk of the fastcgi-write-queue
24100 @@ -2141,7 +2138,7 @@
24101 req_c->offset += weHave;
24102 req_cq->bytes_out += weHave;
24106 hctx->wb->bytes_in += weHave;
24108 if (req_c->offset == req_c->mem->used - 1) {
24109 @@ -2155,12 +2152,12 @@
24115 b->used++; /* add virtual \0 */
24121 b = chunkqueue_get_append_buffer(hctx->wb);
24122 /* terminate STDIN */
24123 fcgi_header(&(header), FCGI_STDIN, request_id, 0, 0);
24124 @@ -2175,118 +2172,19 @@
24125 if ((i+1) % 16 == 0) {
24127 for (j = i-15; j <= i; j++) {
24128 - fprintf(stderr, "%c",
24129 + fprintf(stderr, "%c",
24130 isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
24132 fprintf(stderr, "\n");
24140 -static int fcgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
24143 - handler_ctx *hctx = con->plugin_ctx[p->id];
24144 - fcgi_extension_host *host= hctx->host;
24148 - buffer_copy_string_buffer(p->parse_response, in);
24150 - /* search for \n */
24151 - for (s = p->parse_response->ptr; NULL != (ns = strchr(s, '\n')); s = ns + 1) {
24152 - char *key, *value;
24156 - /* a good day. Someone has read the specs and is sending a \r\n to us */
24158 - if (ns > p->parse_response->ptr &&
24159 - *(ns-1) == '\r') {
24166 - if (NULL == (value = strchr(s, ':'))) {
24167 - /* we expect: "<key>: <value>\n" */
24171 - key_len = value - key;
24175 - while (*value == ' ' || *value == '\t') value++;
24177 - if (host->mode != FCGI_AUTHORIZER ||
24178 - !(con->http_status == 0 ||
24179 - con->http_status == 200)) {
24180 - /* authorizers shouldn't affect the response headers sent back to the client */
24182 - /* don't forward Status: */
24183 - if (0 != strncasecmp(key, "Status", key_len)) {
24184 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24185 - ds = data_response_init();
24187 - buffer_copy_string_len(ds->key, key, key_len);
24188 - buffer_copy_string(ds->value, value);
24190 - array_insert_unique(con->response.headers, (data_unset *)ds);
24194 - switch(key_len) {
24196 - if (0 == strncasecmp(key, "Date", key_len)) {
24197 - con->parsed_response |= HTTP_DATE;
24201 - if (0 == strncasecmp(key, "Status", key_len)) {
24202 - con->http_status = strtol(value, NULL, 10);
24203 - con->parsed_response |= HTTP_STATUS;
24207 - if (0 == strncasecmp(key, "Location", key_len)) {
24208 - con->parsed_response |= HTTP_LOCATION;
24212 - if (0 == strncasecmp(key, "Connection", key_len)) {
24213 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
24214 - con->parsed_response |= HTTP_CONNECTION;
24218 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
24219 - con->response.content_length = strtol(value, NULL, 10);
24220 - con->parsed_response |= HTTP_CONTENT_LENGTH;
24222 - if (con->response.content_length < 0) con->response.content_length = 0;
24230 - /* CGI/1.1 rev 03 - 7.2.1.2 */
24231 - if ((con->parsed_response & HTTP_LOCATION) &&
24232 - !(con->parsed_response & HTTP_STATUS)) {
24233 - con->http_status = 302;
24245 @@ -2327,9 +2225,9 @@
24249 - /* we have at least a header, now check how much me have to fetch */
24250 + /* we have at least a header, now check how much me have to fetch */
24251 header = (FCGI_Header *)(packet->b->ptr);
24254 packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength;
24255 packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8));
24256 packet->type = header->type;
24257 @@ -2348,7 +2246,7 @@
24258 size_t weHave = c->mem->used - c->offset - offset - 1;
24260 if (weHave > weWant) weHave = weWant;
24263 buffer_append_string_len(packet->b, c->mem->ptr + c->offset + offset, weHave);
24265 /* we only skipped the first 8 bytes as they are the fcgi header */
24266 @@ -2380,65 +2278,42 @@
24269 chunkqueue_remove_finished_chunks(hctx->rb);
24275 static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
24281 plugin_data *p = hctx->plugin_data;
24282 connection *con = hctx->remote_conn;
24283 - int fcgi_fd = hctx->fd;
24284 fcgi_extension_host *host= hctx->host;
24285 fcgi_proc *proc = hctx->proc;
24288 - * check how much we have to read
24290 - if (ioctl(hctx->fd, FIONREAD, &toread)) {
24291 - log_error_write(srv, __FILE__, __LINE__, "sd",
24292 - "unexpected end-of-file (perhaps the fastcgi process died):",
24297 - /* init read-buffer */
24299 - if (toread > 0) {
24302 - b = chunkqueue_get_append_buffer(hctx->rb);
24303 - buffer_prepare_copy(b, toread + 1);
24305 - /* append to read-buffer */
24306 - if (-1 == (r = read(hctx->fd, b->ptr, toread))) {
24307 - log_error_write(srv, __FILE__, __LINE__, "sds",
24308 - "unexpected end-of-file (perhaps the fastcgi process died):",
24309 - fcgi_fd, strerror(errno));
24313 - /* this should be catched by the b > 0 above */
24317 - b->used = r + 1; /* one extra for the fake \0 */
24318 - b->ptr[b->used - 1] = '\0';
24320 - log_error_write(srv, __FILE__, __LINE__, "ssdsb",
24321 - "unexpected end-of-file (perhaps the fastcgi process died):",
24322 - "pid:", proc->pid,
24323 - "socket:", proc->connection_name);
24325 + /* in case we read nothing, check the return code
24326 + * if we got something, be happy :)
24328 + * Ok, to be honest:
24329 + * - it is fine to receive a EAGAIN on a second read() call
24330 + * - it might be fine they we get a con-close on a second read() call */
24331 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
24332 + case NETWORK_STATUS_WAIT_FOR_EVENT:
24333 + /* a EAGAIN after we read exactly the chunk-size */
24335 + ERROR("%s", "oops, got a EAGAIN even if we just got call for the event, wired");
24337 + case NETWORK_STATUS_SUCCESS:
24340 + ERROR("reading from fastcgi socket failed (fd=%d)", hctx->sock->fd);
24345 * parse the fastcgi packets and forward the content to the write-queue
24350 fastcgi_response_packet packet;
24352 @@ -2454,92 +2329,136 @@
24354 /* is the header already finished */
24355 if (0 == con->file_started) {
24360 - /* search for header terminator
24362 - * if we start with \r\n check if last packet terminated with \r\n
24363 - * if we start with \n check if last packet terminated with \n
24364 - * search for \r\n\r\n
24365 - * search for \n\n
24368 - if (hctx->response_header->used == 0) {
24369 - buffer_copy_string_buffer(hctx->response_header, packet.b);
24371 - buffer_append_string_buffer(hctx->response_header, packet.b);
24374 - if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) {
24375 - blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4;
24376 - hctx->response_header->used = (c - hctx->response_header->ptr) + 3;
24377 - c += 4; /* point the the start of the response */
24378 - } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) {
24379 - blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2;
24380 - hctx->response_header->used = c - hctx->response_header->ptr + 2;
24381 - c += 2; /* point the the start of the response */
24383 - /* no luck, no header found */
24384 + int have_content_length = 0;
24385 + int need_more = 0;
24388 + /* append the current packet to the chunk queue */
24389 + chunkqueue_append_buffer(hctx->http_rb, packet.b);
24390 + http_response_reset(p->resp);
24392 + switch(http_response_parse_cq(hctx->http_rb, p->resp)) {
24393 + case PARSE_ERROR:
24394 + /* parsing the response header failed */
24396 + con->http_status = 502; /* Bad Gateway */
24399 + case PARSE_NEED_MORE:
24401 + break; /* leave the loop */
24402 + case PARSE_SUCCESS:
24405 + /* should not happen */
24409 - /* parse the response header */
24410 - fcgi_response_parse(srv, con, p, hctx->response_header);
24411 + if (need_more) break;
24413 - con->file_started = 1;
24414 + chunkqueue_remove_finished_chunks(hctx->http_rb);
24416 + con->http_status = p->resp->status;
24417 + hctx->send_content_body = 1;
24419 - if (host->mode == FCGI_AUTHORIZER &&
24420 - (con->http_status == 0 ||
24421 - con->http_status == 200)) {
24422 - /* a authorizer with approved the static request, ignore the content here */
24423 - hctx->send_content_body = 0;
24426 - if (host->allow_xsendfile &&
24427 - NULL != (ds = (data_string *) array_get_element(con->response.headers, "X-LIGHTTPD-send-file"))) {
24428 - stat_cache_entry *sce;
24430 - if (HANDLER_ERROR != stat_cache_get_entry(srv, con, ds->value, &sce)) {
24433 - http_chunk_append_file(srv, con, ds->value, 0, sce->st.st_size);
24434 - hctx->send_content_body = 0; /* ignore the content */
24435 - joblist_append(srv, con);
24436 + /* handle the header fields */
24437 + if (host->mode == FCGI_AUTHORIZER) {
24438 + /* auth mode is a bit different */
24440 + if (con->http_status == 0 ||
24441 + con->http_status == 200) {
24442 + /* a authorizer with approved the static request, ignore the content here */
24443 + hctx->send_content_body = 0;
24447 + /* copy the http-headers */
24448 + for (i = 0; i < p->resp->headers->used; i++) {
24449 + const char *ign[] = { "Status", NULL };
24453 + data_string *header = (data_string *)p->resp->headers->data[i];
24455 + /* ignore all headers in AUTHORIZER mode */
24456 + if (host->mode == FCGI_AUTHORIZER) continue;
24458 + /* some headers are ignored by default */
24459 + for (j = 0; ign[j]; j++) {
24460 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
24462 + if (ign[j]) continue;
24464 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
24465 + /* CGI/1.1 rev 03 - 7.2.1.2 */
24466 + con->http_status = 302;
24467 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
24468 + have_content_length = 1;
24469 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-Sendfile")) ||
24470 + 0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("X-LIGHTTPD-send-file"))) {
24472 + stat_cache_entry *sce;
24474 - if (hctx->send_content_body && blen > 1) {
24475 - /* enable chunked-transfer-encoding */
24476 + if (host->allow_xsendfile &&
24477 + HANDLER_ERROR != stat_cache_get_entry(srv, con, header->value, &sce)) {
24478 + http_chunk_append_file(srv, con, header->value, 0, sce->st.st_size);
24479 + hctx->send_content_body = 0; /* ignore the content */
24481 + joblist_append(srv, con);
24484 + continue; /* ignore header */
24487 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
24488 + ds = data_response_init();
24490 + buffer_copy_string_buffer(ds->key, header->key);
24491 + buffer_copy_string_buffer(ds->value, header->value);
24493 + array_insert_unique(con->response.headers, (data_unset *)ds);
24496 + /* header is complete ... go on with the body */
24498 + con->file_started = 1;
24500 + if (hctx->send_content_body) {
24501 + chunk *c = hctx->http_rb->first;
24503 + /* if we don't have a content-length enable chunked encoding
24506 + * TODO: move this to a later stage in the filter-queue
24508 if (con->request.http_version == HTTP_VERSION_1_1 &&
24509 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24510 + !have_content_length) {
24511 con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24514 - http_chunk_append_mem(srv, con, c, blen);
24515 + /* copy the rest of the data */
24516 + for (c = hctx->http_rb->first; c; c = c->next) {
24517 + if (c->mem->used > 1) {
24518 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
24519 + c->offset = c->mem->used - 1;
24522 + chunkqueue_remove_finished_chunks(hctx->http_rb);
24523 joblist_append(srv, con);
24525 } else if (hctx->send_content_body && packet.b->used > 1) {
24526 - if (con->request.http_version == HTTP_VERSION_1_1 &&
24527 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
24528 - /* enable chunked-transfer-encoding */
24529 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
24532 http_chunk_append_mem(srv, con, packet.b->ptr, packet.b->used);
24533 joblist_append(srv, con);
24537 - log_error_write(srv, __FILE__, __LINE__, "sb",
24538 + log_error_write(srv, __FILE__, __LINE__, "sb",
24539 "FastCGI-stderr:", packet.b);
24543 case FCGI_END_REQUEST:
24544 con->file_finished = 1;
24547 if (host->mode != FCGI_AUTHORIZER ||
24548 !(con->http_status == 0 ||
24549 con->http_status == 200)) {
24550 @@ -2547,39 +2466,39 @@
24551 http_chunk_append_mem(srv, con, NULL, 0);
24552 joblist_append(srv, con);
24559 - log_error_write(srv, __FILE__, __LINE__, "sd",
24560 + log_error_write(srv, __FILE__, __LINE__, "sd",
24561 "FastCGI: header.type not handled: ", packet.type);
24564 buffer_free(packet.b);
24571 static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_host *host) {
24575 for (proc = host->first; proc; proc = proc->next) {
24578 if (p->conf.debug > 2) {
24579 - log_error_write(srv, __FILE__, __LINE__, "sbdddd",
24581 + log_error_write(srv, __FILE__, __LINE__, "sbdddd",
24583 proc->connection_name,
24593 * if the remote side is overloaded, we check back after <n> seconds
24597 switch (proc->state) {
24598 case PROC_STATE_KILLED:
24599 @@ -2592,13 +2511,13 @@
24601 case PROC_STATE_OVERLOADED:
24602 if (srv->cur_ts <= proc->disabled_until) break;
24605 proc->state = PROC_STATE_RUNNING;
24606 host->active_procs++;
24608 - log_error_write(srv, __FILE__, __LINE__, "sbdb",
24609 - "fcgi-server re-enabled:",
24610 - host->host, host->port,
24612 + log_error_write(srv, __FILE__, __LINE__, "sbdb",
24613 + "fcgi-server re-enabled:",
24614 + host->host, host->port,
24617 case PROC_STATE_DIED_WAIT_FOR_PID:
24618 @@ -2606,7 +2525,7 @@
24619 if (!proc->is_local) break;
24621 /* the child should not terminate at all */
24624 switch(waitpid(proc->pid, &status, WNOHANG)) {
24626 /* child is still alive */
24627 @@ -2616,45 +2535,45 @@
24629 if (WIFEXITED(status)) {
24631 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
24632 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
24633 "child exited, pid:", proc->pid,
24634 "status:", WEXITSTATUS(status));
24636 } else if (WIFSIGNALED(status)) {
24637 - log_error_write(srv, __FILE__, __LINE__, "sd",
24638 - "child signaled:",
24639 + log_error_write(srv, __FILE__, __LINE__, "sd",
24640 + "child signaled:",
24643 - log_error_write(srv, __FILE__, __LINE__, "sd",
24644 - "child died somehow:",
24645 + log_error_write(srv, __FILE__, __LINE__, "sd",
24646 + "child died somehow:",
24651 proc->state = PROC_STATE_DIED;
24656 /* fall through if we have a dead proc now */
24657 if (proc->state != PROC_STATE_DIED) break;
24659 case PROC_STATE_DIED:
24660 - /* local proc get restarted by us,
24661 + /* local proc get restarted by us,
24662 * remote ones hopefully by the admin */
24665 if (proc->is_local) {
24666 /* we still have connections bound to this proc,
24667 * let them terminate first */
24668 if (proc->load != 0) break;
24671 /* restart the child */
24674 if (p->conf.debug) {
24675 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
24676 "--- fastcgi spawning",
24677 "\n\tsocket", proc->connection_name,
24678 "\n\tcurrent:", 1, "/", host->min_procs);
24682 if (fcgi_spawn_connection(srv, p, host, proc)) {
24683 log_error_write(srv, __FILE__, __LINE__, "s",
24684 "ERROR: spawning fcgi failed.");
24685 @@ -2662,18 +2581,18 @@
24688 if (srv->cur_ts <= proc->disabled_until) break;
24691 proc->state = PROC_STATE_RUNNING;
24692 host->active_procs++;
24694 - log_error_write(srv, __FILE__, __LINE__, "sb",
24695 - "fcgi-server re-enabled:",
24697 + log_error_write(srv, __FILE__, __LINE__, "sb",
24698 + "fcgi-server re-enabled:",
24699 proc->connection_name);
24709 @@ -2682,19 +2601,19 @@
24710 fcgi_extension_host *host= hctx->host;
24711 connection *con = hctx->remote_conn;
24717 - /* sanity check */
24718 + /* sanity check */
24720 ((!host->host->used || !host->port) && !host->unixsocket->used)) {
24721 - log_error_write(srv, __FILE__, __LINE__, "sxddd",
24722 + log_error_write(srv, __FILE__, __LINE__, "sxddd",
24723 "write-req: error",
24727 host->unixsocket->used);
24730 hctx->proc->disabled_until = srv->cur_ts + 10;
24731 hctx->proc->state = PROC_STATE_DIED;
24733 @@ -2705,12 +2624,12 @@
24734 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
24736 socklen_t socket_error_len = sizeof(socket_error);
24739 /* try to finish the connect() */
24740 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24741 - log_error_write(srv, __FILE__, __LINE__, "ss",
24742 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
24743 + log_error_write(srv, __FILE__, __LINE__, "ss",
24744 "getsockopt failed:", strerror(errno));
24747 hctx->proc->disabled_until = srv->cur_ts + 10;
24748 hctx->proc->state = PROC_STATE_DIED;
24750 @@ -2719,12 +2638,12 @@
24751 if (socket_error != 0) {
24752 if (!hctx->proc->is_local || p->conf.debug) {
24753 /* local procs get restarted */
24756 log_error_write(srv, __FILE__, __LINE__, "sssb",
24757 - "establishing connection failed:", strerror(socket_error),
24758 + "establishing connection failed:", strerror(socket_error),
24759 "socket:", hctx->proc->connection_name);
24763 hctx->proc->disabled_until = srv->cur_ts + 5;
24765 if (hctx->proc->is_local) {
24766 @@ -2732,17 +2651,17 @@
24768 hctx->proc->state = PROC_STATE_DIED;
24772 hctx->proc->state = PROC_STATE_DIED;
24775 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24776 buffer_append_string(p->statuskey, ".died");
24778 status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24781 return HANDLER_ERROR;
24783 - /* go on with preparing the request */
24784 + /* go on with preparing the request */
24785 hctx->state = FCGI_STATE_PREPARE_WRITE;
24788 @@ -2755,14 +2674,14 @@
24789 /* do we have a running process for this host (max-procs) ? */
24792 - for (proc = hctx->host->first;
24793 - proc && proc->state != PROC_STATE_RUNNING;
24794 + for (proc = hctx->host->first;
24795 + proc && proc->state != PROC_STATE_RUNNING;
24796 proc = proc->next);
24799 /* all childs are dead */
24800 if (proc == NULL) {
24801 - hctx->fde_ndx = -1;
24803 + hctx->sock->fde_ndx = -1;
24805 return HANDLER_ERROR;
24808 @@ -2775,50 +2694,50 @@
24811 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
24813 - if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
24815 + if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
24816 if (errno == EMFILE ||
24818 - log_error_write(srv, __FILE__, __LINE__, "sd",
24819 - "wait for fd at connection:", con->fd);
24821 + log_error_write(srv, __FILE__, __LINE__, "sd",
24822 + "wait for fd at connection:", con->sock->fd);
24824 return HANDLER_WAIT_FOR_FD;
24827 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
24829 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
24830 "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
24831 return HANDLER_ERROR;
24833 - hctx->fde_ndx = -1;
24835 + hctx->sock->fde_ndx = -1;
24839 - fdevent_register(srv->ev, hctx->fd, fcgi_handle_fdevent, hctx);
24841 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
24842 - log_error_write(srv, __FILE__, __LINE__, "ss",
24844 + fdevent_register(srv->ev, hctx->sock, fcgi_handle_fdevent, hctx);
24846 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
24847 + log_error_write(srv, __FILE__, __LINE__, "ss",
24848 "fcntl failed:", strerror(errno));
24851 return HANDLER_ERROR;
24855 if (hctx->proc->is_local) {
24856 hctx->pid = hctx->proc->pid;
24860 switch (fcgi_establish_connection(srv, hctx)) {
24861 case CONNECTION_DELAYED:
24862 /* connection is in progress, wait for an event and call getsockopt() below */
24864 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
24867 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
24869 fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
24870 return HANDLER_WAIT_FOR_EVENT;
24871 case CONNECTION_OVERLOADED:
24872 /* cool down the backend, it is overloaded
24875 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24876 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24877 "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:",
24878 "reconnects:", hctx->reconnects,
24879 "load:", host->load);
24880 @@ -2831,7 +2750,7 @@
24881 buffer_append_string(p->statuskey, ".overloaded");
24883 status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
24886 return HANDLER_ERROR;
24887 case CONNECTION_DEAD:
24888 /* we got a hard error from the backend like
24889 @@ -2840,19 +2759,19 @@
24891 * for check if the host is back in 5 seconds
24895 hctx->proc->disabled_until = srv->cur_ts + 5;
24896 if (hctx->proc->is_local) {
24897 hctx->proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
24899 hctx->proc->state = PROC_STATE_DIED;
24902 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24904 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
24905 "backend died, we disable it for a 5 seconds and send the request to another backend instead:",
24906 "reconnects:", hctx->reconnects,
24907 "load:", host->load);
24910 fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
24911 buffer_append_string(p->statuskey, ".died");
24913 @@ -2863,19 +2782,19 @@
24914 /* everything is ok, go on */
24916 fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
24920 case CONNECTION_UNSET:
24925 case FCGI_STATE_PREPARE_WRITE:
24926 /* ok, we have the connection */
24929 hctx->proc->load++;
24930 hctx->proc->last_used = srv->cur_ts;
24931 hctx->got_proc = 1;
24934 status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
24935 status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
24937 @@ -2898,9 +2817,9 @@
24939 if (p->conf.debug) {
24940 log_error_write(srv, __FILE__, __LINE__, "ssdsbsd",
24942 - "pid:", hctx->proc->pid,
24943 - "socket:", hctx->proc->connection_name,
24945 + "pid:", hctx->proc->pid,
24946 + "socket:", hctx->proc->connection_name,
24947 "load:", hctx->proc->load);
24950 @@ -2908,74 +2827,75 @@
24951 if (hctx->request_id == 0) {
24952 hctx->request_id = fcgi_requestid_new(srv, p);
24954 - log_error_write(srv, __FILE__, __LINE__, "sd",
24955 + log_error_write(srv, __FILE__, __LINE__, "sd",
24956 "fcgi-request is already in use:", hctx->request_id);
24961 fcgi_create_env(srv, hctx, hctx->request_id);
24964 fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
24968 case FCGI_STATE_WRITE:
24969 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
24970 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
24972 chunkqueue_remove_finished_chunks(hctx->wb);
24978 - /* the connection got dropped after accept()
24980 - * this is most of the time a PHP which dies
24981 + /* the connection got dropped after accept()
24983 + * this is most of the time a PHP which dies
24984 * after PHP_FCGI_MAX_REQUESTS
24989 if (hctx->wb->bytes_out == 0 &&
24990 hctx->reconnects < 5) {
24991 - usleep(10000); /* take away the load of the webserver
24992 - * to let the php a chance to restart
24994 + usleep(10000); /* take away the load of the webserver
24995 + * to let the php a chance to restart
24999 fcgi_reconnect(srv, hctx);
25002 return HANDLER_WAIT_FOR_FD;
25006 /* not reconnected ... why
25009 * far@#lighttpd report this for FreeBSD
25014 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
25016 + log_error_write(srv, __FILE__, __LINE__, "ssosd",
25017 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
25018 "write-offset:", hctx->wb->bytes_out,
25019 "reconnect attempts:", hctx->reconnects);
25022 return HANDLER_ERROR;
25025 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25027 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25029 return HANDLER_WAIT_FOR_EVENT;
25031 - log_error_write(srv, __FILE__, __LINE__, "ssd",
25032 + log_error_write(srv, __FILE__, __LINE__, "ssd",
25033 "write failed:", strerror(errno), errno);
25036 return HANDLER_ERROR;
25040 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
25041 /* we don't need the out event anymore */
25042 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
25043 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25044 + fdevent_event_del(srv->ev, hctx->sock);
25045 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25046 fcgi_set_state(srv, hctx, FCGI_STATE_READ);
25048 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25050 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25052 return HANDLER_WAIT_FOR_EVENT;
25055 @@ -2987,7 +2907,7 @@
25056 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
25057 return HANDLER_ERROR;
25061 return HANDLER_WAIT_FOR_EVENT;
25064 @@ -2996,18 +2916,18 @@
25066 SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
25067 plugin_data *p = p_d;
25070 handler_ctx *hctx = con->plugin_ctx[p->id];
25072 fcgi_extension_host *host;
25075 if (NULL == hctx) return HANDLER_GO_ON;
25079 if (con->mode != p->id) return HANDLER_GO_ON;
25081 /* we don't have a host yet, choose one
25082 - * -> this happens in the first round
25083 + * -> this happens in the first round
25084 * and when the host died and we have to select a new one */
25085 if (hctx->host == NULL) {
25087 @@ -3016,23 +2936,23 @@
25088 /* get best server */
25089 for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
25090 host = hctx->ext->hosts[k];
25093 /* we should have at least one proc that can do something */
25094 if (host->active_procs == 0) continue;
25096 if (used == -1 || host->load < used) {
25105 /* found a server */
25107 /* all hosts are down */
25109 fcgi_connection_close(srv, hctx);
25112 con->http_status = 500;
25113 con->mode = DIRECT;
25115 @@ -3040,16 +2960,16 @@
25118 host = hctx->ext->hosts[ndx];
25121 - * if check-local is disabled, use the uri.path handler
25125 + * if check-local is disabled, use the uri.path handler
25130 /* init handler-context */
25133 - /* we put a connection on this host, move the other new connections to other hosts
25134 + /* we put a connection on this host, move the other new connections to other hosts
25136 * as soon as hctx->host is unassigned, decrease the load again */
25137 hctx->host->load++;
25138 @@ -3063,7 +2983,7 @@
25139 case HANDLER_ERROR:
25144 if (hctx->state == FCGI_STATE_INIT ||
25145 hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25146 if (proc) host->active_procs--;
25147 @@ -3078,7 +2998,7 @@
25148 return HANDLER_WAIT_FOR_FD;
25150 fcgi_connection_close(srv, hctx);
25153 buffer_reset(con->physical.path);
25154 con->mode = DIRECT;
25155 con->http_status = 500;
25156 @@ -3088,12 +3008,12 @@
25159 fcgi_connection_close(srv, hctx);
25162 buffer_reset(con->physical.path);
25163 con->mode = DIRECT;
25164 con->http_status = 503;
25165 joblist_append(srv, con); /* really ? */
25168 return HANDLER_FINISHED;
25170 case HANDLER_WAIT_FOR_EVENT:
25171 @@ -3115,7 +3035,7 @@
25172 handler_ctx *hctx = ctx;
25173 connection *con = hctx->remote_conn;
25174 plugin_data *p = hctx->plugin_data;
25177 fcgi_proc *proc = hctx->proc;
25178 fcgi_extension_host *host= hctx->host;
25180 @@ -3125,8 +3045,8 @@
25185 - if (host->mode == FCGI_AUTHORIZER &&
25187 + if (host->mode == FCGI_AUTHORIZER &&
25188 (con->http_status == 200 ||
25189 con->http_status == 0)) {
25191 @@ -3136,26 +3056,26 @@
25194 buffer_copy_string_buffer(con->physical.doc_root, host->docroot);
25197 buffer_copy_string_buffer(con->physical.path, host->docroot);
25198 buffer_append_string_buffer(con->physical.path, con->uri.path);
25199 fcgi_connection_close(srv, hctx);
25202 con->mode = DIRECT;
25203 con->file_started = 1; /* fcgi_extension won't touch the request afterwards */
25206 fcgi_connection_close(srv, hctx);
25210 joblist_append(srv, con);
25211 return HANDLER_FINISHED;
25213 if (proc->pid && proc->state != PROC_STATE_DIED) {
25217 /* only fetch the zombie if it is not already done */
25220 switch(waitpid(proc->pid, &status, WNOHANG)) {
25222 /* child is still alive */
25223 @@ -3165,60 +3085,61 @@
25225 /* the child should not terminate at all */
25226 if (WIFEXITED(status)) {
25227 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
25228 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
25229 "child exited, pid:", proc->pid,
25230 "status:", WEXITSTATUS(status));
25231 } else if (WIFSIGNALED(status)) {
25232 - log_error_write(srv, __FILE__, __LINE__, "sd",
25233 - "child signaled:",
25234 + log_error_write(srv, __FILE__, __LINE__, "sd",
25235 + "child signaled:",
25238 - log_error_write(srv, __FILE__, __LINE__, "sd",
25239 - "child died somehow:",
25240 + log_error_write(srv, __FILE__, __LINE__, "sd",
25241 + "child died somehow:",
25246 if (p->conf.debug) {
25247 log_error_write(srv, __FILE__, __LINE__, "ssbsdsd",
25248 "--- fastcgi spawning",
25249 "\n\tsocket", proc->connection_name,
25250 "\n\tcurrent:", 1, "/", host->min_procs);
25254 if (fcgi_spawn_connection(srv, p, host, proc)) {
25255 /* respawning failed, retry later */
25256 proc->state = PROC_STATE_DIED;
25258 - log_error_write(srv, __FILE__, __LINE__, "s",
25259 + log_error_write(srv, __FILE__, __LINE__, "s",
25260 "respawning failed, will retry later");
25269 if (con->file_started == 0) {
25270 /* nothing has been send out yet, try to use another child */
25273 if (hctx->wb->bytes_out == 0 &&
25274 hctx->reconnects < 5) {
25275 fcgi_reconnect(srv, hctx);
25277 - log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25279 + log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25280 "response not received, request not sent",
25281 - "on socket:", proc->connection_name,
25282 + "on socket:", proc->connection_name,
25283 "for", con->uri.path, ", reconnecting");
25286 return HANDLER_WAIT_FOR_FD;
25289 - log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25291 + log_error_write(srv, __FILE__, __LINE__, "sosbsbs",
25292 "response not received, request sent:", hctx->wb->bytes_out,
25293 - "on socket:", proc->connection_name,
25294 + "on socket:", proc->connection_name,
25295 "for", con->uri.path, ", closing connection");
25298 fcgi_connection_close(srv, hctx);
25301 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
25302 buffer_reset(con->physical.path);
25303 con->http_status = 500;
25304 @@ -3226,76 +3147,76 @@
25306 /* response might have been already started, kill the connection */
25307 fcgi_connection_close(srv, hctx);
25309 - log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25311 + log_error_write(srv, __FILE__, __LINE__, "ssbsbs",
25312 "response already sent out, but backend returned error",
25313 - "on socket:", proc->connection_name,
25314 + "on socket:", proc->connection_name,
25315 "for", con->uri.path, ", terminating connection");
25318 connection_set_state(srv, con, CON_STATE_ERROR);
25326 joblist_append(srv, con);
25327 return HANDLER_FINISHED;
25332 if (revents & FDEVENT_OUT) {
25333 if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
25334 hctx->state == FCGI_STATE_WRITE) {
25335 /* we are allowed to send something out
25338 * 1. in a unfinished connect() call
25339 * 2. in a unfinished write() call (long POST request)
25341 return mod_fastcgi_handle_subrequest(srv, con, p);
25343 - log_error_write(srv, __FILE__, __LINE__, "sd",
25344 - "got a FDEVENT_OUT and didn't know why:",
25345 + log_error_write(srv, __FILE__, __LINE__, "sd",
25346 + "got a FDEVENT_OUT and didn't know why:",
25352 /* perhaps this issue is already handled */
25353 if (revents & FDEVENT_HUP) {
25354 if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
25355 /* getoptsock will catch this one (right ?)
25357 - * if we are in connect we might get a EINPROGRESS
25358 - * in the first call and a FDEVENT_HUP in the
25360 + * if we are in connect we might get a EINPROGRESS
25361 + * in the first call and a FDEVENT_HUP in the
25365 * FIXME: as it is a bit ugly.
25369 return mod_fastcgi_handle_subrequest(srv, con, p);
25370 } else if (hctx->state == FCGI_STATE_READ &&
25371 hctx->proc->port == 0) {
25375 * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
25376 * even if the FCGI_FIN packet is not received yet
25379 - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25380 - "error: unexpected close of fastcgi connection for",
25381 + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
25382 + "error: unexpected close of fastcgi connection for",
25384 - "(no fastcgi process on host:",
25385 + "(no fastcgi process on host:",
25394 connection_set_state(srv, con, CON_STATE_ERROR);
25395 fcgi_connection_close(srv, hctx);
25396 joblist_append(srv, con);
25398 } else if (revents & FDEVENT_ERR) {
25399 - log_error_write(srv, __FILE__, __LINE__, "s",
25400 + log_error_write(srv, __FILE__, __LINE__, "s",
25401 "fcgi: got a FDEVENT_ERR. Don't know why.");
25402 /* kill all connections to the fastcgi process */
25404 @@ -3304,45 +3225,42 @@
25405 fcgi_connection_close(srv, hctx);
25406 joblist_append(srv, con);
25410 return HANDLER_FINISHED;
25412 -#define PATCH(x) \
25413 - p->conf.x = s->x;
25415 static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
25417 plugin_config *s = p->config_storage[0];
25421 - PATCH(ext_mapping);
25424 + PATCH_OPTION(exts);
25425 + PATCH_OPTION(debug);
25426 + PATCH_OPTION(ext_mapping);
25428 /* skip the first, the global context */
25429 for (i = 1; i < srv->config_context->used; i++) {
25430 data_config *dc = (data_config *)srv->config_context->data[i];
25431 s = p->config_storage[i];
25434 /* condition didn't match */
25435 if (!config_check_cond(srv, con, dc)) continue;
25439 for (j = 0; j < dc->value->used; j++) {
25440 data_unset *du = dc->value->data[j];
25443 if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.server"))) {
25445 + PATCH_OPTION(exts);
25446 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.debug"))) {
25448 + PATCH_OPTION(debug);
25449 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("fastcgi.map-extensions"))) {
25450 - PATCH(ext_mapping);
25451 + PATCH_OPTION(ext_mapping);
25462 static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
25463 plugin_data *p = p_d;
25464 @@ -3351,16 +3269,16 @@
25466 fcgi_extension *extension = NULL;
25467 fcgi_extension_host *host = NULL;
25470 /* Possibly, we processed already this request */
25471 if (con->file_started == 1) return HANDLER_GO_ON;
25473 fn = uri_path_handler ? con->uri.path : con->physical.path;
25475 if (buffer_is_empty(fn)) return HANDLER_GO_ON;
25478 s_len = fn->used - 1;
25481 fcgi_patch_connection(srv, con, p);
25483 /* fastcgi.map-extensions maps extensions to existing fastcgi.server entries
25484 @@ -3368,24 +3286,24 @@
25485 * fastcgi.map-extensions = ( ".php3" => ".php" )
25487 * fastcgi.server = ( ".php" => ... )
25492 /* check if extension-mapping matches */
25493 for (k = 0; k < p->conf.ext_mapping->used; k++) {
25494 data_string *ds = (data_string *)p->conf.ext_mapping->data[k];
25495 size_t ct_len; /* length of the config entry */
25498 if (ds->key->used == 0) continue;
25501 ct_len = ds->key->used - 1;
25504 if (s_len < ct_len) continue;
25507 /* found a mapping */
25508 if (0 == strncmp(fn->ptr + s_len - ct_len, ds->key->ptr, ct_len)) {
25509 /* check if we know the extension */
25512 /* we can reuse k here */
25513 for (k = 0; k < p->conf.exts->used; k++) {
25514 extension = p->conf.exts->exts[k];
25515 @@ -3407,15 +3325,15 @@
25516 /* check if extension matches */
25517 for (k = 0; k < p->conf.exts->used; k++) {
25518 size_t ct_len; /* length of the config entry */
25521 extension = p->conf.exts->exts[k];
25524 if (extension->key->used == 0) continue;
25527 ct_len = extension->key->used - 1;
25530 if (s_len < ct_len) continue;
25533 /* check extension in the form "/fcgi_pattern" */
25534 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
25536 @@ -3441,10 +3359,10 @@
25540 - /* we found one host that is alive */
25541 + /* we found one host that is alive */
25547 /* sorry, we don't have a server alive for this ext */
25548 buffer_reset(con->physical.path);
25549 @@ -3459,72 +3377,72 @@
25550 "on", extension->key,
25555 return HANDLER_FINISHED;
25558 /* a note about no handler is not sent yey */
25559 extension->note_is_sent = 0;
25562 - * if check-local is disabled, use the uri.path handler
25565 + * if check-local is disabled, use the uri.path handler
25570 /* init handler-context */
25571 if (uri_path_handler) {
25572 if (host->check_local == 0) {
25577 hctx = handler_ctx_init();
25580 hctx->remote_conn = con;
25581 hctx->plugin_data = p;
25583 hctx->ext = extension;
25587 hctx->conf.exts = p->conf.exts;
25588 hctx->conf.debug = p->conf.debug;
25591 con->plugin_ctx[p->id] = hctx;
25597 if (con->conf.log_request_handling) {
25598 - log_error_write(srv, __FILE__, __LINE__, "s",
25599 + log_error_write(srv, __FILE__, __LINE__, "s",
25600 "handling it in mod_fastcgi");
25603 - /* the prefix is the SCRIPT_NAME,
25605 + /* the prefix is the SCRIPT_NAME,
25606 * everthing from start to the next slash
25607 * this is important for check-local = "disable"
25610 * if prefix = /admin.fcgi
25613 * /admin.fcgi/foo/bar
25616 * SCRIPT_NAME = /admin.fcgi
25617 * PATH_INFO = /foo/bar
25620 * if prefix = /fcgi-bin/
25623 * /fcgi-bin/foo/bar
25626 * SCRIPT_NAME = /fcgi-bin/foo
25633 /* the rewrite is only done for /prefix/? matches */
25634 if (extension->key->ptr[0] == '/' &&
25635 con->uri.path->used > extension->key->used &&
25636 NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
25637 - /* rewrite uri.path and pathinfo */
25639 + /* rewrite uri.path and pathinfo */
25641 buffer_copy_string(con->request.pathinfo, pathinfo);
25644 con->uri.path->used -= con->request.pathinfo->used - 1;
25645 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
25647 @@ -3532,19 +3450,19 @@
25650 hctx = handler_ctx_init();
25653 hctx->remote_conn = con;
25654 hctx->plugin_data = p;
25656 hctx->ext = extension;
25659 hctx->conf.exts = p->conf.exts;
25660 hctx->conf.debug = p->conf.debug;
25663 con->plugin_ctx[p->id] = hctx;
25669 if (con->conf.log_request_handling) {
25670 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
25672 @@ -3566,19 +3484,19 @@
25673 JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
25674 plugin_data *p = p_d;
25675 handler_ctx *hctx = con->plugin_ctx[p->id];
25678 if (hctx == NULL) return HANDLER_GO_ON;
25680 - if (hctx->fd != -1) {
25681 + if (hctx->sock->fd != -1) {
25682 switch (hctx->state) {
25683 case FCGI_STATE_READ:
25684 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
25686 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
25689 case FCGI_STATE_CONNECT_DELAYED:
25690 case FCGI_STATE_WRITE:
25691 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
25693 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
25696 case FCGI_STATE_INIT:
25698 @@ -3595,7 +3513,7 @@
25700 static handler_t fcgi_connection_close_callback(server *srv, connection *con, void *p_d) {
25701 plugin_data *p = p_d;
25704 fcgi_connection_close(srv, con->plugin_ctx[p->id]);
25706 return HANDLER_GO_ON;
25707 @@ -3604,16 +3522,39 @@
25708 TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
25709 plugin_data *p = p_d;
25715 /* perhaps we should kill a connect attempt after 10-15 seconds
25718 * currently we wait for the TCP timeout which is on Linux 180 seconds
25725 + for (i = 0; i < srv->conns->used; i++) {
25726 + connection *con = srv->conns->ptr[i];
25727 + handler_ctx *hctx = con->plugin_ctx[p->id];
25729 + /* if a connection is ours and is in handle-req for more than max-request-time
25730 + * kill the connection */
25732 + if (con->mode != p->id) continue;
25733 + if (con->state != CON_STATE_HANDLE_REQUEST) continue;
25734 + if (srv->cur_ts < con->request_start + 60) continue;
25736 + /* the request is waiting for a FCGI_STDOUT since 60 seconds */
25738 + /* kill the connection */
25740 + log_error_write(srv, __FILE__, __LINE__, "s", "fastcgi backend didn't responded after 60 seconds");
25742 + fcgi_connection_close(srv, hctx);
25744 + con->mode = DIRECT;
25745 + con->http_status = 500;
25747 + joblist_append(srv, con);
25750 /* check all childs if they are still up */
25752 for (i = 0; i < srv->config_context->used; i++) {
25753 @@ -3628,45 +3569,45 @@
25754 fcgi_extension *ex;
25756 ex = exts->exts[j];
25759 for (n = 0; n < ex->used; n++) {
25763 unsigned long sum_load = 0;
25764 fcgi_extension_host *host;
25767 host = ex->hosts[n];
25770 fcgi_restart_dead_procs(srv, p, host);
25773 for (proc = host->first; proc; proc = proc->next) {
25774 sum_load += proc->load;
25778 if (host->num_procs &&
25779 host->num_procs < host->max_procs &&
25780 (sum_load / host->num_procs) > host->max_load_per_proc) {
25781 /* overload, spawn new child */
25782 if (p->conf.debug) {
25783 - log_error_write(srv, __FILE__, __LINE__, "s",
25784 + log_error_write(srv, __FILE__, __LINE__, "s",
25785 "overload detected, spawning a new child");
25789 for (proc = host->unused_procs; proc && proc->pid != 0; proc = proc->next);
25793 if (proc == host->unused_procs) host->unused_procs = proc->next;
25796 if (proc->next) proc->next->prev = NULL;
25801 proc = fastcgi_process_init();
25802 proc->id = host->max_id++;
25809 if (buffer_is_empty(host->unixsocket)) {
25810 proc->port = host->port + proc->id;
25812 @@ -3674,13 +3615,13 @@
25813 buffer_append_string(proc->unixsocket, "-");
25814 buffer_append_long(proc->unixsocket, proc->id);
25818 if (fcgi_spawn_connection(srv, p, host, proc)) {
25819 log_error_write(srv, __FILE__, __LINE__, "s",
25820 "ERROR: spawning fcgi failed.");
25821 return HANDLER_ERROR;
25826 proc->next = host->first;
25828 @@ -3688,56 +3629,56 @@
25830 host->first = proc;
25834 for (proc = host->first; proc; proc = proc->next) {
25835 if (proc->load != 0) break;
25836 if (host->num_procs <= host->min_procs) break;
25837 if (proc->pid == 0) continue;
25840 if (srv->cur_ts - proc->last_used > host->idle_timeout) {
25841 /* a proc is idling for a long time now,
25845 if (p->conf.debug) {
25846 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25847 - "idle-timeout reached, terminating child:",
25848 - "socket:", proc->connection_name,
25849 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25850 + "idle-timeout reached, terminating child:",
25851 + "socket:", proc->connection_name,
25858 if (proc->next) proc->next->prev = proc->prev;
25859 if (proc->prev) proc->prev->next = proc->next;
25862 if (proc->prev == NULL) host->first = proc->next;
25866 proc->next = host->unused_procs;
25869 if (host->unused_procs) host->unused_procs->prev = proc;
25870 host->unused_procs = proc;
25873 kill(proc->pid, SIGTERM);
25876 proc->state = PROC_STATE_KILLED;
25878 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25880 - "socket:", proc->connection_name,
25882 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
25884 + "socket:", proc->connection_name,
25891 /* proc is now in unused, let the next second handle the next process */
25898 for (proc = host->unused_procs; proc; proc = proc->next) {
25902 if (proc->pid == 0) continue;
25905 switch (waitpid(proc->pid, &status, WNOHANG)) {
25907 /* child still running after timeout, good */
25908 @@ -3745,10 +3686,10 @@
25910 if (errno != EINTR) {
25911 /* no PID found ? should never happen */
25912 - log_error_write(srv, __FILE__, __LINE__, "sddss",
25913 + log_error_write(srv, __FILE__, __LINE__, "sddss",
25914 "pid ", proc->pid, proc->state,
25915 "not found:", strerror(errno));
25919 if (errno == ECHILD) {
25920 /* someone else has cleaned up for us */
25921 @@ -3762,25 +3703,26 @@
25922 /* the child should not terminate at all */
25923 if (WIFEXITED(status)) {
25924 if (proc->state != PROC_STATE_KILLED) {
25925 - log_error_write(srv, __FILE__, __LINE__, "sdb",
25927 + log_error_write(srv, __FILE__, __LINE__, "sdb",
25929 WEXITSTATUS(status), proc->connection_name);
25931 } else if (WIFSIGNALED(status)) {
25932 if (WTERMSIG(status) != SIGTERM) {
25933 - log_error_write(srv, __FILE__, __LINE__, "sd",
25934 - "child signaled:",
25935 + log_error_write(srv, __FILE__, __LINE__, "sd",
25936 + "child signaled:",
25940 - log_error_write(srv, __FILE__, __LINE__, "sd",
25941 - "child died somehow:",
25942 + log_error_write(srv, __FILE__, __LINE__, "sd",
25943 + "child died somehow:",
25947 proc->state = PROC_STATE_UNSET;
25954 @@ -3804,8 +3746,8 @@
25955 p->handle_subrequest = mod_fastcgi_handle_subrequest;
25956 p->handle_joblist = mod_fastcgi_handle_joblist;
25957 p->handle_trigger = mod_fastcgi_handle_trigger;
25965 --- ../lighttpd-1.4.11/src/mod_flv_streaming.c 2006-03-07 14:06:26.000000000 +0200
25966 +++ lighttpd-1.4.12/src/mod_flv_streaming.c 2006-07-16 00:26:04.000000000 +0300
25967 @@ -23,35 +23,35 @@
25977 plugin_config **config_storage;
25979 - plugin_config conf;
25981 + plugin_config conf;
25984 /* init the plugin data */
25985 INIT_FUNC(mod_flv_streaming_init) {
25989 p = calloc(1, sizeof(*p));
25992 p->query_str = buffer_init();
25993 p->get_params = array_init();
25999 /* detroy the plugin data */
26000 FREE_FUNC(mod_flv_streaming_free) {
26001 plugin_data *p = p_d;
26006 if (!p) return HANDLER_GO_ON;
26009 if (p->config_storage) {
26012 @@ -59,19 +59,19 @@
26013 plugin_config *s = p->config_storage[i];
26018 array_free(s->extensions);
26023 free(p->config_storage);
26027 buffer_free(p->query_str);
26028 array_free(p->get_params);
26034 return HANDLER_GO_ON;
26037 @@ -80,83 +80,80 @@
26038 SETDEFAULTS_FUNC(mod_flv_streaming_set_defaults) {
26039 plugin_data *p = p_d;
26042 - config_values_t cv[] = {
26044 + config_values_t cv[] = {
26045 { "flv-streaming.extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
26046 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26050 if (!p) return HANDLER_ERROR;
26053 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26056 for (i = 0; i < srv->config_context->used; i++) {
26060 s = calloc(1, sizeof(plugin_config));
26061 s->extensions = array_init();
26064 cv[0].destination = s->extensions;
26067 p->config_storage[i] = s;
26070 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26071 return HANDLER_ERROR;
26076 return HANDLER_GO_ON;
26079 -#define PATCH(x) \
26080 - p->conf.x = s->x;
26081 static int mod_flv_streaming_patch_connection(server *srv, connection *con, plugin_data *p) {
26083 plugin_config *s = p->config_storage[0];
26085 - PATCH(extensions);
26088 + PATCH_OPTION(extensions);
26090 /* skip the first, the global context */
26091 for (i = 1; i < srv->config_context->used; i++) {
26092 data_config *dc = (data_config *)srv->config_context->data[i];
26093 s = p->config_storage[i];
26096 /* condition didn't match */
26097 if (!config_check_cond(srv, con, dc)) continue;
26101 for (j = 0; j < dc->value->used; j++) {
26102 data_unset *du = dc->value->data[j];
26105 if (buffer_is_equal_string(du->key, CONST_STR_LEN("flv-streaming.extensions"))) {
26106 - PATCH(extensions);
26107 + PATCH_OPTION(extensions);
26117 -static int split_get_params(server *srv, connection *con, array *get_params, buffer *qrystr) {
26118 +static int split_get_params(array *get_params, buffer *qrystr) {
26121 char *key = NULL, *val = NULL;
26127 /* we need the \0 */
26128 for (i = 0; i < qrystr->used; i++) {
26129 switch(qrystr->ptr[i]) {
26132 val = qrystr->ptr + i + 1;
26135 qrystr->ptr[i] = '\0';
26144 case '\0': /* fin symbol */
26145 @@ -167,7 +164,7 @@
26146 /* terminate the value */
26147 qrystr->ptr[i] = '\0';
26149 - if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
26150 + if (NULL == (ds = (data_string *)array_get_unused_element(get_params, TYPE_STRING))) {
26151 ds = data_string_init();
26153 buffer_copy_string_len(ds->key, key, strlen(key));
26154 @@ -175,14 +172,14 @@
26156 array_insert_unique(get_params, (data_unset *)ds);
26160 key = qrystr->ptr + i + 1;
26171 @@ -190,34 +187,34 @@
26172 plugin_data *p = p_d;
26179 if (buffer_is_empty(con->physical.path)) return HANDLER_GO_ON;
26182 mod_flv_streaming_patch_connection(srv, con, p);
26184 s_len = con->physical.path->used - 1;
26187 for (k = 0; k < p->conf.extensions->used; k++) {
26188 data_string *ds = (data_string *)p->conf.extensions->data[k];
26189 int ct_len = ds->value->used - 1;
26192 if (ct_len > s_len) continue;
26193 if (ds->value->used == 0) continue;
26196 if (0 == strncmp(con->physical.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
26197 data_string *get_param;
26198 stat_cache_entry *sce = NULL;
26202 - /* if there is a start=[0-9]+ in the header use it as start,
26203 + /* if there is a start=[0-9]+ in the header use it as start,
26204 * otherwise send the full file */
26206 array_reset(p->get_params);
26207 buffer_copy_string_buffer(p->query_str, con->uri.query);
26208 - split_get_params(srv, con, p->get_params, p->query_str);
26209 + split_get_params(p->get_params, p->query_str);
26211 if (NULL == (get_param = (data_string *)array_get_element(p->get_params, "start"))) {
26212 return HANDLER_GO_ON;
26213 @@ -256,7 +253,7 @@
26214 return HANDLER_FINISHED;
26220 return HANDLER_GO_ON;
26222 @@ -266,13 +263,13 @@
26223 int mod_flv_streaming_plugin_init(plugin *p) {
26224 p->version = LIGHTTPD_VERSION_ID;
26225 p->name = buffer_init_string("flv_streaming");
26228 p->init = mod_flv_streaming_init;
26229 p->handle_physical = mod_flv_streaming_path_handler;
26230 p->set_defaults = mod_flv_streaming_set_defaults;
26231 p->cleanup = mod_flv_streaming_free;
26239 --- ../lighttpd-1.4.11/src/mod_indexfile.c 2005-09-30 01:08:53.000000000 +0300
26240 +++ lighttpd-1.4.12/src/mod_indexfile.c 2006-07-16 00:26:04.000000000 +0300
26243 #include "stat_cache.h"
26245 +#include "sys-strings.h"
26246 +#include "sys-files.h"
26247 /* plugin config for all request/connections */
26250 @@ -20,51 +22,51 @@
26259 plugin_config **config_storage;
26261 - plugin_config conf;
26263 + plugin_config conf;
26266 /* init the plugin data */
26267 INIT_FUNC(mod_indexfile_init) {
26271 p = calloc(1, sizeof(*p));
26274 p->tmp_buf = buffer_init();
26280 /* detroy the plugin data */
26281 FREE_FUNC(mod_indexfile_free) {
26282 plugin_data *p = p_d;
26287 if (!p) return HANDLER_GO_ON;
26290 if (p->config_storage) {
26292 for (i = 0; i < srv->config_context->used; i++) {
26293 plugin_config *s = p->config_storage[i];
26298 array_free(s->indexfiles);
26303 free(p->config_storage);
26307 buffer_free(p->tmp_buf);
26313 return HANDLER_GO_ON;
26316 @@ -73,131 +75,139 @@
26317 SETDEFAULTS_FUNC(mod_indexfile_set_defaults) {
26318 plugin_data *p = p_d;
26321 - config_values_t cv[] = {
26323 + config_values_t cv[] = {
26324 { "index-file.names", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
26325 { "server.indexfiles", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
26326 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26330 if (!p) return HANDLER_ERROR;
26333 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26336 for (i = 0; i < srv->config_context->used; i++) {
26340 s = calloc(1, sizeof(plugin_config));
26341 s->indexfiles = array_init();
26344 cv[0].destination = s->indexfiles;
26345 cv[1].destination = s->indexfiles; /* old name for [0] */
26348 p->config_storage[i] = s;
26351 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
26352 return HANDLER_ERROR;
26357 return HANDLER_GO_ON;
26360 -#define PATCH(x) \
26361 - p->conf.x = s->x;
26362 static int mod_indexfile_patch_connection(server *srv, connection *con, plugin_data *p) {
26364 plugin_config *s = p->config_storage[0];
26366 - PATCH(indexfiles);
26369 + PATCH_OPTION(indexfiles);
26371 /* skip the first, the global context */
26372 for (i = 1; i < srv->config_context->used; i++) {
26373 data_config *dc = (data_config *)srv->config_context->data[i];
26374 s = p->config_storage[i];
26377 /* condition didn't match */
26378 if (!config_check_cond(srv, con, dc)) continue;
26382 for (j = 0; j < dc->value->used; j++) {
26383 data_unset *du = dc->value->data[j];
26386 if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.indexfiles"))) {
26387 - PATCH(indexfiles);
26388 + PATCH_OPTION(indexfiles);
26389 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("index-file.names"))) {
26390 - PATCH(indexfiles);
26391 + PATCH_OPTION(indexfiles);
26401 URIHANDLER_FUNC(mod_indexfile_subrequest) {
26402 plugin_data *p = p_d;
26404 stat_cache_entry *sce = NULL;
26407 if (con->uri.path->used == 0) return HANDLER_GO_ON;
26408 if (con->uri.path->ptr[con->uri.path->used - 2] != '/') return HANDLER_GO_ON;
26411 mod_indexfile_patch_connection(srv, con, p);
26414 + /* is the physical-path really a dir ? */
26415 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
26416 + return HANDLER_GO_ON;
26419 + if (!S_ISDIR(sce->st.st_mode)) {
26420 + return HANDLER_GO_ON;
26423 if (con->conf.log_request_handling) {
26424 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling the request as Indexfile");
26425 log_error_write(srv, __FILE__, __LINE__, "sb", "URI :", con->uri.path);
26431 for (k = 0; k < p->conf.indexfiles->used; k++) {
26432 data_string *ds = (data_string *)p->conf.indexfiles->data[k];
26435 if (ds->value && ds->value->ptr[0] == '/') {
26436 - /* if the index-file starts with a prefix as use this file as
26437 + /* if the index-file starts with a prefix as use this file as
26438 * index-generator */
26439 buffer_copy_string_buffer(p->tmp_buf, con->physical.doc_root);
26441 buffer_copy_string_buffer(p->tmp_buf, con->physical.path);
26442 + PATHNAME_APPEND_SLASH(p->tmp_buf);
26444 buffer_append_string_buffer(p->tmp_buf, ds->value);
26447 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26448 if (errno == EACCES) {
26449 con->http_status = 403;
26450 buffer_reset(con->physical.path);
26453 return HANDLER_FINISHED;
26457 if (errno != ENOENT &&
26458 errno != ENOTDIR) {
26459 /* we have no idea what happend. let's tell the user so. */
26462 con->http_status = 500;
26465 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
26466 "file not found ... or so: ", strerror(errno),
26468 "->", con->physical.path);
26471 buffer_reset(con->physical.path);
26474 return HANDLER_FINISHED;
26480 /* rewrite uri.path to the real path (/ -> /index.php) */
26481 buffer_append_string_buffer(con->uri.path, ds->value);
26482 buffer_copy_string_buffer(con->physical.path, p->tmp_buf);
26485 /* fce is already set up a few lines above */
26488 return HANDLER_GO_ON;
26493 return HANDLER_GO_ON;
26495 @@ -207,13 +217,13 @@
26496 int mod_indexfile_plugin_init(plugin *p) {
26497 p->version = LIGHTTPD_VERSION_ID;
26498 p->name = buffer_init_string("indexfile");
26501 p->init = mod_indexfile_init;
26502 p->handle_subrequest_start = mod_indexfile_subrequest;
26503 p->set_defaults = mod_indexfile_set_defaults;
26504 p->cleanup = mod_indexfile_free;
26512 --- ../lighttpd-1.4.11/src/mod_mysql_vhost.c 2006-01-14 20:35:10.000000000 +0200
26513 +++ lighttpd-1.4.12/src/mod_mysql_vhost.c 2006-07-16 00:26:04.000000000 +0300
26515 -#include <unistd.h>
26519 -#include <strings.h>
26520 +#include <string.h>
26522 #ifdef HAVE_CONFIG_H
26523 #include "config.h"
26526 +#ifdef HAVE_MYSQL_H
26527 +# ifdef HAVE_LIBMYSQL
26528 +# define HAVE_MYSQL
26535 @@ -16,61 +21,40 @@
26538 #include "stat_cache.h"
26539 -#ifdef DEBUG_MOD_MYSQL_VHOST
26542 +#include "sys-files.h"
26545 - * Plugin for lighttpd to use MySQL
26546 - * for domain to directory lookups,
26547 - * i.e virtual hosts (vhosts).
26549 - * Optionally sets fcgi_offset and fcgi_arg
26550 - * in preparation for fcgi.c to handle
26551 - * per-user fcgi chroot jails.
26553 - * /ada@riksnet.se 2004-12-06
26555 +#include "mod_sql_vhost_core.h"
26559 +#define CORE_PLUGIN "mod_sql_vhost_core"
26569 - buffer *hostname;
26570 - unsigned short port;
26574 buffer *mysql_post;
26576 + mod_sql_vhost_core_plugin_config *core;
26579 /* global plugin data */
26587 plugin_config **config_storage;
26589 - plugin_config conf;
26591 + plugin_config conf;
26594 -/* per connection plugin data */
26596 - buffer *server_name;
26597 - buffer *document_root;
26598 - buffer *fcgi_arg;
26599 - unsigned fcgi_offset;
26600 -} plugin_connection_data;
26601 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost);
26603 /* init the plugin data */
26604 INIT_FUNC(mod_mysql_vhost_init) {
26608 p = calloc(1, sizeof(*p));
26610 p->tmp_buf = buffer_init();
26611 @@ -83,144 +67,77 @@
26612 plugin_data *p = p_d;
26617 - log_error_write(srv, __FILE__, __LINE__, "ss",
26618 - "mod_mysql_vhost_cleanup", p ? "yes" : "NO");
26621 if (!p) return HANDLER_GO_ON;
26624 if (p->config_storage) {
26626 for (i = 0; i < srv->config_context->used; i++) {
26627 plugin_config *s = p->config_storage[i];
26632 mysql_close(s->mysql);
26634 - buffer_free(s->mydb);
26635 - buffer_free(s->myuser);
26636 - buffer_free(s->mypass);
26637 - buffer_free(s->mysock);
26639 buffer_free(s->mysql_pre);
26640 buffer_free(s->mysql_post);
26645 free(p->config_storage);
26647 buffer_free(p->tmp_buf);
26651 - return HANDLER_GO_ON;
26654 -/* handle the plugin per connection data */
26655 -static void* mod_mysql_vhost_connection_data(server *srv, connection *con, void *p_d)
26657 - plugin_data *p = p_d;
26658 - plugin_connection_data *c = con->plugin_ctx[p->id];
26663 - log_error_write(srv, __FILE__, __LINE__, "ss",
26664 - "mod_mysql_connection_data", c ? "old" : "NEW");
26668 - c = calloc(1, sizeof(*c));
26670 - c->server_name = buffer_init();
26671 - c->document_root = buffer_init();
26672 - c->fcgi_arg = buffer_init();
26673 - c->fcgi_offset = 0;
26675 - return con->plugin_ctx[p->id] = c;
26678 -/* destroy the plugin per connection data */
26679 -CONNECTION_FUNC(mod_mysql_vhost_handle_connection_close) {
26680 - plugin_data *p = p_d;
26681 - plugin_connection_data *c = con->plugin_ctx[p->id];
26686 - log_error_write(srv, __FILE__, __LINE__, "ss",
26687 - "mod_mysql_vhost_handle_connection_close", c ? "yes" : "NO");
26690 - if (!c) return HANDLER_GO_ON;
26692 - buffer_free(c->server_name);
26693 - buffer_free(c->document_root);
26694 - buffer_free(c->fcgi_arg);
26695 - c->fcgi_offset = 0;
26700 - con->plugin_ctx[p->id] = NULL;
26701 return HANDLER_GO_ON;
26704 /* set configuration values */
26705 SERVER_FUNC(mod_mysql_vhost_set_defaults) {
26706 plugin_data *p = p_d;
26707 + mod_sql_vhost_core_plugin_data *core_config;
26712 - config_values_t cv[] = {
26713 - { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26714 - { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26715 - { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26716 - { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26717 - { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
26718 - { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER },
26719 - { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER },
26720 - { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
26723 + /* our very own plugin storage, one entry for each conditional
26725 + * srv->config_context->used is the number of conditionals
26727 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
26730 + /* get the config of the core-plugin */
26731 + core_config = plugin_get_config(srv, CORE_PLUGIN);
26734 + /* walk through all conditionals and check for assignments */
26735 for (i = 0; i < srv->config_context->used; i++) {
26742 + /* get the config from the core plugin for this conditional-context */
26743 s = calloc(1, sizeof(plugin_config));
26744 - s->mydb = buffer_init();
26745 - s->myuser = buffer_init();
26746 - s->mypass = buffer_init();
26747 - s->mysock = buffer_init();
26748 - s->hostname = buffer_init();
26749 - s->port = 0; /* default port for mysql */
26750 - sel = buffer_init();
26753 + s->core = core_config->config_storage[i];
26757 s->mysql_pre = buffer_init();
26758 s->mysql_post = buffer_init();
26760 - cv[0].destination = s->mydb;
26761 - cv[1].destination = s->myuser;
26762 - cv[2].destination = s->mypass;
26763 - cv[3].destination = s->mysock;
26764 - cv[4].destination = sel;
26765 - cv[5].destination = s->hostname;
26766 - cv[6].destination = &(s->port);
26769 p->config_storage[i] = s;
26771 - if (config_insert_values_global(srv,
26772 - ((data_config *)srv->config_context->data[i])->value,
26773 - cv)) return HANDLER_ERROR;
26775 - s->mysql_pre = buffer_init();
26776 - s->mysql_post = buffer_init();
26779 + /* check if we are the plugin for this backend */
26780 + if (!buffer_is_equal_string(s->core->backend, CONST_STR_LEN("mysql"))) continue;
26782 + /* attach us to the core-plugin */
26783 + s->core->backend_data = p;
26784 + s->core->get_vhost = mod_mysql_vhost_get_vhost;
26786 + sel = buffer_init();
26787 + buffer_copy_string_buffer(sel, s->core->select_vhost);
26789 if (sel->used && (qmark = index(sel->ptr, '?'))) {
26791 buffer_copy_string(s->mysql_pre, sel->ptr);
26792 @@ -228,35 +145,35 @@
26794 buffer_copy_string_buffer(s->mysql_pre, sel);
26805 * - password, default: empty
26806 * - socket, default: mysql default
26807 * - hostname, if set overrides socket
26808 * - port, default: 3306
26812 /* all have to be set */
26813 - if (!(buffer_is_empty(s->myuser) ||
26814 - buffer_is_empty(s->mydb))) {
26815 + if (!(buffer_is_empty(s->core->user) ||
26816 + buffer_is_empty(s->core->db))) {
26821 if (NULL == (s->mysql = mysql_init(NULL))) {
26822 log_error_write(srv, __FILE__, __LINE__, "s", "mysql_init() failed, exiting...");
26825 return HANDLER_ERROR;
26827 -#define FOO(x) (s->x->used ? s->x->ptr : NULL)
26829 - if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(myuser), FOO(mypass),
26830 - FOO(mydb), s->port, FOO(mysock), 0)) {
26831 +#define FOO(x) (s->core->x->used ? s->core->x->ptr : NULL)
26833 + if (!mysql_real_connect(s->mysql, FOO(hostname), FOO(user), FOO(pass),
26834 + FOO(db), s->core->port, FOO(sock), 0)) {
26835 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(s->mysql));
26838 return HANDLER_ERROR;
26841 @@ -265,61 +182,47 @@
26842 /* otherwise we cannot be sure that mysql is fd i-1 */
26843 if (-1 == (fd = open("/dev/null", 0))) {
26845 - fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26846 + fcntl(fd-1, F_SETFD, FD_CLOEXEC);
26855 return HANDLER_GO_ON;
26858 -#define PATCH(x) \
26859 - p->conf.x = s->x;
26860 static int mod_mysql_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
26863 plugin_config *s = p->config_storage[0];
26865 - PATCH(mysql_pre);
26866 - PATCH(mysql_post);
26872 + PATCH_OPTION(mysql_pre);
26873 + PATCH_OPTION(mysql_post);
26874 + PATCH_OPTION(mysql);
26876 /* skip the first, the global context */
26877 for (i = 1; i < srv->config_context->used; i++) {
26878 data_config *dc = (data_config *)srv->config_context->data[i];
26879 s = p->config_storage[i];
26882 /* condition didn't match */
26883 if (!config_check_cond(srv, con, dc)) continue;
26885 - /* merge config */
26886 - for (j = 0; j < dc->value->used; j++) {
26887 - data_unset *du = dc->value->data[j];
26889 - if (buffer_is_equal_string(du->key, CONST_STR_LEN("mysql-vhost.sql"))) {
26890 - PATCH(mysql_pre);
26891 - PATCH(mysql_post);
26898 + PATCH_OPTION(mysql);
26899 + PATCH_OPTION(mysql_pre);
26900 + PATCH_OPTION(mysql_post);
26910 -/* handle document root request */
26911 -CONNECTION_FUNC(mod_mysql_vhost_handle_docroot) {
26913 + * get the vhost info from the database
26915 +SQLVHOST_BACKEND_GETVHOST(mod_mysql_vhost_get_vhost) {
26916 plugin_data *p = p_d;
26917 - plugin_connection_data *c;
26918 - stat_cache_entry *sce;
26922 @@ -332,13 +235,6 @@
26924 if (!p->conf.mysql) return HANDLER_GO_ON;
26926 - /* sets up connection data if not done yet */
26927 - c = mod_mysql_vhost_connection_data(srv, con, p_d);
26929 - /* check if cached this connection */
26930 - if (c->server_name->used && /* con->uri.authority->used && */
26931 - buffer_is_equal(c->server_name, con->uri.authority)) goto GO_ON;
26933 /* build and run SQL query */
26934 buffer_copy_string_buffer(p->tmp_buf, p->conf.mysql_pre);
26935 if (p->conf.mysql_post->used) {
26936 @@ -347,77 +243,43 @@
26938 if (mysql_query(p->conf.mysql, p->tmp_buf->ptr)) {
26939 log_error_write(srv, __FILE__, __LINE__, "s", mysql_error(p->conf.mysql));
26942 + mysql_free_result(result);
26943 + return HANDLER_GO_ON;
26945 result = mysql_store_result(p->conf.mysql);
26946 cols = mysql_num_fields(result);
26947 row = mysql_fetch_row(result);
26949 if (!row || cols < 1) {
26950 /* no such virtual host */
26951 mysql_free_result(result);
26952 return HANDLER_GO_ON;
26955 - /* sanity check that really is a directory */
26956 - buffer_copy_string(p->tmp_buf, row[0]);
26957 - BUFFER_APPEND_SLASH(p->tmp_buf);
26959 - if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->tmp_buf, &sce)) {
26960 - log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->tmp_buf);
26963 - if (!S_ISDIR(sce->st.st_mode)) {
26964 - log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->tmp_buf);
26967 + buffer_copy_string(docroot, row[0]);
26969 - /* cache the data */
26970 - buffer_copy_string_buffer(c->server_name, con->uri.authority);
26971 - buffer_copy_string_buffer(c->document_root, p->tmp_buf);
26973 - /* fcgi_offset and fcgi_arg are optional */
26974 - if (cols > 1 && row[1]) {
26975 - c->fcgi_offset = atoi(row[1]);
26977 - if (cols > 2 && row[2]) {
26978 - buffer_copy_string(c->fcgi_arg, row[2]);
26980 - c->fcgi_arg->used = 0;
26983 - c->fcgi_offset = c->fcgi_arg->used = 0;
26985 mysql_free_result(result);
26987 - /* fix virtual server and docroot */
26988 -GO_ON: buffer_copy_string_buffer(con->server_name, c->server_name);
26989 - buffer_copy_string_buffer(con->physical.doc_root, c->document_root);
26992 - log_error_write(srv, __FILE__, __LINE__, "sbbdb",
26993 - result ? "NOT CACHED" : "cached",
26994 - con->server_name, con->physical.doc_root,
26995 - c->fcgi_offset, c->fcgi_arg);
26997 - return HANDLER_GO_ON;
26999 -ERR500: if (result) mysql_free_result(result);
27000 - con->http_status = 500; /* Internal Error */
27001 - return HANDLER_FINISHED;
27002 + return HANDLER_GO_ON;
27005 /* this function is called at dlopen() time and inits the callbacks */
27006 int mod_mysql_vhost_plugin_init(plugin *p) {
27009 p->version = LIGHTTPD_VERSION_ID;
27010 p->name = buffer_init_string("mysql_vhost");
27012 p->init = mod_mysql_vhost_init;
27013 p->cleanup = mod_mysql_vhost_cleanup;
27014 - p->handle_request_done = mod_mysql_vhost_handle_connection_close;
27016 p->set_defaults = mod_mysql_vhost_set_defaults;
27017 - p->handle_docroot = mod_mysql_vhost_handle_docroot;
27019 + ds = data_string_init();
27020 + buffer_copy_string(ds->value, CORE_PLUGIN);
27021 + array_insert_unique(p->required_plugins, (data_unset *)ds);
27026 --- ../lighttpd-1.4.11/src/mod_proxy.c 2006-01-31 13:01:22.000000000 +0200
27027 +++ lighttpd-1.4.12/src/mod_proxy.c 2006-07-18 13:03:40.000000000 +0300
27029 #include <sys/types.h>
27031 -#include <unistd.h>
27034 #include <string.h>
27037 #include "inet_ntop_cache.h"
27039 +#include "network.h"
27041 +#include "http_resp.h"
27048 #include "sys-socket.h"
27049 +#include "sys-files.h"
27050 +#include "sys-strings.h"
27052 #define data_proxy data_fastcgi
27053 #define data_proxy_init data_fastcgi_init
27054 @@ -38,22 +42,25 @@
27055 #define PROXY_RETRY_TIMEOUT 60
27059 - * the proxy module is based on the fastcgi module
27062 + * the proxy module is based on the fastcgi module
27064 * 28.06.2004 Jan Kneschke The first release
27065 * 01.07.2004 Evgeny Rodichev Several bugfixes and cleanups
27066 * - co-ordinate up- and downstream flows correctly (proxy_demux_response
27067 * and proxy_handle_fdevent)
27068 * - correctly transfer upstream http_response_status;
27069 * - some unused structures removed.
27072 * TODO: - delay upstream read if write_queue is too large
27073 * (to prevent memory eating, like in apache). Shoud be
27075 * - persistent connection with upstream servers
27082 PROXY_BALANCE_UNSET,
27083 PROXY_BALANCE_FAIR,
27084 @@ -66,26 +73,33 @@
27087 proxy_balance_t balance;
27089 + array *last_used_backends; /* "extension" : last_used_backend */
27096 buffer *parse_response;
27097 buffer *balance_buf;
27102 + array *ignore_headers;
27104 plugin_config **config_storage;
27107 plugin_config conf;
27111 - PROXY_STATE_INIT,
27112 - PROXY_STATE_CONNECT,
27113 - PROXY_STATE_PREPARE_WRITE,
27114 - PROXY_STATE_WRITE,
27115 - PROXY_STATE_READ,
27116 - PROXY_STATE_ERROR
27118 + PROXY_STATE_INIT,
27119 + PROXY_STATE_CONNECT,
27120 + PROXY_STATE_PREPARE_WRITE,
27121 + PROXY_STATE_WRITE,
27122 + PROXY_STATE_RESPONSE_HEADER,
27123 + PROXY_STATE_RESPONSE_CONTENT,
27124 + PROXY_STATE_ERROR
27125 } proxy_connection_state_t;
27127 enum { PROXY_STDOUT, PROXY_END_REQUEST };
27128 @@ -93,19 +107,16 @@
27130 proxy_connection_state_t state;
27131 time_t state_timestamp;
27136 - buffer *response;
27137 - buffer *response_header;
27141 - int fd; /* fd to the proxy process */
27142 - int fde_ndx; /* index into the fd-event buffer */
27145 + iosocket *fd; /* fd to the proxy process */
27147 size_t path_info_offset; /* start of path_info in uri.path */
27150 connection *remote_conn; /* dump pointer */
27151 plugin_data *plugin_data; /* dump pointer */
27153 @@ -116,69 +127,89 @@
27155 static handler_ctx * handler_ctx_init() {
27156 handler_ctx * hctx;
27160 hctx = calloc(1, sizeof(*hctx));
27163 hctx->state = PROXY_STATE_INIT;
27166 - hctx->response = buffer_init();
27167 - hctx->response_header = buffer_init();
27169 hctx->wb = chunkqueue_init();
27170 + hctx->rb = chunkqueue_init();
27172 + hctx->fd = iosocket_init();
27175 - hctx->fde_ndx = -1;
27180 static void handler_ctx_free(handler_ctx *hctx) {
27181 - buffer_free(hctx->response);
27182 - buffer_free(hctx->response_header);
27183 chunkqueue_free(hctx->wb);
27185 + chunkqueue_free(hctx->rb);
27187 + iosocket_free(hctx->fd);
27192 INIT_FUNC(mod_proxy_init) {
27197 + char *hop2hop_headers[] = {
27204 p = calloc(1, sizeof(*p));
27206 - p->parse_response = buffer_init();
27208 p->balance_buf = buffer_init();
27210 + p->ignore_headers = array_init();
27211 + p->resp = http_response_init();
27213 + for (i = 0; hop2hop_headers[i]; i++) {
27216 + if (NULL == (ds = (data_string *)array_get_unused_element(p->ignore_headers, TYPE_STRING))) {
27217 + ds = data_string_init();
27220 + buffer_copy_string(ds->key, hop2hop_headers[i]);
27221 + buffer_copy_string(ds->value, hop2hop_headers[i]);
27222 + array_insert_unique(p->ignore_headers, (data_unset *)ds);
27229 FREE_FUNC(mod_proxy_free) {
27230 plugin_data *p = p_d;
27235 - buffer_free(p->parse_response);
27236 - buffer_free(p->balance_buf);
27238 if (p->config_storage) {
27240 for (i = 0; i < srv->config_context->used; i++) {
27241 plugin_config *s = p->config_storage[i];
27246 array_free(s->extensions);
27248 + array_free(s->last_used_backends);
27253 free(p->config_storage);
27257 + array_free(p->ignore_headers);
27258 + buffer_free(p->balance_buf);
27259 + http_response_free(p->resp);
27264 return HANDLER_GO_ON;
27267 @@ -186,37 +217,38 @@
27268 plugin_data *p = p_d;
27272 - config_values_t cv[] = {
27274 + config_values_t cv[] = {
27275 { "proxy.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
27276 { "proxy.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
27277 { "proxy.balance", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
27278 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27282 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
27285 for (i = 0; i < srv->config_context->used; i++) {
27290 s = malloc(sizeof(plugin_config));
27291 - s->extensions = array_init();
27292 + s->extensions = array_init();
27293 + s->last_used_backends = array_init();
27297 cv[0].destination = s->extensions;
27298 cv[1].destination = &(s->debug);
27299 cv[2].destination = p->balance_buf;
27301 buffer_reset(p->balance_buf);
27304 p->config_storage[i] = s;
27305 ca = ((data_config *)srv->config_context->data[i])->value;
27308 if (0 != config_insert_values_global(srv, ca, cv)) {
27309 return HANDLER_ERROR;
27313 if (buffer_is_empty(p->balance_buf)) {
27314 s->balance = PROXY_BALANCE_FAIR;
27315 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("fair"))) {
27316 @@ -226,99 +258,99 @@
27317 } else if (buffer_is_equal_string(p->balance_buf, CONST_STR_LEN("hash"))) {
27318 s->balance = PROXY_BALANCE_HASH;
27320 - log_error_write(srv, __FILE__, __LINE__, "sb",
27321 - "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27322 + log_error_write(srv, __FILE__, __LINE__, "sb",
27323 + "proxy.balance has to be one of: fair, round-robin, hash, but not:", p->balance_buf);
27324 return HANDLER_ERROR;
27327 if (NULL != (du = array_get_element(ca, "proxy.server"))) {
27329 data_array *da = (data_array *)du;
27332 if (du->type != TYPE_ARRAY) {
27333 - log_error_write(srv, __FILE__, __LINE__, "sss",
27334 + log_error_write(srv, __FILE__, __LINE__, "sss",
27335 "unexpected type for key: ", "proxy.server", "array of strings");
27338 return HANDLER_ERROR;
27344 * proxy.server = ( "<ext>" => ...,
27349 for (j = 0; j < da->value->used; j++) {
27350 data_array *da_ext = (data_array *)da->value->data[j];
27354 if (da_ext->type != TYPE_ARRAY) {
27355 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
27356 - "unexpected type for key: ", "proxy.server",
27357 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
27358 + "unexpected type for key: ", "proxy.server",
27359 "[", da->value->data[j]->key, "](string)");
27362 return HANDLER_ERROR;
27366 - * proxy.server = ( "<ext>" =>
27367 - * ( "<host>" => ( ... ),
27370 + * proxy.server = ( "<ext>" =>
27371 + * ( "<host>" => ( ... ),
27372 * "<host>" => ( ... )
27379 for (n = 0; n < da_ext->value->used; n++) {
27380 data_array *da_host = (data_array *)da_ext->value->data[n];
27386 - config_values_t pcv[] = {
27388 + config_values_t pcv[] = {
27389 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
27390 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
27391 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
27395 if (da_host->type != TYPE_ARRAY) {
27396 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27397 - "unexpected type for key:",
27399 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
27400 + "unexpected type for key:",
27402 "[", da_ext->value->data[n]->key, "](string)");
27405 return HANDLER_ERROR;
27409 df = data_proxy_init();
27415 buffer_copy_string_buffer(df->key, da_host->key);
27418 pcv[0].destination = df->host;
27419 pcv[1].destination = &(df->port);
27422 if (0 != config_insert_values_internal(srv, da_host->value, pcv)) {
27423 return HANDLER_ERROR;
27427 if (buffer_is_empty(df->host)) {
27428 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27429 - "missing key (string):",
27430 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
27431 + "missing key (string):",
27438 return HANDLER_ERROR;
27442 /* if extension already exists, take it */
27445 if (NULL == (dfa = (data_array *)array_get_element(s->extensions, da_ext->key->ptr))) {
27446 dfa = data_array_init();
27449 buffer_copy_string_buffer(dfa->key, da_ext->key);
27452 array_insert_unique(dfa->value, (data_unset *)df);
27453 array_insert_unique(s->extensions, (data_unset *)dfa);
27455 @@ -328,67 +360,76 @@
27461 return HANDLER_GO_ON;
27464 void proxy_connection_close(server *srv, handler_ctx *hctx) {
27469 if (NULL == hctx) return;
27472 p = hctx->plugin_data;
27473 con = hctx->remote_conn;
27476 if (hctx->fd != -1) {
27477 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
27478 + fdevent_event_del(srv->ev, hctx->fd);
27479 fdevent_unregister(srv->ev, hctx->fd);
27482 + close(hctx->fd->fd);
27487 handler_ctx_free(hctx);
27488 - con->plugin_ctx[p->id] = NULL;
27489 + con->plugin_ctx[p->id] = NULL;
27492 static int proxy_establish_connection(server *srv, handler_ctx *hctx) {
27493 struct sockaddr *proxy_addr;
27494 struct sockaddr_in proxy_addr_in;
27498 plugin_data *p = hctx->plugin_data;
27499 data_proxy *host= hctx->host;
27500 - int proxy_fd = hctx->fd;
27502 + int proxy_fd = hctx->fd->fd;
27504 memset(&proxy_addr, 0, sizeof(proxy_addr));
27507 proxy_addr_in.sin_family = AF_INET;
27508 proxy_addr_in.sin_addr.s_addr = inet_addr(host->host->ptr);
27509 proxy_addr_in.sin_port = htons(host->port);
27510 servlen = sizeof(proxy_addr_in);
27513 proxy_addr = (struct sockaddr *) &proxy_addr_in;
27516 if (-1 == connect(proxy_fd, proxy_addr, servlen)) {
27517 - if (errno == EINPROGRESS || errno == EALREADY) {
27519 + errno = WSAGetLastError();
27523 + case WSAEWOULDBLOCK:
27525 + case EINPROGRESS:
27527 if (p->conf.debug) {
27528 - log_error_write(srv, __FILE__, __LINE__, "sd",
27529 + log_error_write(srv, __FILE__, __LINE__, "sd",
27530 "connect delayed:", proxy_fd);
27537 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
27540 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
27541 "connect failed:", proxy_fd, strerror(errno), errno);
27547 + fprintf(stderr, "%s.%d: connected fd = %d\r\n", __FILE__, __LINE__, proxy_fd);
27548 if (p->conf.debug) {
27549 - log_error_write(srv, __FILE__, __LINE__, "sd",
27550 + log_error_write(srv, __FILE__, __LINE__, "sd",
27551 "connect succeeded: ", proxy_fd);
27554 @@ -396,51 +437,52 @@
27557 void proxy_set_header(connection *con, const char *key, const char *value) {
27558 - data_string *ds_dst;
27559 + data_string *ds_dst;
27561 - if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27562 - ds_dst = data_string_init();
27565 - buffer_copy_string(ds_dst->key, key);
27566 - buffer_copy_string(ds_dst->value, value);
27567 - array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27568 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27569 + ds_dst = data_string_init();
27572 + buffer_copy_string(ds_dst->key, key);
27573 + buffer_copy_string(ds_dst->value, value);
27574 + array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27577 void proxy_append_header(connection *con, const char *key, const char *value) {
27578 - data_string *ds_dst;
27579 + data_string *ds_dst;
27581 - if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27582 - ds_dst = data_string_init();
27585 - buffer_copy_string(ds_dst->key, key);
27586 - buffer_append_string(ds_dst->value, value);
27587 - array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27588 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
27589 + ds_dst = data_string_init();
27592 + buffer_copy_string(ds_dst->key, key);
27593 + buffer_append_string(ds_dst->value, value);
27594 + array_insert_unique(con->request.headers, (data_unset *)ds_dst);
27598 static int proxy_create_env(server *srv, handler_ctx *hctx) {
27602 connection *con = hctx->remote_conn;
27603 + plugin_data *p = hctx->plugin_data;
27609 b = chunkqueue_get_append_buffer(hctx->wb);
27613 buffer_copy_string(b, get_http_method_name(con->request.http_method));
27614 BUFFER_APPEND_STRING_CONST(b, " ");
27617 buffer_append_string_buffer(b, con->request.uri);
27618 BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");
27620 proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
27621 - /* http_host is NOT is just a pointer to a buffer
27622 + /* http_host is NOT is just a pointer to a buffer
27623 * which is NULL if it is not set */
27624 - if (con->request.http_host &&
27625 + if (con->request.http_host &&
27626 !buffer_is_empty(con->request.http_host)) {
27627 proxy_set_header(con, "X-Host", con->request.http_host->ptr);
27629 @@ -449,24 +491,25 @@
27630 /* request header */
27631 for (i = 0; i < con->request.headers->used; i++) {
27635 ds = (data_string *)con->request.headers->data[i];
27637 - if (ds->value->used && ds->key->used) {
27638 - if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27640 - buffer_append_string_buffer(b, ds->key);
27641 - BUFFER_APPEND_STRING_CONST(b, ": ");
27642 - buffer_append_string_buffer(b, ds->value);
27643 - BUFFER_APPEND_STRING_CONST(b, "\r\n");
27646 + if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
27648 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
27649 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
27651 + buffer_append_string_buffer(b, ds->key);
27652 + BUFFER_APPEND_STRING_CONST(b, ": ");
27653 + buffer_append_string_buffer(b, ds->value);
27654 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
27658 BUFFER_APPEND_STRING_CONST(b, "\r\n");
27661 hctx->wb->bytes_in += b->used - 1;
27665 if (con->request.content_length) {
27666 chunkqueue *req_cq = con->request_content_queue;
27668 @@ -479,7 +522,7 @@
27670 /* we announce toWrite octects
27671 * now take all the request_content chunk that we need to fill this request
27675 switch (req_c->type) {
27677 @@ -507,223 +550,150 @@
27679 req_c->offset += weHave;
27680 req_cq->bytes_out += weHave;
27683 hctx->wb->bytes_in += weHave;
27700 static int proxy_set_state(server *srv, handler_ctx *hctx, proxy_connection_state_t state) {
27701 hctx->state = state;
27702 hctx->state_timestamp = srv->cur_ts;
27708 -static int proxy_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
27710 - int http_response_status = -1;
27714 - /* \r\n -> \0\0 */
27716 - buffer_copy_string_buffer(p->parse_response, in);
27718 - for (s = p->parse_response->ptr; NULL != (ns = strstr(s, "\r\n")); s = ns + 2) {
27719 - char *key, *value;
27727 - if (-1 == http_response_status) {
27728 - /* The first line of a Response message is the Status-Line */
27730 - for (key=s; *key && *key != ' '; key++);
27733 - http_response_status = (int) strtol(key, NULL, 10);
27734 - if (http_response_status <= 0) http_response_status = 502;
27736 - http_response_status = 502;
27739 - con->http_status = http_response_status;
27740 - con->parsed_response |= HTTP_STATUS;
27744 - if (NULL == (value = strchr(s, ':'))) {
27745 - /* now we expect: "<key>: <value>\n" */
27751 - key_len = value - key;
27755 - while (*value == ' ' || *value == '\t') value++;
27759 - switch(key_len) {
27761 - if (0 == strncasecmp(key, "Date", key_len)) {
27762 - con->parsed_response |= HTTP_DATE;
27766 - if (0 == strncasecmp(key, "Location", key_len)) {
27767 - con->parsed_response |= HTTP_LOCATION;
27771 - if (0 == strncasecmp(key, "Connection", key_len)) {
27776 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
27777 - con->response.content_length = strtol(value, NULL, 10);
27778 - con->parsed_response |= HTTP_CONTENT_LENGTH;
27785 - if (copy_header) {
27786 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27787 - ds = data_response_init();
27789 - buffer_copy_string_len(ds->key, key, key_len);
27790 - buffer_copy_string(ds->value, value);
27792 - array_insert_unique(con->response.headers, (data_unset *)ds);
27800 static int proxy_demux_response(server *srv, handler_ctx *hctx) {
27805 plugin_data *p = hctx->plugin_data;
27806 connection *con = hctx->remote_conn;
27807 - int proxy_fd = hctx->fd;
27809 - /* check how much we have to read */
27810 - if (ioctl(hctx->fd, FIONREAD, &b)) {
27811 - log_error_write(srv, __FILE__, __LINE__, "sd",
27812 - "ioctl failed: ",
27814 + chunkqueue *next_queue = NULL;
27817 + switch(srv->network_backend_read(srv, con, hctx->fd, hctx->rb)) {
27818 + case NETWORK_STATUS_SUCCESS:
27819 + /* we got content */
27821 + case NETWORK_STATUS_WAIT_FOR_EVENT:
27823 + case NETWORK_STATUS_CONNECTION_CLOSE:
27824 + /* we are done, get out of here */
27825 + con->file_finished = 1;
27827 + /* close the chunk-queue with a empty chunk */
27835 + /* looks like we got some content
27837 + * split off the header from the incoming stream
27840 - if (p->conf.debug) {
27841 - log_error_write(srv, __FILE__, __LINE__, "sd",
27842 - "proxy - have to read:", b);
27844 + if (hctx->state == PROXY_STATE_RESPONSE_HEADER) {
27846 + int have_content_length = 0;
27849 - if (hctx->response->used == 0) {
27850 - /* avoid too small buffer */
27851 - buffer_prepare_append(hctx->response, b + 1);
27852 - hctx->response->used = 1;
27854 - buffer_prepare_append(hctx->response, hctx->response->used + b);
27857 - if (-1 == (r = read(hctx->fd, hctx->response->ptr + hctx->response->used - 1, b))) {
27858 - log_error_write(srv, __FILE__, __LINE__, "sds",
27859 - "unexpected end-of-file (perhaps the proxy process died):",
27860 - proxy_fd, strerror(errno));
27864 - /* this should be catched by the b > 0 above */
27867 - hctx->response->used += r;
27868 - hctx->response->ptr[hctx->response->used - 1] = '\0';
27871 - log_error_write(srv, __FILE__, __LINE__, "sdsbs",
27872 - "demux: Response buffer len", hctx->response->used, ":", hctx->response, ":");
27874 + http_response_reset(p->resp);
27876 - if (0 == con->got_response) {
27877 - con->got_response = 1;
27878 - buffer_prepare_copy(hctx->response_header, 128);
27881 - if (0 == con->file_started) {
27884 - /* search for the \r\n\r\n in the string */
27885 - if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) {
27886 - size_t hlen = c - hctx->response->ptr + 4;
27887 - size_t blen = hctx->response->used - hlen - 1;
27890 - buffer_append_string_len(hctx->response_header, hctx->response->ptr, c - hctx->response->ptr + 4);
27892 - log_error_write(srv, __FILE__, __LINE__, "sb", "Header:", hctx->response_header);
27894 - /* parse the response header */
27895 - proxy_response_parse(srv, con, p, hctx->response_header);
27897 - /* enable chunked-transfer-encoding */
27898 - if (con->request.http_version == HTTP_VERSION_1_1 &&
27899 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
27900 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
27901 + /* the response header is not fully received yet,
27903 + * extract the http-response header from the rb-cq
27905 + switch (http_response_parse_cq(hctx->rb, p->resp)) {
27906 + case PARSE_ERROR:
27907 + /* parsing failed */
27909 + con->http_status = 502; /* Bad Gateway */
27911 + case PARSE_NEED_MORE:
27913 + case PARSE_SUCCESS:
27914 + con->http_status = p->resp->status;
27916 + chunkqueue_remove_finished_chunks(hctx->rb);
27918 + /* copy the http-headers */
27919 + for (i = 0; i < p->resp->headers->used; i++) {
27920 + const char *ign[] = { "Status", "Connection", NULL };
27924 + data_string *header = (data_string *)p->resp->headers->data[i];
27926 + /* some headers are ignored by default */
27927 + for (j = 0; ign[j]; j++) {
27928 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
27930 + if (ign[j]) continue;
27932 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
27933 + /* CGI/1.1 rev 03 - 7.2.1.2 */
27934 + if (con->http_status == 0) con->http_status = 302;
27935 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
27936 + have_content_length = 1;
27939 - con->file_started = 1;
27941 - http_chunk_append_mem(srv, con, c + 4, blen + 1);
27942 - joblist_append(srv, con);
27944 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
27945 + ds = data_response_init();
27947 - hctx->response->used = 0;
27948 + buffer_copy_string_buffer(ds->key, header->key);
27949 + buffer_copy_string_buffer(ds->value, header->value);
27951 + array_insert_unique(con->response.headers, (data_unset *)ds);
27954 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
27955 - joblist_append(srv, con);
27956 - hctx->response->used = 0;
27958 + con->file_started = 1;
27960 + if (con->request.http_version == HTTP_VERSION_1_1 &&
27961 + !have_content_length) {
27962 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
27965 + hctx->state = PROXY_STATE_RESPONSE_CONTENT;
27970 - /* reading from upstream done */
27971 - con->file_finished = 1;
27973 - http_chunk_append_mem(srv, con, NULL, 0);
27974 - joblist_append(srv, con);
27981 + /* FIXME: pass the response-header to the other plugins to
27982 + * setup the filter-queue
27984 + * - use next-queue instead of con->write_queue
27987 + next_queue = con->write_queue;
27989 + assert(hctx->state == PROXY_STATE_RESPONSE_CONTENT);
27991 + /* FIXME: if we have a content-length or chunked-encoding
27994 + * for now we wait for EOF on the socket */
27996 + /* copy the content to the next cq */
27997 + for (c = hctx->rb->first; c; c = c->next) {
27998 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
28000 + c->offset = c->mem->used - 1;
28003 + chunkqueue_remove_finished_chunks(hctx->rb);
28004 + joblist_append(srv, con);
28010 @@ -731,32 +701,32 @@
28011 data_proxy *host= hctx->host;
28012 plugin_data *p = hctx->plugin_data;
28013 connection *con = hctx->remote_conn;
28019 - (!host->host->used || !host->port)) return -1;
28023 + (!host->host->used || !host->port)) return -1;
28025 switch(hctx->state) {
28026 case PROXY_STATE_INIT:
28027 - if (-1 == (hctx->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28028 + if (-1 == (hctx->fd->fd = socket(AF_INET, SOCK_STREAM, 0))) {
28029 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed: ", strerror(errno));
28030 return HANDLER_ERROR;
28032 - hctx->fde_ndx = -1;
28034 + hctx->fd->fde_ndx = -1;
28039 fdevent_register(srv->ev, hctx->fd, proxy_handle_fdevent, hctx);
28042 if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
28043 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed: ", strerror(errno));
28046 return HANDLER_ERROR;
28053 case PROXY_STATE_CONNECT:
28054 /* try to finish the connect() */
28055 if (hctx->state == PROXY_STATE_INIT) {
28056 @@ -764,16 +734,16 @@
28057 switch (proxy_establish_connection(srv, hctx)) {
28059 proxy_set_state(srv, hctx, PROXY_STATE_CONNECT);
28062 /* connection is in progress, wait for an event and call getsockopt() below */
28064 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28067 + fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28069 return HANDLER_WAIT_FOR_EVENT;
28071 /* if ECONNREFUSED choose another connection -> FIXME */
28072 - hctx->fde_ndx = -1;
28074 + hctx->fd->fde_ndx = -1;
28076 return HANDLER_ERROR;
28078 /* everything is ok, go on */
28079 @@ -782,152 +752,152 @@
28082 socklen_t socket_error_len = sizeof(socket_error);
28084 - /* we don't need it anymore */
28085 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28087 + /* we don't need it anymore */
28088 + fdevent_event_del(srv->ev, hctx->fd);
28090 /* try to finish the connect() */
28091 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28092 - log_error_write(srv, __FILE__, __LINE__, "ss",
28093 + if (0 != getsockopt(hctx->fd->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
28094 + log_error_write(srv, __FILE__, __LINE__, "ss",
28095 "getsockopt failed:", strerror(errno));
28098 return HANDLER_ERROR;
28100 if (socket_error != 0) {
28101 log_error_write(srv, __FILE__, __LINE__, "ss",
28102 - "establishing connection failed:", strerror(socket_error),
28103 + "establishing connection failed:", strerror(socket_error),
28104 "port:", hctx->host->port);
28107 return HANDLER_ERROR;
28109 if (p->conf.debug) {
28110 - log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
28111 + log_error_write(srv, __FILE__, __LINE__, "s", "proxy - connect - delayed success");
28116 proxy_set_state(srv, hctx, PROXY_STATE_PREPARE_WRITE);
28118 case PROXY_STATE_PREPARE_WRITE:
28119 proxy_create_env(srv, hctx);
28122 proxy_set_state(srv, hctx, PROXY_STATE_WRITE);
28126 case PROXY_STATE_WRITE:;
28127 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
28128 + ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
28130 chunkqueue_remove_finished_chunks(hctx->wb);
28133 - if (errno != EAGAIN &&
28134 - errno != EINTR) {
28135 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28137 - return HANDLER_ERROR;
28139 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28141 + case NETWORK_STATUS_FATAL_ERROR:
28142 + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed:", strerror(errno), errno);
28144 - return HANDLER_WAIT_FOR_EVENT;
28146 + return HANDLER_ERROR;
28147 + case NETWORK_STATUS_WAIT_FOR_EVENT:
28149 + fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28151 + return HANDLER_WAIT_FOR_EVENT;
28154 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
28155 - proxy_set_state(srv, hctx, PROXY_STATE_READ);
28156 + proxy_set_state(srv, hctx, PROXY_STATE_RESPONSE_HEADER);
28158 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
28159 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
28160 + fdevent_event_del(srv->ev, hctx->fd);
28161 + fdevent_event_add(srv->ev, hctx->fd, FDEVENT_IN);
28163 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
28165 + fdevent_event_add(srv->ev, hctx->fd, FDEVENT_OUT);
28167 return HANDLER_WAIT_FOR_EVENT;
28171 return HANDLER_WAIT_FOR_EVENT;
28172 - case PROXY_STATE_READ:
28173 + case PROXY_STATE_RESPONSE_CONTENT:
28174 + case PROXY_STATE_RESPONSE_HEADER:
28175 /* waiting for a response */
28177 return HANDLER_WAIT_FOR_EVENT;
28179 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
28180 return HANDLER_ERROR;
28184 return HANDLER_GO_ON;
28187 -#define PATCH(x) \
28188 - p->conf.x = s->x;
28189 static int mod_proxy_patch_connection(server *srv, connection *con, plugin_data *p) {
28191 plugin_config *s = p->config_storage[0];
28193 - PATCH(extensions);
28198 + PATCH_OPTION(extensions);
28199 + PATCH_OPTION(debug);
28200 + PATCH_OPTION(balance);
28201 + PATCH_OPTION(last_used_backends);
28203 /* skip the first, the global context */
28204 for (i = 1; i < srv->config_context->used; i++) {
28205 data_config *dc = (data_config *)srv->config_context->data[i];
28206 s = p->config_storage[i];
28209 /* condition didn't match */
28210 if (!config_check_cond(srv, con, dc)) continue;
28214 for (j = 0; j < dc->value->used; j++) {
28215 data_unset *du = dc->value->data[j];
28218 if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.server"))) {
28219 - PATCH(extensions);
28220 + PATCH_OPTION(extensions);
28221 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
28223 + PATCH_OPTION(debug);
28224 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balance"))) {
28226 + PATCH_OPTION(balance);
28227 + PATCH_OPTION(last_used_backends);
28237 SUBREQUEST_FUNC(mod_proxy_handle_subrequest) {
28238 plugin_data *p = p_d;
28241 handler_ctx *hctx = con->plugin_ctx[p->id];
28245 if (NULL == hctx) return HANDLER_GO_ON;
28247 mod_proxy_patch_connection(srv, con, p);
28254 if (con->mode != p->id) return HANDLER_GO_ON;
28257 /* ok, create the request */
28258 switch(proxy_write_request(srv, hctx)) {
28259 case HANDLER_ERROR:
28260 - log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
28261 + log_error_write(srv, __FILE__, __LINE__, "sbdd", "proxy-server disabled:",
28268 /* disable this server */
28269 host->is_disabled = 1;
28270 host->disable_ts = srv->cur_ts;
28273 proxy_connection_close(srv, hctx);
28275 - /* reset the enviroment and restart the sub-request */
28277 + /* reset the enviroment and restart the sub-request */
28278 buffer_reset(con->physical.path);
28279 con->mode = DIRECT;
28281 joblist_append(srv, con);
28283 - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28284 - * and hope that the childs will be restarted
28286 + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
28287 + * and hope that the childs will be restarted
28291 return HANDLER_WAIT_FOR_FD;
28292 @@ -938,7 +908,7 @@
28298 if (con->file_started == 1) {
28299 return HANDLER_FINISHED;
28301 @@ -951,13 +921,14 @@
28302 handler_ctx *hctx = ctx;
28303 connection *con = hctx->remote_conn;
28304 plugin_data *p = hctx->plugin_data;
28309 if ((revents & FDEVENT_IN) &&
28310 - hctx->state == PROXY_STATE_READ) {
28311 + (hctx->state == PROXY_STATE_RESPONSE_HEADER ||
28312 + hctx->state == PROXY_STATE_RESPONSE_CONTENT)) {
28314 if (p->conf.debug) {
28315 - log_error_write(srv, __FILE__, __LINE__, "sd",
28316 + log_error_write(srv, __FILE__, __LINE__, "sd",
28317 "proxy: fdevent-in", hctx->state);
28320 @@ -965,11 +936,15 @@
28324 + log_error_write(srv, __FILE__, __LINE__, "sd",
28325 + "proxy: request done", hctx->fd->fd);
28326 hctx->host->usage--;
28329 + http_chunk_append_mem(srv, con, NULL, 0);
28332 proxy_connection_close(srv, hctx);
28335 joblist_append(srv, con);
28336 return HANDLER_FINISHED;
28338 @@ -982,53 +957,53 @@
28339 /* response might have been already started, kill the connection */
28340 connection_set_state(srv, con, CON_STATE_ERROR);
28344 joblist_append(srv, con);
28345 return HANDLER_FINISHED;
28350 if (revents & FDEVENT_OUT) {
28351 if (p->conf.debug) {
28352 - log_error_write(srv, __FILE__, __LINE__, "sd",
28353 + log_error_write(srv, __FILE__, __LINE__, "sd",
28354 "proxy: fdevent-out", hctx->state);
28357 if (hctx->state == PROXY_STATE_CONNECT ||
28358 hctx->state == PROXY_STATE_WRITE) {
28359 /* we are allowed to send something out
28362 * 1. in a unfinished connect() call
28363 * 2. in a unfinished write() call (long POST request)
28365 return mod_proxy_handle_subrequest(srv, con, p);
28367 - log_error_write(srv, __FILE__, __LINE__, "sd",
28368 + log_error_write(srv, __FILE__, __LINE__, "sd",
28369 "proxy: out", hctx->state);
28374 /* perhaps this issue is already handled */
28375 if (revents & FDEVENT_HUP) {
28376 if (p->conf.debug) {
28377 - log_error_write(srv, __FILE__, __LINE__, "sd",
28378 + log_error_write(srv, __FILE__, __LINE__, "sd",
28379 "proxy: fdevent-hup", hctx->state);
28383 if (hctx->state == PROXY_STATE_CONNECT) {
28384 /* connect() -> EINPROGRESS -> HUP */
28388 - * what is proxy is doing if it can't reach the next hop ?
28390 + * what is proxy is doing if it can't reach the next hop ?
28395 proxy_connection_close(srv, hctx);
28396 joblist_append(srv, con);
28399 con->http_status = 503;
28400 con->mode = DIRECT;
28403 return HANDLER_FINISHED;
28406 @@ -1038,13 +1013,13 @@
28407 joblist_append(srv, con);
28408 } else if (revents & FDEVENT_ERR) {
28409 /* kill all connections to the proxy process */
28412 log_error_write(srv, __FILE__, __LINE__, "sd", "proxy-FDEVENT_ERR, but no HUP", revents);
28414 joblist_append(srv, con);
28415 proxy_connection_close(srv, hctx);
28419 return HANDLER_FINISHED;
28422 @@ -1058,44 +1033,48 @@
28424 data_array *extension = NULL;
28425 size_t path_info_offset;
28427 + data_integer *last_used_backend;
28428 + data_proxy *host = NULL;
28429 + handler_ctx *hctx = NULL;
28431 + array *backends = NULL;
28433 /* Possibly, we processed already this request */
28434 if (con->file_started == 1) return HANDLER_GO_ON;
28437 mod_proxy_patch_connection(srv, con, p);
28440 fn = con->uri.path;
28442 if (fn->used == 0) {
28443 return HANDLER_ERROR;
28447 s_len = fn->used - 1;
28451 path_info_offset = 0;
28453 - if (p->conf.debug) {
28454 + if (p->conf.debug) {
28455 log_error_write(srv, __FILE__, __LINE__, "s", "proxy - start");
28458 /* check if extension matches */
28459 for (k = 0; k < p->conf.extensions->used; k++) {
28463 extension = (data_array *)p->conf.extensions->data[k];
28466 if (extension->key->used == 0) continue;
28469 ct_len = extension->key->used - 1;
28472 if (s_len < ct_len) continue;
28475 /* check extension in the form "/proxy_pattern" */
28476 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
28477 if (s_len > ct_len + 1) {
28481 if (0 != (pi_offset = strchr(fn->ptr + ct_len + 1, '/'))) {
28482 path_info_offset = pi_offset - fn->ptr;
28484 @@ -1106,12 +1085,14 @@
28490 if (k == p->conf.extensions->used) {
28491 return HANDLER_GO_ON;
28494 - if (p->conf.debug) {
28495 + backends = extension->value;
28497 + if (p->conf.debug) {
28498 log_error_write(srv, __FILE__, __LINE__, "s", "proxy - ext found");
28501 @@ -1120,34 +1101,34 @@
28502 /* hash balancing */
28504 if (p->conf.debug) {
28505 - log_error_write(srv, __FILE__, __LINE__, "sd",
28506 - "proxy - used hash balancing, hosts:", extension->value->used);
28507 + log_error_write(srv, __FILE__, __LINE__, "sd",
28508 + "proxy - used hash balancing, hosts:", backends->used);
28511 - for (k = 0, ndx = -1, last_max = ULONG_MAX; k < extension->value->used; k++) {
28512 - data_proxy *host = (data_proxy *)extension->value->data[k];
28513 + for (k = 0, ndx = -1, last_max = ULONG_MAX; k < backends->used; k++) {
28514 unsigned long cur_max;
28516 - if (host->is_disabled) continue;
28518 + data_proxy *cur = (data_proxy *)backends->data[k];
28520 + if (cur->is_disabled) continue;
28522 cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
28523 - generate_crc32c(CONST_BUF_LEN(host->host)) + /* we can cache this */
28524 + generate_crc32c(CONST_BUF_LEN(cur->host)) + /* we can cache this */
28525 generate_crc32c(CONST_BUF_LEN(con->uri.authority));
28528 if (p->conf.debug) {
28529 - log_error_write(srv, __FILE__, __LINE__, "sbbbd",
28530 + log_error_write(srv, __FILE__, __LINE__, "sbbbd",
28531 "proxy - election:",
28535 con->uri.authority,
28539 - if ((last_max == ULONG_MAX) || /* first round */
28540 - (cur_max > last_max)) {
28541 + if (host == NULL || (cur_max > last_max)) {
28542 last_max = cur_max;
28549 @@ -1155,19 +1136,20 @@
28550 case PROXY_BALANCE_FAIR:
28551 /* fair balancing */
28552 if (p->conf.debug) {
28553 - log_error_write(srv, __FILE__, __LINE__, "s",
28554 + log_error_write(srv, __FILE__, __LINE__, "s",
28555 "proxy - used fair balancing");
28558 - for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28559 - data_proxy *host = (data_proxy *)extension->value->data[k];
28561 - if (host->is_disabled) continue;
28563 - if (host->usage < max_usage) {
28564 - max_usage = host->usage;
28567 + /* try to find the host with the lowest load */
28568 + for (k = 0, max_usage = 0; k < backends->used; k++) {
28569 + data_proxy *cur = (data_proxy *)backends->data[k];
28571 + if (cur->is_disabled) continue;
28573 + if (NULL == host || cur->usage < max_usage) {
28574 + max_usage = cur->usage;
28580 @@ -1175,89 +1157,100 @@
28581 case PROXY_BALANCE_RR:
28583 if (p->conf.debug) {
28584 - log_error_write(srv, __FILE__, __LINE__, "s",
28585 + log_error_write(srv, __FILE__, __LINE__, "s",
28586 "proxy - used round-robin balancing");
28589 /* just to be sure */
28590 - assert(extension->value->used < INT_MAX);
28592 - for (k = 0, ndx = -1, max_usage = INT_MAX; k < extension->value->used; k++) {
28593 - data_proxy *host = (data_proxy *)extension->value->data[k];
28595 - if (host->is_disabled) continue;
28597 - /* first usable ndx */
28598 - if (max_usage == INT_MAX) {
28601 + assert(backends->used < INT_MAX);
28603 - /* get next ndx */
28604 - if ((int)k > host->last_used_ndx) {
28606 - host->last_used_ndx = k;
28607 + /* send each request to another host:
28611 + * if we have three hosts it is
28613 + * 1 .. 2 .. 3 .. 1 .. 2 .. 3
28619 + /* walk through the list */
28620 + last_used_backend = (data_integer *)array_get_element(p->conf.last_used_backends, extension->key->ptr);
28622 + if (NULL == last_used_backend) {
28623 + last_used_backend = data_integer_init();
28625 + buffer_copy_string_buffer(last_used_backend->key, extension->key);
28626 + last_used_backend->value = 0;
28628 + array_insert_unique(p->conf.last_used_backends, (data_unset *)last_used_backend);
28631 + /* scan all but the last host to see if they are up
28632 + * take the first running host */
28633 + for (k = last_used_backend->value + 1; (int)(k % backends->used) != last_used_backend->value; k++) {
28634 + data_proxy *cur = (data_proxy *)backends->data[k % backends->used];
28636 + if (cur->is_disabled) continue;
28640 + last_used_backend->value = k;
28645 - /* didn't found a higher id, wrap to the start */
28646 - if (ndx != -1 && max_usage != INT_MAX) {
28649 + if (NULL == host) {
28650 + /* we found nothing better, fallback to the last used backend
28651 + * and check if it is still up */
28652 + host = (data_proxy *)backends->data[last_used_backend->value];
28654 + if (host->is_disabled) host = NULL;
28662 - /* found a server */
28664 - data_proxy *host = (data_proxy *)extension->value->data[ndx];
28667 - * if check-local is disabled, use the uri.path handler
28671 - /* init handler-context */
28672 - handler_ctx *hctx;
28673 - hctx = handler_ctx_init();
28675 - hctx->path_info_offset = path_info_offset;
28676 - hctx->remote_conn = con;
28677 - hctx->plugin_data = p;
28678 - hctx->host = host;
28680 - con->plugin_ctx[p->id] = hctx;
28684 - con->mode = p->id;
28686 - if (p->conf.debug) {
28687 - log_error_write(srv, __FILE__, __LINE__, "sbd",
28688 - "proxy - found a host",
28689 - host->host, host->port);
28692 - return HANDLER_GO_ON;
28694 - /* no handler found */
28695 + /* we havn't found a host */
28696 + if (NULL == host) {
28697 con->http_status = 500;
28699 - log_error_write(srv, __FILE__, __LINE__, "sb",
28700 - "no proxy-handler found for:",
28702 + log_error_write(srv, __FILE__, __LINE__, "sb",
28703 + "no proxy-handler found for:",
28707 return HANDLER_FINISHED;
28710 + /* init handler-context */
28711 + hctx = handler_ctx_init();
28713 + hctx->path_info_offset = path_info_offset;
28714 + hctx->remote_conn = con;
28715 + hctx->plugin_data = p;
28716 + hctx->host = host;
28718 + con->plugin_ctx[p->id] = hctx;
28722 + /* we handle this request */
28723 + con->mode = p->id;
28725 + if (p->conf.debug) {
28726 + log_error_write(srv, __FILE__, __LINE__, "sbd",
28727 + "proxy - found a host",
28728 + host->host, host->port);
28731 return HANDLER_GO_ON;
28734 static handler_t mod_proxy_connection_close_callback(server *srv, connection *con, void *p_d) {
28735 plugin_data *p = p_d;
28738 proxy_connection_close(srv, con->plugin_ctx[p->id]);
28740 return HANDLER_GO_ON;
28741 @@ -1276,11 +1269,11 @@
28743 for (i = 0; i < srv->config_context->used; i++) {
28744 plugin_config *s = p->config_storage[i];
28746 - if (!s) continue;
28748 + if (!s) continue;
28750 /* get the extensions for all configs */
28753 for (k = 0; k < s->extensions->used; k++) {
28754 data_array *extension = (data_array *)s->extensions->data[k];
28756 @@ -1290,8 +1283,8 @@
28758 if (!host->is_disabled ||
28759 srv->cur_ts - host->disable_ts < 5) continue;
28761 - log_error_write(srv, __FILE__, __LINE__, "sbd",
28763 + log_error_write(srv, __FILE__, __LINE__, "sbd",
28764 "proxy - re-enabled:",
28765 host->host, host->port);
28767 @@ -1317,8 +1310,8 @@
28768 p->handle_uri_clean = mod_proxy_check_extension;
28769 p->handle_subrequest = mod_proxy_handle_subrequest;
28770 p->handle_trigger = mod_proxy_trigger;
28778 --- ../lighttpd-1.4.11/src/mod_proxy_core.c 1970-01-01 03:00:00.000000000 +0300
28779 +++ lighttpd-1.4.12/src/mod_proxy_core.c 2006-07-18 13:03:40.000000000 +0300
28781 +#include <string.h>
28782 +#include <stdlib.h>
28783 +#include <fcntl.h>
28784 +#include <errno.h>
28786 +#include "buffer.h"
28787 +#include "array.h"
28791 +#include "plugin.h"
28792 +#include "joblist.h"
28793 +#include "sys-files.h"
28794 +#include "inet_ntop_cache.h"
28795 +#include "http_resp.h"
28796 +#include "http_chunk.h"
28797 +#include "crc32.h"
28799 +#include "mod_proxy_core_pool.h"
28800 +#include "mod_proxy_core_backend.h"
28801 +#include "mod_proxy_core_backlog.h"
28804 + PROXY_PROTOCOL_UNSET,
28805 + PROXY_PROTOCOL_HTTP,
28806 + PROXY_PROTOCOL_HTTPS,
28807 + PROXY_PROTOCOL_FASTCGI,
28808 + PROXY_PROTOCOL_SCGI
28809 +} proxy_protocol_t;
28812 + proxy_backends *backends;
28814 + proxy_backlog *backlog;
28818 + proxy_balance_t balancer;
28819 + proxy_protocol_t protocol;
28827 + array *possible_balancers;
28828 + array *possible_protocols;
28830 + /* for parsing only */
28831 + array *backends_arr;
28832 + buffer *protocol_buf;
28833 + buffer *balance_buf;
28835 + plugin_config **config_storage;
28837 + plugin_config conf;
28840 +int array_insert_int(array *a, const char *key, int val) {
28841 + data_integer *di;
28843 + if (NULL == (di = (data_integer *)array_get_unused_element(a, TYPE_INTEGER))) {
28844 + di = data_integer_init();
28847 + buffer_copy_string(di->key, key);
28849 + array_insert_unique(a, (data_unset *)di);
28854 +INIT_FUNC(mod_proxy_core_init) {
28857 + p = calloc(1, sizeof(*p));
28859 + /* create some backends as long as we don't have the config-parser */
28861 + p->possible_balancers = array_init();
28862 + array_insert_int(p->possible_balancers, "fair", PROXY_BALANCE_FAIR);
28863 + array_insert_int(p->possible_balancers, "hash", PROXY_BALANCE_RR);
28864 + array_insert_int(p->possible_balancers, "round-robin", PROXY_BALANCE_HASH);
28866 + p->possible_protocols = array_init();
28867 + array_insert_int(p->possible_protocols, "http", PROXY_PROTOCOL_HTTP);
28868 + array_insert_int(p->possible_protocols, "fastcgi", PROXY_PROTOCOL_FASTCGI);
28869 + array_insert_int(p->possible_protocols, "scgi", PROXY_PROTOCOL_SCGI);
28870 + array_insert_int(p->possible_protocols, "https", PROXY_PROTOCOL_HTTPS);
28872 + p->balance_buf = buffer_init();
28873 + p->protocol_buf = buffer_init();
28874 + p->backends_arr = array_init();
28876 + p->resp = http_response_init();
28881 +FREE_FUNC(mod_proxy_core_free) {
28882 + plugin_data *p = p_d;
28884 + if (!p) return HANDLER_GO_ON;
28886 + if (p->config_storage) {
28888 + for (i = 0; i < srv->config_context->used; i++) {
28889 + plugin_config *s = p->config_storage[i];
28891 + if (!s) continue;
28893 + proxy_backends_free(s->backends);
28894 + proxy_backlog_free(s->backlog);
28899 + free(p->config_storage);
28902 + array_free(p->possible_protocols);
28903 + array_free(p->possible_balancers);
28904 + array_free(p->backends_arr);
28906 + buffer_free(p->balance_buf);
28907 + buffer_free(p->protocol_buf);
28909 + http_response_free(p->resp);
28913 + return HANDLER_GO_ON;
28916 +SETDEFAULTS_FUNC(mod_proxy_core_set_defaults) {
28917 + plugin_data *p = p_d;
28920 + config_values_t cv[] = {
28921 + { "proxy-core.backends", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
28922 + { "proxy-core.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
28923 + { "proxy-core.balancer", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
28924 + { "proxy-core.protocol", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
28925 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
28928 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
28930 + for (i = 0; i < srv->config_context->used; i++) {
28931 + plugin_config *s;
28933 + proxy_backend *backend;
28935 + array_reset(p->backends_arr);
28936 + buffer_reset(p->balance_buf);
28937 + buffer_reset(p->protocol_buf);
28939 + s = malloc(sizeof(plugin_config));
28941 + s->balancer = PROXY_BALANCE_UNSET;
28942 + s->protocol = PROXY_PROTOCOL_UNSET;
28943 + s->backends = proxy_backends_init();
28944 + s->backlog = proxy_backlog_init();
28946 + cv[0].destination = p->backends_arr;
28947 + cv[1].destination = &(s->debug);
28948 + cv[2].destination = p->balance_buf; /* parse into a constant */
28949 + cv[3].destination = p->protocol_buf; /* parse into a constant */
28951 + buffer_reset(p->balance_buf);
28953 + p->config_storage[i] = s;
28954 + ca = ((data_config *)srv->config_context->data[i])->value;
28956 + if (0 != config_insert_values_global(srv, ca, cv)) {
28957 + return HANDLER_ERROR;
28960 + if (!buffer_is_empty(p->balance_buf)) {
28961 + data_integer *di;
28963 + if (NULL == (di = (data_integer *)array_get_element(p->possible_balancers, BUF_STR(p->balance_buf)))) {
28964 + ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->balance_buf));
28966 + return HANDLER_ERROR;
28969 + s->balancer = di->value;
28972 + if (!buffer_is_empty(p->protocol_buf)) {
28973 + data_integer *di;
28975 + if (NULL == (di = (data_integer *)array_get_element(p->possible_protocols, BUF_STR(p->protocol_buf)))) {
28976 + ERROR("proxy.balance has to be on of 'fair', 'round-robin', 'hash', got %s", BUF_STR(p->protocol_buf));
28978 + return HANDLER_ERROR;
28981 + s->protocol = di->value;
28984 + backend = proxy_backend_init();
28986 + /* check if the backends have a valid host-name */
28987 + for (j = 0; j < p->backends_arr->used; j++) {
28988 + data_string *ds = (data_string *)p->backends_arr->data[j];
28990 + /* the values should be ips or hostnames */
28991 + if (0 != proxy_address_pool_add_string(backend->address_pool, ds->value)) {
28992 + return HANDLER_ERROR;
28996 + proxy_backends_add(s->backends, backend);
28999 + return HANDLER_GO_ON;
29004 + PROXY_STATE_UNSET,
29005 + PROXY_STATE_CONNECTING,
29006 + PROXY_STATE_CONNECTED,
29007 + PROXY_STATE_WRITE_REQUEST_HEADER,
29008 + PROXY_STATE_WRITE_REQUEST_BODY,
29009 + PROXY_STATE_READ_RESPONSE_HEADER,
29010 + PROXY_STATE_READ_RESPONSE_BODY
29014 + proxy_connection *proxy_con;
29015 + proxy_backend *proxy_backend;
29017 + connection *remote_con;
29019 + array *request_headers;
29025 + * - the encoded_rb is the raw network stuff
29026 + * - the rb is filtered through the stream decoder
29028 + * - wb is the normal bytes stream
29029 + * - encoded_wb is encoded for the network by the stream encoder
29031 + chunkqueue *recv;
29032 + chunkqueue *recv_raw;
29033 + chunkqueue *send_raw;
29034 + chunkqueue *send;
29036 + off_t bytes_read;
29037 + off_t content_length;
29039 + proxy_state_t state;
29042 +proxy_session *proxy_session_init(void) {
29043 + proxy_session *sess;
29045 + sess = calloc(1, sizeof(*sess));
29047 + sess->state = PROXY_STATE_UNSET;
29048 + sess->request_headers = array_init();
29050 + sess->recv = chunkqueue_init();
29051 + sess->recv_raw = chunkqueue_init();
29052 + sess->send_raw = chunkqueue_init();
29053 + sess->send = chunkqueue_init();
29055 + sess->is_chunked = 0;
29060 +void proxy_session_free(proxy_session *sess) {
29061 + if (!sess) return;
29063 + array_free(sess->request_headers);
29065 + chunkqueue_free(sess->recv);
29066 + chunkqueue_free(sess->recv_raw);
29067 + chunkqueue_free(sess->send_raw);
29068 + chunkqueue_free(sess->send);
29073 +handler_t proxy_connection_connect(proxy_connection *con) {
29076 + if (-1 == (fd = socket(con->address->addr.plain.sa_family, SOCK_STREAM, 0))) {
29079 + fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
29081 + con->sock->fd = fd;
29082 + con->sock->fde_ndx = -1;
29083 + con->sock->type = IOSOCKET_TYPE_SOCKET;
29085 + if (-1 == connect(fd, &(con->address->addr.plain), sizeof(con->address->addr))) {
29087 + case EINPROGRESS:
29090 + return HANDLER_WAIT_FOR_EVENT;
29093 + con->sock->fd = -1;
29095 + return HANDLER_ERROR;
29099 + return HANDLER_GO_ON;
29103 + * event-handler for idling connections
29105 + * unused (idling) keep-alive connections are not bound to a session
29106 + * and need their own event-handler
29108 + * if the connection closes (we get a FDEVENT_IN), close our side too and
29109 + * let the trigger-func handle the cleanup
29111 + * @see proxy_trigger
29115 +static handler_t proxy_handle_fdevent_idle(void *s, void *ctx, int revents) {
29116 + server *srv = (server *)s;
29117 + proxy_connection *proxy_con = ctx;
29119 + if (revents & FDEVENT_IN) {
29120 + switch (proxy_con->state) {
29121 + case PROXY_CONNECTION_STATE_IDLE:
29122 + proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29124 + /* close + unregister have to be in the same call,
29125 + * otherwise we get a events for a re-opened fd */
29127 + fdevent_event_del(srv->ev, proxy_con->sock);
29130 + case PROXY_CONNECTION_STATE_CLOSED:
29131 + /* poll() is state-driven, we will get events as long as it isn't disabled
29132 + * the close() above should disable the events too */
29133 + ERROR("%s", "hurry up buddy, I got another event for a closed idle-connection");
29136 + ERROR("invalid connection state: %d, should be idle", proxy_con->state);
29141 + return HANDLER_GO_ON;
29144 +void chunkqueue_skip(chunkqueue *cq, off_t skip) {
29147 + for (c = cq->first; c && skip; c = c->next) {
29148 + if (skip > c->mem->used - c->offset - 1) {
29149 + skip -= c->mem->used - c->offset - 1;
29151 + c->offset += skip;
29159 +int proxy_http_stream_decoder(server *srv, proxy_session *sess, chunkqueue *raw, chunkqueue *decoded) {
29162 + if (sess->is_chunked) {
29164 + /* the start should always be a chunk-length */
29165 + off_t chunk_len = 0;
29166 + char *err = NULL;
29167 + int chunklen_strlen = 0;
29169 + off_t we_have = 0, we_need = 0;
29173 + chunk_len = strtol(BUF_STR(c->mem) + c->offset, &err, 16);
29174 + if (!(*err == ' ' || *err == '\r' || *err == ';')) {
29175 + if (*err == '\0') {
29176 + /* we just need more data */
29182 + if (chunk_len < 0) {
29183 + ERROR("chunk_len is negative: %Ld", chunk_len);
29187 + chunklen_strlen = err - (BUF_STR(c->mem) + c->offset);
29188 + chunklen_strlen++; /* skip the err-char */
29191 + ch = BUF_STR(c->mem)[c->offset + chunklen_strlen];
29196 + /* bingo, chunk-header is finished */
29201 + chunklen_strlen++;
29202 + } while (ch != '\n' && c != '\0');
29204 + if (ch != '\n') {
29205 + ERROR("%s", "missing the CRLF");
29209 + we_need = chunk_len + chunklen_strlen + 2;
29210 + /* do we have the full chunk ? */
29211 + for (c = raw->first; c; c = c->next) {
29212 + we_have += c->mem->used - 1 - c->offset;
29214 + /* we have enough, jump out */
29215 + if (we_have > we_need) break;
29218 + /* get more data */
29219 + if (we_have < we_need) {
29223 + /* skip the chunk-header */
29224 + chunkqueue_skip(raw, chunklen_strlen);
29226 + /* final chunk */
29227 + if (chunk_len == 0) {
29228 + chunkqueue_skip(raw, 2);
29233 + /* we have enough, copy the data */
29234 + for (c = raw->first; c && chunk_len; c = c->next) {
29235 + off_t we_want = 0;
29236 + buffer *b = chunkqueue_get_append_buffer(decoded);
29238 + we_want = chunk_len > (c->mem->used - c->offset - 1) ? c->mem->used - c->offset - 1: chunk_len;
29240 + buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want);
29242 + c->offset += we_want;
29243 + chunk_len -= we_want;
29246 + /* skip the \r\n */
29247 + chunkqueue_skip(raw, 2);
29249 + /* we are done, give the connection to someone else */
29250 + chunkqueue_remove_finished_chunks(raw);
29253 + /* no chunked encoding, ok, perhaps a content-length ? */
29255 + TRACE("content-lenght: %d", sess->content_length);
29257 + chunkqueue_remove_finished_chunks(raw);
29258 + for (c = raw->first; c; c = c->next) {
29261 + if (c->mem->used == 0) continue;
29263 + b = chunkqueue_get_append_buffer(decoded);
29265 + sess->bytes_read += c->mem->used - c->offset - 1;
29267 + buffer_copy_string_len(b, c->mem->ptr + c->offset, c->mem->used - c->offset - 1);
29269 + c->offset = c->mem->used - 1;
29271 + if (sess->bytes_read == sess->content_length) {
29276 + if (sess->bytes_read == sess->content_length) {
29277 + return 1; /* finished */
29283 +/* don't call any proxy functions directly */
29284 +static handler_t proxy_handle_fdevent(void *s, void *ctx, int revents) {
29285 + server *srv = (server *)s;
29286 + proxy_session *sess = ctx;
29288 + if (revents & FDEVENT_OUT) {
29289 + switch (sess->state) {
29290 + case PROXY_STATE_CONNECTING: /* delayed connect */
29291 + case PROXY_STATE_WRITE_REQUEST_HEADER:
29292 + case PROXY_STATE_WRITE_REQUEST_BODY:
29293 + /* we are still connection */
29295 + joblist_append(srv, sess->remote_con);
29298 + ERROR("oops, unexpected state for fdevent-out %d", sess->state);
29301 + } else if (revents & FDEVENT_IN) {
29304 + switch (sess->state) {
29305 + case PROXY_STATE_READ_RESPONSE_HEADER:
29306 + /* call our header parser */
29307 + joblist_append(srv, sess->remote_con);
29309 + case PROXY_STATE_READ_RESPONSE_BODY:
29310 + /* we should be in the WRITE state now,
29311 + * just read in the content and forward it to the outgoing connection
29314 + chunkqueue_remove_finished_chunks(sess->recv_raw);
29315 + switch (srv->network_backend_read(srv, sess->remote_con, sess->proxy_con->sock, sess->recv_raw)) {
29316 + case NETWORK_STATUS_CONNECTION_CLOSE:
29317 + fdevent_event_del(srv->ev,sess->proxy_con->sock);
29319 + /* the connection is gone
29320 + * make the connect */
29321 + sess->remote_con->file_finished = 1;
29322 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29324 + case NETWORK_STATUS_SUCCESS:
29325 + /* read even more, do we have all the content */
29327 + /* how much do we want to read ? */
29329 + /* call stream-decoder (HTTP-chunked, FastCGI, ... ) */
29331 + switch (proxy_http_stream_decoder(srv, sess, sess->recv_raw, sess->recv)) {
29339 + /* we are done */
29340 + sess->remote_con->file_finished = 1;
29344 + chunkqueue_remove_finished_chunks(sess->recv_raw);
29346 + /* copy the content to the next cq */
29347 + for (c = sess->recv->first; c; c = c->next) {
29348 + if (c->mem->used == 0) continue;
29350 + http_chunk_append_mem(srv, sess->remote_con, c->mem->ptr + c->offset, c->mem->used - c->offset);
29352 + c->offset = c->mem->used - 1;
29355 + chunkqueue_remove_finished_chunks(sess->recv);
29357 + if (sess->remote_con->file_finished) {
29358 + /* send final HTTP-Chunk packet */
29359 + http_chunk_append_mem(srv, sess->remote_con, NULL, 0);
29364 + ERROR("%s", "oops, we failed to read");
29368 + joblist_append(srv, sess->remote_con);
29371 + ERROR("oops, unexpected state for fdevent-in %d", sess->state);
29376 + if (revents & FDEVENT_HUP) {
29377 + /* someone closed our connection */
29378 + switch (sess->state) {
29379 + case PROXY_STATE_CONNECTING:
29380 + /* let the getsockopt() catch this */
29381 + joblist_append(srv, sess->remote_con);
29384 + ERROR("oops, unexpected state for fdevent-hup %d", sess->state);
29389 + return HANDLER_GO_ON;
29393 + * generate a HTTP/1.1 proxy request from the set of request-headers
29395 + * TODO: this is HTTP-proxy specific and will be moved moved into a separate backed
29398 +int proxy_get_request_chunk(server *srv, connection *con, proxy_session *sess, chunkqueue *cq) {
29402 + b = chunkqueue_get_append_buffer(cq);
29404 + /* request line */
29405 + buffer_copy_string(b, get_http_method_name(con->request.http_method));
29406 + BUFFER_APPEND_STRING_CONST(b, " ");
29408 + buffer_append_string_buffer(b, con->request.uri);
29409 + BUFFER_APPEND_STRING_CONST(b, " HTTP/1.1\r\n");
29411 + for (i = 0; i < sess->request_headers->used; i++) {
29414 + ds = (data_string *)sess->request_headers->data[i];
29416 + buffer_append_string_buffer(b, ds->key);
29417 + BUFFER_APPEND_STRING_CONST(b, ": ");
29418 + buffer_append_string_buffer(b, ds->value);
29419 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
29422 + BUFFER_APPEND_STRING_CONST(b, "\r\n");
29427 +void proxy_set_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29428 + data_string *ds_dst;
29430 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29431 + ds_dst = data_string_init();
29434 + buffer_copy_string_len(ds_dst->key, key, key_len);
29435 + buffer_copy_string_len(ds_dst->value, value, val_len);
29436 + array_insert_unique(hdrs, (data_unset *)ds_dst);
29439 +void proxy_append_header(array *hdrs, const char *key, size_t key_len, const char *value, size_t val_len) {
29440 + data_string *ds_dst;
29442 + if (NULL == (ds_dst = (data_string *)array_get_unused_element(hdrs, TYPE_STRING))) {
29443 + ds_dst = data_string_init();
29446 + buffer_copy_string_len(ds_dst->key, key, key_len);
29447 + buffer_append_string_len(ds_dst->value, value, val_len);
29448 + array_insert_unique(hdrs, (data_unset *)ds_dst);
29453 + * build the request-header array and call the backend specific request formater
29454 + * to fill the chunkqueue
29456 +int proxy_get_request_header(server *srv, connection *con, proxy_session *sess) {
29457 + /* request line */
29458 + const char *remote_ip;
29461 + remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
29462 + proxy_append_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-For"), remote_ip, strlen(remote_ip));
29464 + /* http_host is NOT is just a pointer to a buffer
29465 + * which is NULL if it is not set */
29466 + if (con->request.http_host &&
29467 + !buffer_is_empty(con->request.http_host)) {
29468 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Host"), CONST_BUF_LEN(con->request.http_host));
29470 + if (con->conf.is_ssl) {
29471 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("https"));
29473 + proxy_set_header(sess->request_headers, CONST_STR_LEN("X-Forwarded-Proto"), CONST_STR_LEN("http"));
29476 + /* request header */
29477 + for (i = 0; i < con->request.headers->used; i++) {
29480 + ds = (data_string *)con->request.headers->data[i];
29482 + if (buffer_is_empty(ds->value) || buffer_is_empty(ds->key)) continue;
29484 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;
29485 + if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Keep-Alive"))) continue;
29487 + proxy_set_header(sess->request_headers, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
29490 + proxy_get_request_chunk(srv, con, sess, sess->send_raw);
29496 + * parse the response header
29498 + * NOTE: this can be used by all backends as they all send a HTTP-Response a clean block
29499 + * - fastcgi needs some decoding for the protocol
29501 +parse_status_t proxy_parse_response_header(server *srv, connection *con, plugin_data *p, proxy_session *sess, chunkqueue *cq) {
29502 + int have_content_length = 0;
29505 + http_response_reset(p->resp);
29507 + switch (http_response_parse_cq(cq, p->resp)) {
29508 + case PARSE_ERROR:
29509 + /* parsing failed */
29511 + return PARSE_ERROR;
29512 + case PARSE_NEED_MORE:
29513 + return PARSE_NEED_MORE;
29514 + case PARSE_SUCCESS:
29515 + con->http_status = p->resp->status;
29517 + chunkqueue_remove_finished_chunks(cq);
29519 + sess->content_length = -1;
29521 + /* copy the http-headers */
29522 + for (i = 0; i < p->resp->headers->used; i++) {
29523 + const char *ign[] = { "Status", "Connection", NULL };
29527 + data_string *header = (data_string *)p->resp->headers->data[i];
29529 + /* some headers are ignored by default */
29530 + for (j = 0; ign[j]; j++) {
29531 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
29533 + if (ign[j]) continue;
29535 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
29536 + /* CGI/1.1 rev 03 - 7.2.1.2 */
29537 + if (con->http_status == 0) con->http_status = 302;
29538 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
29539 + have_content_length = 1;
29541 + sess->content_length = strtol(header->value->ptr, NULL, 10);
29543 + if (sess->content_length < 0) {
29544 + return PARSE_ERROR;
29546 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Transfer-Encoding"))) {
29547 + if (strstr(header->value->ptr, "chunked")) {
29548 + sess->is_chunked = 1;
29550 + /* ignore the header */
29554 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
29555 + ds = data_response_init();
29557 + buffer_copy_string_buffer(ds->key, header->key);
29558 + buffer_copy_string_buffer(ds->value, header->value);
29560 + array_insert_unique(con->response.headers, (data_unset *)ds);
29563 + /* does the client allow us to send chunked encoding ? */
29564 + if (con->request.http_version == HTTP_VERSION_1_1 &&
29565 + !have_content_length) {
29566 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
29572 + return PARSE_SUCCESS; /* we have a full header */
29575 +/* we are event-driven
29577 + * the first entry is connect() call, if the doesn't need a event
29580 + * - connect (+ delayed connect)
29581 + * - write header + content
29582 + * - read header + content
29584 + * as soon as have read the response header we switch con->file_started and return HANDLER_GO_ON to
29585 + * tell the core we are ready to stream out the content.
29587 +handler_t proxy_state_engine(server *srv, connection *con, plugin_data *p, proxy_session *sess) {
29588 + /* do we have a connection ? */
29590 + if (sess->state == PROXY_STATE_UNSET) {
29591 + /* we are not started yet */
29592 + switch(proxy_connection_connect(sess->proxy_con)) {
29593 + case HANDLER_WAIT_FOR_EVENT:
29594 + /* waiting on the connect call */
29596 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29597 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29599 + sess->state = PROXY_STATE_CONNECTING;
29600 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
29602 + return HANDLER_WAIT_FOR_EVENT;
29603 + case HANDLER_GO_ON:
29604 + /* we are connected */
29605 + sess->state = PROXY_STATE_CONNECTED;
29606 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29607 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
29610 + case HANDLER_ERROR:
29612 + /* not good, something failed */
29613 + return HANDLER_ERROR;
29616 + } else if (sess->state == PROXY_STATE_CONNECTING) {
29617 + int socket_error;
29618 + socklen_t socket_error_len = sizeof(socket_error);
29620 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29622 + if (0 != getsockopt(sess->proxy_con->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
29623 + ERROR("getsockopt failed:", strerror(errno));
29625 + return HANDLER_ERROR;
29627 + if (socket_error != 0) {
29628 + switch (socket_error) {
29629 + case ECONNREFUSED:
29630 + /* there is no-one on the other side */
29631 + sess->proxy_con->address->disabled_until = srv->cur_ts + 2;
29633 + TRACE("address %s refused us, disabling for 2 sec", sess->proxy_con->address->name->ptr);
29635 + case EHOSTUNREACH:
29636 + /* there is no-one on the other side */
29637 + sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
29639 + TRACE("host %s is unreachable, disabling for 60 sec", sess->proxy_con->address->name->ptr);
29642 + sess->proxy_con->address->disabled_until = srv->cur_ts + 60;
29644 + TRACE("connected finally failed: %s (%d)", strerror(socket_error), socket_error);
29646 + TRACE("connect to address %s failed and I don't know why, disabling for 10 sec", sess->proxy_con->address->name->ptr);
29651 + sess->proxy_con->address->state = PROXY_ADDRESS_STATE_DISABLED;
29653 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29654 + return HANDLER_COMEBACK;
29657 + sess->state = PROXY_STATE_CONNECTED;
29658 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
29661 + if (sess->state == PROXY_STATE_CONNECTED) {
29662 + /* build the header */
29663 + proxy_get_request_header(srv, con, sess);
29665 + sess->state = PROXY_STATE_WRITE_REQUEST_HEADER;
29668 + switch (sess->state) {
29669 + case PROXY_STATE_WRITE_REQUEST_HEADER:
29670 + /* create the request-packet */
29671 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29673 + switch (srv->network_backend_write(srv, con, sess->proxy_con->sock, sess->send_raw)) {
29674 + case NETWORK_STATUS_SUCCESS:
29675 + sess->state = PROXY_STATE_WRITE_REQUEST_BODY;
29677 + case NETWORK_STATUS_WAIT_FOR_EVENT:
29678 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_OUT);
29680 + return HANDLER_WAIT_FOR_EVENT;
29681 + case NETWORK_STATUS_CONNECTION_CLOSE:
29682 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29684 + /* this connection is closed, restart the request with a new connection */
29686 + return HANDLER_COMEBACK;
29688 + return HANDLER_ERROR;
29690 + /* fall through */
29691 + case PROXY_STATE_WRITE_REQUEST_BODY:
29692 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29693 + sess->state = PROXY_STATE_READ_RESPONSE_HEADER;
29695 + case PROXY_STATE_READ_RESPONSE_HEADER:
29696 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29698 + chunkqueue_remove_finished_chunks(sess->recv_raw);
29700 + switch (srv->network_backend_read(srv, con, sess->proxy_con->sock, sess->recv_raw)) {
29701 + case NETWORK_STATUS_SUCCESS:
29702 + /* we read everything from the socket, do we have a full header ? */
29704 + switch (proxy_parse_response_header(srv, con, p, sess, sess->recv_raw)) {
29705 + case PARSE_ERROR:
29706 + con->http_status = 502; /* bad gateway */
29708 + return HANDLER_FINISHED;
29709 + case PARSE_NEED_MORE:
29710 + /* we need more */
29711 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29713 + return HANDLER_WAIT_FOR_EVENT;
29714 + case PARSE_SUCCESS:
29717 + return HANDLER_ERROR;
29720 + con->file_started = 1;
29722 + sess->state = PROXY_STATE_READ_RESPONSE_BODY;
29725 + * set the event to pass the content through to the server
29727 + * this triggers the event-handler
29728 + * @see proxy_handle_fdevent
29730 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29732 + return HANDLER_GO_ON; /* tell http_response_prepare that we are done with the header */
29733 + case NETWORK_STATUS_WAIT_FOR_EVENT:
29734 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
29735 + return HANDLER_WAIT_FOR_EVENT;
29736 + case NETWORK_STATUS_CONNECTION_CLOSE:
29737 + if (chunkqueue_length(sess->recv_raw) == 0) {
29738 + /* the connection went away before we got something back */
29739 + sess->proxy_con->state = PROXY_CONNECTION_STATE_CLOSED;
29742 + * we might run into a 'race-condition'
29744 + * 1. proxy-con is keep-alive, idling and just being closed (FDEVENT_IN) [fd=27]
29745 + * 2. new connection comes in, we use the idling connection [fd=14]
29746 + * 3. we write(), successful [to fd=27]
29747 + * 3. we read() ... and finally receive the close-event for the connection
29750 + con->http_status = 500;
29752 + ERROR("++ %s", "oops, connection got closed while we were reading from it");
29753 + return HANDLER_FINISHED;
29756 + ERROR("%s", "conn-close after header-read");
29760 + ERROR("++ %s", "oops, something went wrong while reading");
29761 + return HANDLER_ERROR;
29763 + case PROXY_STATE_READ_RESPONSE_BODY:
29764 + /* if we do everything right, we won't get call for this state-anymore */
29766 + ERROR("%s", "PROXY_STATE_READ_RESPONSE_BODY");
29771 + return HANDLER_GO_ON;
29774 +proxy_backend *proxy_get_backend(server *srv, connection *con, plugin_data *p, buffer *uri) {
29777 + for (i = 0; i < p->conf.backends->used; i++) {
29778 + proxy_backend *backend = p->conf.backends->ptr[i];
29787 + * choose a available address from the address-pool
29789 + * the backend has different balancers
29791 +proxy_address *proxy_backend_balance(server *srv, connection *con, proxy_backend *backend) {
29793 + proxy_address_pool *address_pool = backend->address_pool;
29794 + unsigned long last_max; /* for the HASH balancer */
29795 + proxy_address *address = NULL, *cur_address = NULL;
29796 + int active_addresses = 0, rand_ndx;
29798 + switch(backend->balancer) {
29799 + case PROXY_BALANCE_HASH:
29800 + /* hash balancing */
29802 + for (i = 0, last_max = ULONG_MAX; i < address_pool->used; i++) {
29803 + unsigned long cur_max;
29805 + cur_address = address_pool->ptr[i];
29807 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
29809 + cur_max = generate_crc32c(CONST_BUF_LEN(con->uri.path)) +
29810 + generate_crc32c(CONST_BUF_LEN(cur_address->name)) + /* we can cache this */
29811 + generate_crc32c(CONST_BUF_LEN(con->uri.authority));
29813 + TRACE("hash-election: %s - %s - %s: %ld",
29814 + con->uri.path->ptr,
29815 + cur_address->name->ptr,
29816 + con->uri.authority->ptr,
29819 + if (address == NULL || (cur_max > last_max)) {
29820 + last_max = cur_max;
29822 + address = cur_address;
29827 + case PROXY_BALANCE_FAIR:
29828 + /* fair balancing */
29830 + for (i = 0; i < address_pool->used; i++) {
29831 + cur_address = address_pool->ptr[i];
29833 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
29835 + /* the address is up, use it */
29837 + address = cur_address;
29843 + case PROXY_BALANCE_RR:
29844 + /* round robin */
29847 + * instead of real RoundRobin we just do a RandomSelect
29849 + * it is state-less and has the same distribution
29852 + active_addresses = 0;
29854 + for (i = 0; i < address_pool->used; i++) {
29855 + cur_address = address_pool->ptr[i];
29857 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
29859 + active_addresses++;
29862 + rand_ndx = (int) (1.0 * active_addresses * rand()/(RAND_MAX));
29864 + active_addresses = 0;
29865 + for (i = 0; i < address_pool->used; i++) {
29866 + cur_address = address_pool->ptr[i];
29868 + if (cur_address->state != PROXY_ADDRESS_STATE_ACTIVE) continue;
29870 + address = cur_address;
29872 + if (rand_ndx == active_addresses++) break;
29883 +static int mod_proxy_core_patch_connection(server *srv, connection *con, plugin_data *p) {
29885 + plugin_config *s = p->config_storage[0];
29887 + /* global defaults */
29888 + PATCH_OPTION(balancer);
29889 + PATCH_OPTION(debug);
29890 + PATCH_OPTION(backends);
29891 + PATCH_OPTION(backlog);
29892 + PATCH_OPTION(protocol);
29894 + /* skip the first, the global context */
29895 + for (i = 1; i < srv->config_context->used; i++) {
29896 + data_config *dc = (data_config *)srv->config_context->data[i];
29897 + s = p->config_storage[i];
29899 + /* condition didn't match */
29900 + if (!config_check_cond(srv, con, dc)) continue;
29902 + /* merge config */
29903 + for (j = 0; j < dc->value->used; j++) {
29904 + data_unset *du = dc->value->data[j];
29906 + if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.backends"))) {
29907 + PATCH_OPTION(backends);
29908 + PATCH_OPTION(backlog);
29909 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.debug"))) {
29910 + PATCH_OPTION(debug);
29911 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.balancer"))) {
29912 + PATCH_OPTION(balancer);
29913 + } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("proxy.protocol"))) {
29914 + PATCH_OPTION(protocol);
29923 +SUBREQUEST_FUNC(mod_proxy_core_check_extension) {
29924 + plugin_data *p = p_d;
29925 + proxy_session *sess = con->plugin_ctx[p->id]; /* if this is the second round, sess is already prepared */
29927 + /* check if we have a matching conditional for this request */
29929 + if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
29931 + mod_proxy_core_patch_connection(srv, con, p);
29934 + * 0. build session
29935 + * 1. get a proxy connection
29936 + * 2. create the http-request header
29937 + * 3. stream the content to the backend
29938 + * 4. wait for http-response header
29939 + * 5. decode the response + parse the response
29940 + * 6. stream the response-content to the client
29941 + * 7. kill session
29945 + /* a session lives for a single request */
29946 + sess = proxy_session_init();
29948 + con->plugin_ctx[p->id] = sess;
29949 + con->mode = p->id;
29951 + sess->remote_con = con;
29954 + switch (sess->state) {
29955 + case PROXY_STATE_CONNECTING:
29956 + /* this connections is waited 10 seconds to connect to the backend
29957 + * and didn't got a successful connection yet, sending timeout */
29958 + if (srv->cur_ts - con->request_start > 10) {
29959 + con->http_status = 504; /* gateway timeout */
29961 + if (sess->proxy_con) {
29962 + /* if we are waiting for a proxy-connection right now, close it */
29963 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
29965 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
29966 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
29968 + proxy_connection_free(sess->proxy_con);
29970 + sess->proxy_con = NULL;
29973 + return HANDLER_FINISHED;
29976 + /* handle-request-timeout, */
29977 + if (srv->cur_ts - con->request_start > 60) {
29978 + TRACE("request runs longer than 60sec: current state: %d", sess->state);
29983 + /* if the WRITE fails from the start, restart the connection */
29985 + if (sess->proxy_con == NULL) {
29986 + proxy_address *address = NULL;
29987 + if (NULL == (sess->proxy_backend = proxy_get_backend(srv, con, p, con->uri.path))) {
29988 + /* no connection pool for this location */
29993 + * ask the balancer for the next address and
29994 + * check the connection pool if we have a connection open
29995 + * for that address
29997 + if (NULL == (address = proxy_backend_balance(srv, con, sess->proxy_backend))) {
29998 + /* we don't have any backends to connect to */
29999 + proxy_request *req;
30001 + /* connection pool is full, queue the request for now */
30002 + req = proxy_request_init();
30003 + req->added_ts = srv->cur_ts;
30006 + TRACE("backlog: all backends are down, putting %s (%d) into the backlog", BUF_STR(con->uri.path), con->sock->fd);
30007 + proxy_backlog_push(p->conf.backlog, req);
30009 + /* no, not really a event,
30010 + * we just want to block the outer loop from stepping forward
30012 + * the trigger will bring this connection back into the game
30014 + return HANDLER_WAIT_FOR_EVENT;
30017 + if (PROXY_CONNECTIONPOOL_FULL == proxy_connection_pool_get_connection(
30018 + sess->proxy_backend->pool,
30020 + &(sess->proxy_con))) {
30021 + proxy_request *req;
30023 + /* connection pool is full, queue the request for now */
30024 + req = proxy_request_init();
30025 + req->added_ts = srv->cur_ts;
30028 + TRACE("backlog: the con-pool is full, putting %s (%d) into the backlog", con->uri.path->ptr, con->sock->fd);
30029 + proxy_backlog_push(p->conf.backlog, req);
30031 + /* no, not really a event,
30032 + * we just want to block the outer loop from stepping forward
30034 + * the trigger will bring this connection back into the game
30036 + return HANDLER_WAIT_FOR_EVENT;
30039 + /* a fresh connection, we need address for it */
30040 + if (sess->proxy_con->state == PROXY_CONNECTION_STATE_CONNECTING) {
30041 + sess->state = PROXY_STATE_UNSET;
30042 + sess->bytes_read = 0;
30044 + /* we are already connected */
30045 + sess->state = PROXY_STATE_CONNECTED;
30047 + /* the connection was idling and using the fdevent_idle-handler
30048 + * switch it back to the normal proxy-event-handler */
30049 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30050 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30052 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent, sess);
30053 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30057 + switch (proxy_state_engine(srv, con, p, sess)) {
30058 + case HANDLER_WAIT_FOR_EVENT:
30059 + return HANDLER_WAIT_FOR_EVENT;
30060 + case HANDLER_COMEBACK:
30061 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30063 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30064 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30066 + proxy_connection_free(sess->proxy_con);
30068 + sess->proxy_con = NULL;
30069 + /* restart the connection to the backend */
30070 + TRACE("%s", "write failed, restarting request");
30072 + case HANDLER_GO_ON:
30073 + return HANDLER_GO_ON;
30075 + return HANDLER_ERROR;
30079 + /* should not be reached */
30080 + return HANDLER_ERROR;
30084 + * end of the connection to the client
30086 +REQUESTDONE_FUNC(mod_proxy_connection_close_callback) {
30087 + plugin_data *p = p_d;
30089 + if (con->mode != p->id) return HANDLER_GO_ON;
30091 + return HANDLER_GO_ON;
30095 + * end of a request
30097 +CONNECTION_FUNC(mod_proxy_connection_reset) {
30098 + plugin_data *p = p_d;
30099 + proxy_session *sess = con->plugin_ctx[p->id];
30101 + if (con->mode != p->id) return HANDLER_GO_ON;
30103 + if (sess->proxy_con) {
30104 + switch (sess->proxy_con->state) {
30105 + case PROXY_CONNECTION_STATE_CONNECTED:
30106 + sess->proxy_con->state = PROXY_CONNECTION_STATE_IDLE;
30108 + /* ignore events as the FD is idle, we might get a HUP as the remote connection might close */
30109 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30110 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30112 + fdevent_register(srv->ev, sess->proxy_con->sock, proxy_handle_fdevent_idle, sess->proxy_con);
30113 + fdevent_event_add(srv->ev, sess->proxy_con->sock, FDEVENT_IN);
30116 + case PROXY_CONNECTION_STATE_CLOSED:
30117 + proxy_connection_pool_remove_connection(sess->proxy_backend->pool, sess->proxy_con);
30119 + fdevent_event_del(srv->ev, sess->proxy_con->sock);
30120 + fdevent_unregister(srv->ev, sess->proxy_con->sock);
30122 + proxy_connection_free(sess->proxy_con);
30124 + case PROXY_CONNECTION_STATE_IDLE:
30125 + TRACE("%s", "... connection is already back in the pool");
30128 + ERROR("connection is in a unexpected state at close-time: %d", sess->proxy_con->state);
30132 + /* if we have the connection in the backlog, remove it */
30133 + proxy_backlog_remove_connection(p->conf.backlog, con);
30137 + proxy_session_free(sess);
30139 + con->plugin_ctx[p->id] = NULL;
30141 + return HANDLER_GO_ON;
30147 + * cleanup dead connections once a second
30149 + * the idling event-handler can't cleanup connections itself and has to wait until the
30150 + * trigger cleans up
30152 +handler_t mod_proxy_trigger_context(server *srv, plugin_config *p) {
30154 + proxy_request *req;
30156 + for (i = 0; i < p->backends->used; i++) {
30157 + proxy_backend *backend = p->backends->ptr[i];
30158 + proxy_connection_pool *pool = backend->pool;
30159 + proxy_address_pool *address_pool = backend->address_pool;
30161 + for (j = 0; j < pool->used; ) {
30162 + proxy_connection *proxy_con = pool->ptr[j];
30164 + /* remove-con is removing the current con and moves the good connections to the left
30165 + * no need to increment i */
30166 + if (proxy_con->state == PROXY_CONNECTION_STATE_CLOSED) {
30167 + proxy_connection_pool_remove_connection(backend->pool, proxy_con);
30169 + fdevent_event_del(srv->ev, proxy_con->sock);
30170 + fdevent_unregister(srv->ev, proxy_con->sock);
30172 + proxy_connection_free(proxy_con);
30178 + /* active the disabled addresses again */
30179 + for (j = 0; j < address_pool->used; j++) {
30180 + proxy_address *address = address_pool->ptr[j];
30182 + if (address->state != PROXY_ADDRESS_STATE_DISABLED) continue;
30184 + if (srv->cur_ts > address->disabled_until) {
30185 + address->disabled_until = 0;
30186 + address->state = PROXY_ADDRESS_STATE_ACTIVE;
30191 + /* wake up the connections from the backlog */
30192 + while ((req = proxy_backlog_shift(p->backlog))) {
30193 + connection *con = req->con;
30195 + joblist_append(srv, con);
30197 + proxy_request_free(req);
30200 + return HANDLER_GO_ON;
30203 +TRIGGER_FUNC(mod_proxy_trigger) {
30204 + plugin_data *p = p_d;
30207 + for (i = 0; i < srv->config_context->used; i++) {
30208 + mod_proxy_trigger_context(srv, p->config_storage[i]);
30211 + return HANDLER_GO_ON;
30214 +int mod_proxy_core_plugin_init(plugin *p) {
30215 + p->version = LIGHTTPD_VERSION_ID;
30216 + p->name = buffer_init_string("mod_proxy_core");
30218 + p->init = mod_proxy_core_init;
30219 + p->cleanup = mod_proxy_core_free;
30220 + p->set_defaults = mod_proxy_core_set_defaults;
30221 + p->handle_uri_clean = mod_proxy_core_check_extension;
30222 + p->handle_subrequest_start = mod_proxy_core_check_extension;
30223 + p->handle_subrequest = mod_proxy_core_check_extension;
30224 + p->connection_reset = mod_proxy_connection_reset;
30225 + p->handle_connection_close = mod_proxy_connection_close_callback;
30226 + p->handle_trigger = mod_proxy_trigger;
30232 --- ../lighttpd-1.4.11/src/mod_proxy_core.h 1970-01-01 03:00:00.000000000 +0300
30233 +++ lighttpd-1.4.12/src/mod_proxy_core.h 2006-07-18 13:03:40.000000000 +0300
30235 +#ifndef _MOD_PROXY_CORE_H_
30236 +#define _MOD_PROXY_CORE_H_
30238 +#include "buffer.h"
30241 +#define PROXY_BACKEND_CONNECT_PARAMS \
30242 + (server *srv, connection *con, void *p_d)
30244 +#define PROXY_BACKEND_CONNECT_RETVAL handler_t
30246 +#define PROXY_BACKEND_CONNECT(name) \
30247 + PROXY_BACKEND_CONNECT_RETVAL name PROXY_BACKEND_CONNECT_PARAMS
30249 +#define PROXY_BACKEND_CONNECT_PTR(name) \
30250 + PROXY_BACKEND_CONNECT_RETVAL (* name)PROXY_BACKEND_CONNECT_PARAMS
30253 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.c 1970-01-01 03:00:00.000000000 +0300
30254 +++ lighttpd-1.4.12/src/mod_proxy_core_address.c 2006-07-18 13:03:40.000000000 +0300
30256 +#include <stdlib.h>
30257 +#include <string.h>
30260 +#include "sys-socket.h"
30261 +#include "mod_proxy_core_address.h"
30263 +proxy_address *proxy_address_init(void) {
30264 + proxy_address *address;
30266 + address = calloc(1, sizeof(*address));
30268 + address->name = buffer_init();
30273 +void proxy_address_free(proxy_address *address) {
30274 + if (!address) return;
30276 + buffer_free(address->name);
30282 +proxy_address_pool *proxy_address_pool_init(void) {
30283 + proxy_address_pool *address_pool;
30285 + address_pool = calloc(1, sizeof(*address_pool));
30287 + return address_pool;
30290 +void proxy_address_pool_free(proxy_address_pool *address_pool) {
30291 + if (!address_pool) return;
30293 + FOREACH(address_pool, element, proxy_address_free(element))
30295 + free(address_pool);
30298 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address) {
30299 + ARRAY_STATIC_PREPARE_APPEND(address_pool);
30301 + address_pool->ptr[address_pool->used++] = address;
30304 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *name) {
30305 + struct addrinfo *res = NULL, pref, *cur;
30308 + pref.ai_flags = 0;
30309 + pref.ai_family = PF_UNSPEC;
30310 + pref.ai_socktype = SOCK_STREAM;
30311 + pref.ai_protocol = 0;
30312 + pref.ai_addrlen = 0;
30313 + pref.ai_addr = NULL;
30314 + pref.ai_canonname = NULL;
30315 + pref.ai_next = NULL;
30317 + if (0 != (ret = getaddrinfo(name->ptr, "80", &pref, &res))) {
30318 + ERROR("getaddrinfo failed: %s", gai_strerror(ret));
30323 + for (cur = res; cur; cur = cur->ai_next) {
30324 + proxy_address *a = proxy_address_init();
30326 + memcpy(&(a->addr), cur->ai_addr, cur->ai_addrlen);
30328 + a->state = PROXY_ADDRESS_STATE_ACTIVE;
30330 + buffer_copy_string(a->name, inet_ntoa(a->addr.ipv4.sin_addr));
30332 + proxy_address_pool_add(address_pool, a);
30335 + freeaddrinfo(res);
30341 --- ../lighttpd-1.4.11/src/mod_proxy_core_address.h 1970-01-01 03:00:00.000000000 +0300
30342 +++ lighttpd-1.4.12/src/mod_proxy_core_address.h 2006-07-18 13:03:40.000000000 +0300
30344 +#ifndef _MOD_PROXY_CORE_ADDRESS_H_
30345 +#define _MOD_PROXY_CORE_ADDRESS_H_
30348 +#include "buffer.h"
30349 +#include "sys-socket.h"
30350 +#include "array-static.h"
30353 + PROXY_ADDRESS_STATE_UNSET,
30354 + PROXY_ADDRESS_STATE_ACTIVE,
30355 + PROXY_ADDRESS_STATE_DISABLED,
30356 +} proxy_address_state_t;
30361 + buffer *name; /* a inet_ntoa() prepresentation of the address */
30363 + time_t last_used;
30364 + time_t disabled_until;
30366 + proxy_address_state_t state;
30369 +ARRAY_STATIC_DEF(proxy_address_pool, proxy_address, );
30371 +proxy_address_pool *proxy_address_pool_init(void);
30372 +void proxy_address_pool_free(proxy_address_pool *address_pool);
30373 +void proxy_address_pool_add(proxy_address_pool *address_pool, proxy_address *address);
30374 +int proxy_address_pool_add_string(proxy_address_pool *address_pool, buffer *address);
30377 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.c 1970-01-01 03:00:00.000000000 +0300
30378 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.c 2006-07-18 13:03:40.000000000 +0300
30380 +#include <stdlib.h>
30382 +#include "mod_proxy_core_backend.h"
30383 +#include "mod_proxy_core_pool.h"
30384 +#include "mod_proxy_core_address.h"
30386 +proxy_backend *proxy_backend_init(void) {
30387 + proxy_backend *backend;
30389 + backend = calloc(1, sizeof(*backend));
30390 + backend->pool = proxy_connection_pool_init();
30391 + backend->address_pool = proxy_address_pool_init();
30392 + backend->balancer = PROXY_BALANCE_RR;
30397 +void proxy_backend_free(proxy_backend *backend) {
30398 + if (!backend) return;
30400 + proxy_address_pool_free(backend->address_pool);
30401 + proxy_connection_pool_free(backend->pool);
30406 +proxy_backends *proxy_backends_init(void) {
30407 + proxy_backends *backends;
30409 + backends = calloc(1, sizeof(*backends));
30414 +void proxy_backends_free(proxy_backends *backends) {
30415 + FOREACH(backends, element, proxy_backend_free(element))
30420 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend) {
30421 + ARRAY_STATIC_PREPARE_APPEND(backends);
30423 + backends->ptr[backends->used++] = backend;
30425 --- ../lighttpd-1.4.11/src/mod_proxy_core_backend.h 1970-01-01 03:00:00.000000000 +0300
30426 +++ lighttpd-1.4.12/src/mod_proxy_core_backend.h 2006-07-18 13:03:40.000000000 +0300
30428 +#ifndef _MOD_PROXY_CORE_BACKEND_H_
30429 +#define _MOD_PROXY_CORE_BACKEND_H_
30431 +#include "array-static.h"
30432 +#include "buffer.h"
30433 +#include "mod_proxy_core_address.h"
30434 +#include "mod_proxy_core_pool.h"
30435 +#include "sys-socket.h"
30438 + * a single DNS name might explode to several IP addresses
30441 + * - http://foo.bar/suburl/
30442 + * - https://foo.bar/suburl/
30443 + * - unix:/tmp/socket
30444 + * - tcp://foobar:1025/
30451 + * request-url-rewrite
30452 + * response-url-rewrite
30455 + PROXY_BALANCE_UNSET,
30456 + PROXY_BALANCE_FAIR,
30457 + PROXY_BALANCE_HASH,
30459 +} proxy_balance_t;
30464 + proxy_connection_pool *pool; /* pool of active connections */
30465 + int use_keepalive;
30467 + proxy_address_pool *address_pool; /* possible destination-addresses, disabling is done here */
30468 + proxy_balance_t balancer; /* how to choose a address from the address-pool */
30471 +ARRAY_STATIC_DEF(proxy_backends, proxy_backend, );
30473 +proxy_backend *proxy_backend_init(void);
30474 +void proxy_backend_free(proxy_backend *backend);
30476 +proxy_backends *proxy_backends_init(void);
30477 +void proxy_backends_free(proxy_backends *backends);
30478 +void proxy_backends_add(proxy_backends *backends, proxy_backend *backend);
30482 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.c 1970-01-01 03:00:00.000000000 +0300
30483 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.c 2006-07-18 13:03:40.000000000 +0300
30485 +#include <stdlib.h>
30487 +#include "mod_proxy_core_backlog.h"
30488 +#include "array-static.h"
30490 +proxy_backlog *proxy_backlog_init(void) {
30491 + STRUCT_INIT(proxy_backlog, backlog);
30496 +void proxy_backlog_free(proxy_backlog *backlog) {
30497 + if (!backlog) return;
30502 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req) {
30503 + /* first entry */
30504 + if (NULL == backlog->first) {
30505 + backlog->first = backlog->last = req;
30507 + backlog->last->next = req;
30508 + backlog->last = req;
30510 + backlog->length++;
30516 + * remove the first element from the backlog
30518 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog) {
30519 + proxy_request *req = NULL;
30521 + if (!backlog->first) return req;
30523 + backlog->length--;
30525 + req = backlog->first;
30527 + backlog->first = req->next;
30529 + /* the backlog is empty */
30530 + if (backlog->first == NULL) backlog->last = NULL;
30535 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con) {
30536 + proxy_request *req = NULL;
30538 + if (!backlog->first) return -1;
30539 + if (!con) return -1;
30541 + /* the first element is what we look for */
30542 + if (backlog->first->con == con) {
30543 + req = backlog->first;
30545 + backlog->first = req->next;
30546 + if (backlog->first == NULL) backlog->last = NULL;
30548 + backlog->length--;
30550 + proxy_request_free(req);
30556 + for (req = backlog->first; req && req->next; req = req->next) {
30557 + proxy_request *cur;
30559 + if (req->next->con != con) continue;
30561 + backlog->length--;
30562 + /* the next node is our searched connection */
30565 + req->next = cur->next;
30567 + /* the next node is the last one, make the current the new last */
30568 + if (cur == backlog->last) {
30569 + backlog->last = req;
30571 + cur->next = NULL;
30573 + proxy_request_free(req);
30581 +proxy_request *proxy_request_init(void) {
30582 + STRUCT_INIT(proxy_request, request);
30587 +void proxy_request_free(proxy_request *request) {
30588 + if (!request) return;
30594 --- ../lighttpd-1.4.11/src/mod_proxy_core_backlog.h 1970-01-01 03:00:00.000000000 +0300
30595 +++ lighttpd-1.4.12/src/mod_proxy_core_backlog.h 2006-07-18 13:03:40.000000000 +0300
30597 +#ifndef _MOD_PROXY_CORE_BACKLOG_H_
30598 +#define _MOD_PROXY_CORE_BACKLOG_H_
30600 +#include <sys/types.h>
30601 +#include <sys/time.h>
30603 +typedef struct _proxy_request {
30604 + void *con; /* a pointer to the client-connection, (type: connection) */
30606 + time_t added_ts; /* when was the entry added (for timeout handling) */
30608 + struct _proxy_request *next;
30612 + * a we can't get a connection from the pool, queue the request in the
30613 + * request queue (FIFO)
30615 + * - the queue is infinite
30616 + * - entries are removed after a timeout (status 504)
30619 + proxy_request *first; /* pull() does q->first = q->first->next */
30620 + proxy_request *last; /* push() does q->last = r */
30625 +proxy_backlog *proxy_backlog_init(void);
30626 +void proxy_backlog_free(proxy_backlog *backlog);
30629 + * append a request to the end
30631 + * @return 0 in success, -1 if full
30633 +int proxy_backlog_push(proxy_backlog *backlog, proxy_request *req);
30636 + * remove the first request from the backlog
30638 + * @return NULL if backlog is empty, the request otherwise
30640 +proxy_request *proxy_backlog_shift(proxy_backlog *backlog);
30642 + * remove the request with the connection 'con' from the backlog
30644 + * @return -1 if not found, 0 otherwise
30646 +int proxy_backlog_remove_connection(proxy_backlog *backlog, void *con);
30648 +proxy_request *proxy_request_init(void);
30649 +void proxy_request_free(proxy_request *req);
30653 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.c 1970-01-01 03:00:00.000000000 +0300
30654 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.c 2006-07-18 13:03:40.000000000 +0300
30657 +#include <stdlib.h>
30659 +#include "array-static.h"
30660 +#include "sys-files.h"
30662 +#include "mod_proxy_core_pool.h"
30664 +proxy_connection * proxy_connection_init(void) {
30665 + proxy_connection *con;
30667 + con = calloc(1, sizeof(*con));
30669 + con->sock = iosocket_init();
30674 +void proxy_connection_free(proxy_connection *con) {
30675 + if (!con) return;
30677 + iosocket_free(con->sock);
30682 +proxy_connection_pool *proxy_connection_pool_init(void) {
30683 + proxy_connection_pool *pool;
30685 + pool = calloc(1, sizeof(*pool));
30687 + /* default: max parallel connections to the backend
30689 + * this should match max-procs if we manage the procs ourself
30692 + pool->max_size = 8;
30697 +void proxy_connection_pool_free(proxy_connection_pool *pool) {
30700 + if (!pool) return;
30702 + for (i = 0; i < pool->used; i++) {
30703 + proxy_connection_free(pool->ptr[i]);
30706 + if (pool->size) free(pool->ptr);
30711 +void proxy_connection_pool_add_connection(proxy_connection_pool *pool, proxy_connection *c) {
30712 + ARRAY_STATIC_PREPARE_APPEND(pool);
30714 + pool->ptr[pool->used++] = c;
30717 + * remove the connection from the pool
30719 + * usually called on conn-shutdown
30721 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c) {
30724 + if (pool->used == 0) return -1; /* empty */
30726 + for (i = 0; i < pool->used; i++) {
30727 + if (pool->ptr[i] == c) {
30732 + if (i == pool->used) return -1; /* not found */
30735 + * move all elements one to the left
30737 + * if the last element is going to be removed, skip the loop
30739 + for (; i < pool->used - 1; i++) {
30740 + pool->ptr[i] = pool->ptr[i + 1];
30748 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon) {
30749 + proxy_connection *proxy_con = NULL;
30752 + /* search for a idling proxy connection with the given address */
30753 + for (i = 0; i < pool->used; i++) {
30754 + proxy_con = pool->ptr[i];
30756 + if (proxy_con->address == address &&
30757 + proxy_con->state == PROXY_CONNECTION_STATE_IDLE) {
30762 + if (i == pool->used) {
30763 + /* no idling connection found */
30765 + if (pool->used == pool->max_size) return PROXY_CONNECTIONPOOL_FULL;
30767 + proxy_con = proxy_connection_init();
30769 + proxy_con->state = PROXY_CONNECTION_STATE_CONNECTING;
30770 + proxy_con->address = address;
30772 + proxy_connection_pool_add_connection(pool, proxy_con);
30774 + proxy_con->state = PROXY_CONNECTION_STATE_CONNECTED;
30777 + *rcon = proxy_con;
30779 + return PROXY_CONNECTIONPOOL_GOT_CONNECTION;
30783 --- ../lighttpd-1.4.11/src/mod_proxy_core_pool.h 1970-01-01 03:00:00.000000000 +0300
30784 +++ lighttpd-1.4.12/src/mod_proxy_core_pool.h 2006-07-18 13:03:40.000000000 +0300
30786 +#ifndef _MOD_PROXY_CORE_POOL_H_
30787 +#define _MOD_PROXY_CORE_POOL_H_
30789 +#include <sys/time.h>
30791 +#include "iosocket.h"
30792 +#include "array-static.h"
30793 +#include "mod_proxy_core_address.h"
30796 + PROXY_CONNECTION_STATE_UNSET,
30797 + PROXY_CONNECTION_STATE_CONNECTING,
30798 + PROXY_CONNECTION_STATE_CONNECTED,
30799 + PROXY_CONNECTION_STATE_IDLE,
30800 + PROXY_CONNECTION_STATE_CLOSED,
30801 +} proxy_connection_state_t;
30804 + * a connection to a proxy backend
30806 + * the connection is independent of the incoming request to allow keep-alive
30811 + time_t last_read; /* timeout handling for keep-alive connections */
30812 + time_t last_write;
30814 + proxy_address *address; /* the struct sock_addr for the sock */
30816 + proxy_connection_state_t state;
30817 +} proxy_connection;
30819 +ARRAY_STATIC_DEF(proxy_connection_pool, proxy_connection, size_t max_size;);
30822 + PROXY_CONNECTIONPOOL_UNSET,
30823 + PROXY_CONNECTIONPOOL_FULL,
30824 + PROXY_CONNECTIONPOOL_GOT_CONNECTION,
30825 +} proxy_connection_pool_t;
30827 +proxy_connection_pool *proxy_connection_pool_init(void);
30828 +void proxy_connection_pool_free(proxy_connection_pool *pool);
30830 +proxy_connection_pool_t proxy_connection_pool_get_connection(proxy_connection_pool *pool, proxy_address *address, proxy_connection **rcon);
30831 +int proxy_connection_pool_remove_connection(proxy_connection_pool *pool, proxy_connection *c);
30833 +proxy_connection * proxy_connection_init(void);
30834 +void proxy_connection_free(proxy_connection *pool);
30838 --- ../lighttpd-1.4.11/src/mod_redirect.c 2006-02-08 15:38:06.000000000 +0200
30839 +++ lighttpd-1.4.12/src/mod_redirect.c 2006-07-16 00:26:04.000000000 +0300
30840 @@ -22,35 +22,35 @@
30846 plugin_config **config_storage;
30848 - plugin_config conf;
30850 + plugin_config conf;
30853 INIT_FUNC(mod_redirect_init) {
30857 p = calloc(1, sizeof(*p));
30860 p->match_buf = buffer_init();
30861 p->location = buffer_init();
30867 FREE_FUNC(mod_redirect_free) {
30868 plugin_data *p = p_d;
30871 if (!p) return HANDLER_GO_ON;
30873 if (p->config_storage) {
30875 for (i = 0; i < srv->config_context->used; i++) {
30876 plugin_config *s = p->config_storage[i];
30879 pcre_keyvalue_buffer_free(s->redirect);
30884 free(p->config_storage);
30887 buffer_free(p->match_buf);
30888 buffer_free(p->location);
30894 return HANDLER_GO_ON;
30897 @@ -69,195 +69,137 @@
30898 plugin_data *p = p_d;
30902 - config_values_t cv[] = {
30904 + config_values_t cv[] = {
30905 { "url.redirect", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
30906 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
30910 if (!p) return HANDLER_ERROR;
30914 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
30917 for (i = 0; i < srv->config_context->used; i++) {
30921 data_array *da = (data_array *)du;
30924 s = calloc(1, sizeof(plugin_config));
30925 s->redirect = pcre_keyvalue_buffer_init();
30928 cv[0].destination = s->redirect;
30931 p->config_storage[i] = s;
30932 ca = ((data_config *)srv->config_context->data[i])->value;
30935 if (0 != config_insert_values_global(srv, ca, cv)) {
30936 return HANDLER_ERROR;
30940 if (NULL == (du = array_get_element(ca, "url.redirect"))) {
30941 /* no url.redirect defined */
30946 if (du->type != TYPE_ARRAY) {
30947 - log_error_write(srv, __FILE__, __LINE__, "sss",
30948 + log_error_write(srv, __FILE__, __LINE__, "sss",
30949 "unexpected type for key: ", "url.redirect", "array of strings");
30952 return HANDLER_ERROR;
30956 da = (data_array *)du;
30959 for (j = 0; j < da->value->used; j++) {
30960 if (da->value->data[j]->type != TYPE_STRING) {
30961 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
30962 - "unexpected type for key: ",
30964 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
30965 + "unexpected type for key: ",
30967 "[", da->value->data[j]->key, "](string)");
30970 return HANDLER_ERROR;
30973 - if (0 != pcre_keyvalue_buffer_append(s->redirect,
30975 + if (0 != pcre_keyvalue_buffer_append(s->redirect,
30976 ((data_string *)(da->value->data[j]))->key->ptr,
30977 ((data_string *)(da->value->data[j]))->value->ptr)) {
30979 - log_error_write(srv, __FILE__, __LINE__, "sb",
30981 + log_error_write(srv, __FILE__, __LINE__, "sb",
30982 "pcre-compile failed for", da->value->data[j]->key);
30988 return HANDLER_GO_ON;
30991 static int mod_redirect_patch_connection(server *srv, connection *con, plugin_data *p) {
30993 plugin_config *s = p->config_storage[0];
30996 p->conf.redirect = s->redirect;
30999 /* skip the first, the global context */
31000 for (i = 1; i < srv->config_context->used; i++) {
31001 data_config *dc = (data_config *)srv->config_context->data[i];
31002 s = p->config_storage[i];
31005 /* condition didn't match */
31006 if (!config_check_cond(srv, con, dc)) continue;
31010 for (j = 0; j < dc->value->used; j++) {
31011 data_unset *du = dc->value->data[j];
31014 if (0 == strcmp(du->key->ptr, "url.redirect")) {
31015 p->conf.redirect = s->redirect;
31016 p->conf.context = dc;
31025 static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
31027 plugin_data *p = p_data;
31036 * e.g. redirect /base/ to /index.php?section=base
31042 mod_redirect_patch_connection(srv, con, p);
31045 buffer_copy_string_buffer(p->match_buf, con->request.uri);
31047 - for (i = 0; i < p->conf.redirect->used; i++) {
31049 - pcre_extra *extra;
31050 - const char *pattern;
31051 - size_t pattern_len;
31053 - pcre_keyvalue *kv = p->conf.redirect->kv[i];
31058 - extra = kv->key_extra;
31059 - pattern = kv->value->ptr;
31060 - pattern_len = kv->value->used - 1;
31062 - if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31063 - if (n != PCRE_ERROR_NOMATCH) {
31064 - log_error_write(srv, __FILE__, __LINE__, "sd",
31065 - "execution error while matching: ", n);
31066 - return HANDLER_ERROR;
31069 - const char **list;
31070 - size_t start, end;
31074 - pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31076 - /* search for $[0-9] */
31078 - buffer_reset(p->location);
31080 - start = 0; end = pattern_len;
31081 - for (k = 0; k < pattern_len; k++) {
31082 - if ((pattern[k] == '$' || pattern[k] == '%') &&
31083 - isdigit((unsigned char)pattern[k + 1])) {
31086 - size_t num = pattern[k + 1] - '0';
31090 - buffer_append_string_len(p->location, pattern + start, end - start);
31092 - if (pattern[k] == '$') {
31093 - /* n is always > 0 */
31094 - if (num < (size_t)n) {
31095 - buffer_append_string(p->location, list[num]);
31098 - config_append_cond_match_buffer(con, p->conf.context, p->location, num);
31106 - buffer_append_string_len(p->location, pattern + start, pattern_len - start);
31110 - response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31112 - con->http_status = 301;
31113 - con->file_finished = 1;
31115 - return HANDLER_FINISHED;
31117 + i = config_exec_pcre_keyvalue_buffer(con, p->conf.redirect, p->conf.context, p->match_buf, p->location);
31120 + response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));
31122 + con->http_status = 301;
31123 + con->file_finished = 1;
31125 + return HANDLER_FINISHED;
31127 + else if (i != PCRE_ERROR_NOMATCH) {
31128 + log_error_write(srv, __FILE__, __LINE__, "s",
31129 + "execution error while matching", i);
31141 return HANDLER_GO_ON;
31144 @@ -265,13 +207,13 @@
31145 int mod_redirect_plugin_init(plugin *p) {
31146 p->version = LIGHTTPD_VERSION_ID;
31147 p->name = buffer_init_string("redirect");
31150 p->init = mod_redirect_init;
31151 p->handle_uri_clean = mod_redirect_uri_handler;
31152 p->set_defaults = mod_redirect_set_defaults;
31153 p->cleanup = mod_redirect_free;
31161 --- ../lighttpd-1.4.11/src/mod_rewrite.c 2005-09-29 20:59:10.000000000 +0300
31162 +++ lighttpd-1.4.12/src/mod_rewrite.c 2006-07-16 00:26:03.000000000 +0300
31167 -#ifdef HAVE_PCRE_H
31177 - rewrite_rule **ptr;
31181 -} rewrite_rule_buffer;
31184 - rewrite_rule_buffer *rewrite;
31185 + pcre_keyvalue_buffer *rewrite;
31187 data_config *context; /* to which apply me */
31190 @@ -42,20 +26,20 @@
31196 plugin_config **config_storage;
31198 - plugin_config conf;
31200 + plugin_config conf;
31203 static handler_ctx * handler_ctx_init() {
31204 handler_ctx * hctx;
31207 hctx = calloc(1, sizeof(*hctx));
31210 hctx->state = REWRITE_STATE_UNSET;
31217 @@ -63,207 +47,136 @@
31221 -rewrite_rule_buffer *rewrite_rule_buffer_init(void) {
31222 - rewrite_rule_buffer *kvb;
31224 - kvb = calloc(1, sizeof(*kvb));
31229 -int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
31230 -#ifdef HAVE_PCRE_H
31232 - const char *errptr;
31235 - if (!key) return -1;
31237 - if (kvb->size == 0) {
31241 - kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));
31243 - for(i = 0; i < kvb->size; i++) {
31244 - kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31246 - } else if (kvb->used == kvb->size) {
31249 - kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));
31251 - for(i = kvb->used; i < kvb->size; i++) {
31252 - kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
31256 - if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
31257 - 0, &errptr, &erroff, NULL))) {
31262 - kvb->ptr[kvb->used]->value = buffer_init();
31263 - buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
31264 - kvb->ptr[kvb->used]->once = once;
31279 -void rewrite_rule_buffer_free(rewrite_rule_buffer *kvb) {
31280 -#ifdef HAVE_PCRE_H
31283 - for (i = 0; i < kvb->size; i++) {
31284 - if (kvb->ptr[i]->key) pcre_free(kvb->ptr[i]->key);
31285 - if (kvb->ptr[i]->value) buffer_free(kvb->ptr[i]->value);
31286 - free(kvb->ptr[i]);
31289 - if (kvb->ptr) free(kvb->ptr);
31296 INIT_FUNC(mod_rewrite_init) {
31300 p = calloc(1, sizeof(*p));
31303 p->match_buf = buffer_init();
31309 FREE_FUNC(mod_rewrite_free) {
31310 plugin_data *p = p_d;
31315 if (!p) return HANDLER_GO_ON;
31318 buffer_free(p->match_buf);
31319 if (p->config_storage) {
31321 for (i = 0; i < srv->config_context->used; i++) {
31322 plugin_config *s = p->config_storage[i];
31323 - rewrite_rule_buffer_free(s->rewrite);
31325 + pcre_keyvalue_buffer_free(s->rewrite);
31326 + buffer_free(s->once);
31330 free(p->config_storage);
31337 return HANDLER_GO_ON;
31340 static int parse_config_entry(server *srv, plugin_config *s, array *ca, const char *option, int once) {
31344 if (NULL != (du = array_get_element(ca, option))) {
31345 data_array *da = (data_array *)du;
31349 if (du->type != TYPE_ARRAY) {
31350 - log_error_write(srv, __FILE__, __LINE__, "sss",
31351 + log_error_write(srv, __FILE__, __LINE__, "sss",
31352 "unexpected type for key: ", option, "array of strings");
31355 return HANDLER_ERROR;
31359 da = (data_array *)du;
31362 for (j = 0; j < da->value->used; j++) {
31363 if (da->value->data[j]->type != TYPE_STRING) {
31364 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
31365 - "unexpected type for key: ",
31367 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
31368 + "unexpected type for key: ",
31370 "[", da->value->data[j]->key, "](string)");
31373 return HANDLER_ERROR;
31376 - if (0 != rewrite_rule_buffer_append(s->rewrite,
31377 - ((data_string *)(da->value->data[j]))->key,
31378 - ((data_string *)(da->value->data[j]))->value,
31381 + if (0 != pcre_keyvalue_buffer_append(s->rewrite,
31382 + ((data_string *)(da->value->data[j]))->key->ptr,
31383 + ((data_string *)(da->value->data[j]))->value->ptr)) {
31385 - log_error_write(srv, __FILE__, __LINE__, "sb",
31386 + log_error_write(srv, __FILE__, __LINE__, "sb",
31387 "pcre-compile failed for", da->value->data[j]->key);
31389 - log_error_write(srv, __FILE__, __LINE__, "s",
31390 + log_error_write(srv, __FILE__, __LINE__, "s",
31391 "pcre support is missing, please install libpcre and the headers");
31396 + buffer_append_string_len(s->once, CONST_STR_LEN("1"));
31398 + buffer_append_string_len(s->once, CONST_STR_LEN("0"));
31407 SETDEFAULTS_FUNC(mod_rewrite_set_defaults) {
31408 plugin_data *p = p_d;
31411 - config_values_t cv[] = {
31413 + config_values_t cv[] = {
31414 { "url.rewrite-repeat", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
31415 { "url.rewrite-once", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
31417 - /* old names, still supported
31420 + /* old names, still supported
31422 * url.rewrite remapped to url.rewrite-once
31423 * url.rewrite-final is url.rewrite-once
31427 { "url.rewrite", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
31428 { "url.rewrite-final", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
31429 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
31433 if (!p) return HANDLER_ERROR;
31437 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
31440 for (i = 0; i < srv->config_context->used; i++) {
31445 s = calloc(1, sizeof(plugin_config));
31446 - s->rewrite = rewrite_rule_buffer_init();
31448 - cv[0].destination = s->rewrite;
31449 - cv[1].destination = s->rewrite;
31450 - cv[2].destination = s->rewrite;
31452 + s->rewrite = pcre_keyvalue_buffer_init();
31453 + s->once = buffer_init();
31455 p->config_storage[i] = s;
31456 ca = ((data_config *)srv->config_context->data[i])->value;
31459 if (0 != config_insert_values_global(srv, ca, cv)) {
31460 return HANDLER_ERROR;
31464 parse_config_entry(srv, s, ca, "url.rewrite-once", 1);
31465 parse_config_entry(srv, s, ca, "url.rewrite-final", 1);
31466 parse_config_entry(srv, s, ca, "url.rewrite", 1);
31467 parse_config_entry(srv, s, ca, "url.rewrite-repeat", 0);
31471 return HANDLER_GO_ON;
31474 @@ -271,157 +184,107 @@
31476 plugin_config *s = p->config_storage[0];
31477 p->conf.rewrite = s->rewrite;
31479 + p->conf.once = s->once;
31481 /* skip the first, the global context */
31482 for (i = 1; i < srv->config_context->used; i++) {
31483 data_config *dc = (data_config *)srv->config_context->data[i];
31484 s = p->config_storage[i];
31487 if (COMP_HTTP_URL == dc->comp) continue;
31490 /* condition didn't match */
31491 if (!config_check_cond(srv, con, dc)) continue;
31495 for (j = 0; j < dc->value->used; j++) {
31496 data_unset *du = dc->value->data[j];
31499 if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite"))) {
31500 p->conf.rewrite = s->rewrite;
31501 + p->conf.once = s->once;
31502 p->conf.context = dc;
31503 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-once"))) {
31504 p->conf.rewrite = s->rewrite;
31505 + p->conf.once = s->once;
31506 p->conf.context = dc;
31507 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-repeat"))) {
31508 p->conf.rewrite = s->rewrite;
31509 + p->conf.once = s->once;
31510 p->conf.context = dc;
31511 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("url.rewrite-final"))) {
31512 p->conf.rewrite = s->rewrite;
31513 + p->conf.once = s->once;
31514 p->conf.context = dc;
31523 URIHANDLER_FUNC(mod_rewrite_con_reset) {
31524 plugin_data *p = p_d;
31530 if (con->plugin_ctx[p->id]) {
31531 handler_ctx_free(con->plugin_ctx[p->id]);
31532 con->plugin_ctx[p->id] = NULL;
31536 return HANDLER_GO_ON;
31539 URIHANDLER_FUNC(mod_rewrite_uri_handler) {
31541 plugin_data *p = p_d;
31551 * e.g. rewrite /base/ to /index.php?section=base
31557 if (con->plugin_ctx[p->id]) {
31558 hctx = con->plugin_ctx[p->id];
31561 if (hctx->loops++ > 100) {
31562 - log_error_write(srv, __FILE__, __LINE__, "s",
31563 + log_error_write(srv, __FILE__, __LINE__, "s",
31564 "ENDLESS LOOP IN rewrite-rule DETECTED ... aborting request, perhaps you want to use url.rewrite-once instead of url.rewrite-repeat");
31567 return HANDLER_ERROR;
31571 if (hctx->state == REWRITE_STATE_FINISHED) return HANDLER_GO_ON;
31575 mod_rewrite_patch_connection(srv, con, p);
31577 if (!p->conf.rewrite) return HANDLER_GO_ON;
31580 buffer_copy_string_buffer(p->match_buf, con->request.uri);
31582 - for (i = 0; i < p->conf.rewrite->used; i++) {
31584 - const char *pattern;
31585 - size_t pattern_len;
31587 - rewrite_rule *rule = p->conf.rewrite->ptr[i];
31591 - match = rule->key;
31592 - pattern = rule->value->ptr;
31593 - pattern_len = rule->value->used - 1;
31595 - if ((n = pcre_exec(match, NULL, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
31596 - if (n != PCRE_ERROR_NOMATCH) {
31597 - log_error_write(srv, __FILE__, __LINE__, "sd",
31598 - "execution error while matching: ", n);
31599 - return HANDLER_ERROR;
31602 - const char **list;
31603 - size_t start, end;
31607 - pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);
31609 - /* search for $[0-9] */
31611 - buffer_reset(con->request.uri);
31613 - start = 0; end = pattern_len;
31614 - for (k = 0; k < pattern_len; k++) {
31615 - if ((pattern[k] == '$' || pattern[k] == '%') &&
31616 - isdigit((unsigned char)pattern[k + 1])) {
31619 - size_t num = pattern[k + 1] - '0';
31623 - buffer_append_string_len(con->request.uri, pattern + start, end - start);
31625 - if (pattern[k] == '$') {
31626 - /* n is always > 0 */
31627 - if (num < (size_t)n) {
31628 - buffer_append_string(con->request.uri, list[num]);
31631 - config_append_cond_match_buffer(con, p->conf.context, con->request.uri, num);
31639 - buffer_append_string_len(con->request.uri, pattern + start, pattern_len - start);
31643 - hctx = handler_ctx_init();
31645 - con->plugin_ctx[p->id] = hctx;
31647 - if (rule->once) hctx->state = REWRITE_STATE_FINISHED;
31649 - return HANDLER_COMEBACK;
31651 + i = config_exec_pcre_keyvalue_buffer(con, p->conf.rewrite, p->conf.context, p->match_buf, con->request.uri);
31654 + hctx = handler_ctx_init();
31656 + con->plugin_ctx[p->id] = hctx;
31658 + if (p->conf.once->ptr[i] == '1')
31659 + hctx->state = REWRITE_STATE_FINISHED;
31661 + return HANDLER_COMEBACK;
31663 + else if (i != PCRE_ERROR_NOMATCH) {
31664 + log_error_write(srv, __FILE__, __LINE__, "s",
31665 + "execution error while matching", i);
31673 @@ -434,17 +297,17 @@
31674 int mod_rewrite_plugin_init(plugin *p) {
31675 p->version = LIGHTTPD_VERSION_ID;
31676 p->name = buffer_init_string("rewrite");
31679 p->init = mod_rewrite_init;
31680 /* it has to stay _raw as we are matching on uri + querystring
31684 p->handle_uri_raw = mod_rewrite_uri_handler;
31685 p->set_defaults = mod_rewrite_set_defaults;
31686 p->cleanup = mod_rewrite_free;
31687 p->connection_reset = mod_rewrite_con_reset;
31695 --- ../lighttpd-1.4.11/src/mod_rrdtool.c 2005-08-22 01:52:24.000000000 +0300
31696 +++ lighttpd-1.4.12/src/mod_rrdtool.c 2006-07-18 13:03:40.000000000 +0300
31698 #include <stdlib.h>
31700 #include <string.h>
31701 -#include <unistd.h>
31705 @@ -20,10 +19,14 @@
31706 /* no need for waitpid if we don't have fork */
31707 #include <sys/wait.h>
31710 +#include "sys-files.h"
31711 +#include "sys-process.h"
31714 buffer *path_rrdtool_bin;
31718 double requests, *requests_ptr;
31719 double bytes_written, *bytes_written_ptr;
31720 double bytes_read, *bytes_read_ptr;
31721 @@ -31,84 +34,84 @@
31731 int read_fd, write_fd;
31735 int rrdtool_running;
31738 plugin_config **config_storage;
31739 plugin_config conf;
31742 INIT_FUNC(mod_rrd_init) {
31746 p = calloc(1, sizeof(*p));
31749 p->resp = buffer_init();
31750 p->cmd = buffer_init();
31756 FREE_FUNC(mod_rrd_free) {
31757 plugin_data *p = p_d;
31761 if (!p) return HANDLER_GO_ON;
31764 if (p->config_storage) {
31765 for (i = 0; i < srv->config_context->used; i++) {
31766 plugin_config *s = p->config_storage[i];
31769 buffer_free(s->path_rrdtool_bin);
31770 buffer_free(s->path_rrd);
31776 buffer_free(p->cmd);
31777 buffer_free(p->resp);
31780 free(p->config_storage);
31783 if (p->rrdtool_pid) {
31786 close(p->write_fd);
31789 /* collect status */
31790 waitpid(p->rrdtool_pid, &status, 0);
31798 return HANDLER_GO_ON;
31801 int mod_rrd_create_pipe(server *srv, plugin_data *p) {
31805 int to_rrdtool_fds[2];
31806 int from_rrdtool_fds[2];
31809 if (pipe(to_rrdtool_fds)) {
31810 - log_error_write(srv, __FILE__, __LINE__, "ss",
31811 + log_error_write(srv, __FILE__, __LINE__, "ss",
31812 "pipe failed: ", strerror(errno));
31817 if (pipe(from_rrdtool_fds)) {
31818 - log_error_write(srv, __FILE__, __LINE__, "ss",
31819 + log_error_write(srv, __FILE__, __LINE__, "ss",
31820 "pipe failed: ", strerror(errno));
31826 switch (pid = fork()) {
31828 @@ -117,33 +120,28 @@
31834 /* move stdout to from_rrdtool_fd[1] */
31835 close(STDOUT_FILENO);
31836 dup2(from_rrdtool_fds[1], STDOUT_FILENO);
31837 close(from_rrdtool_fds[1]);
31839 close(from_rrdtool_fds[0]);
31842 /* move the stdin to to_rrdtool_fd[0] */
31843 close(STDIN_FILENO);
31844 dup2(to_rrdtool_fds[0], STDIN_FILENO);
31845 close(to_rrdtool_fds[0]);
31847 close(to_rrdtool_fds[1]);
31850 close(STDERR_FILENO);
31852 - if (srv->errorlog_mode == ERRORLOG_FILE) {
31853 - dup2(srv->errorlog_fd, STDERR_FILENO);
31854 - close(srv->errorlog_fd);
31860 args = malloc(sizeof(*args) * argc);
31864 args[i++] = p->conf.path_rrdtool_bin->ptr;
31867 @@ -152,12 +150,12 @@
31868 for (i = 3; i < 256; i++) {
31874 execv(args[0], args);
31877 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing rrdtool failed: ", strerror(errno), args[0]);
31883 @@ -168,19 +166,19 @@
31889 close(from_rrdtool_fds[1]);
31890 close(to_rrdtool_fds[0]);
31893 /* register PID and wait for them asyncronously */
31894 p->write_fd = to_rrdtool_fds[1];
31895 p->read_fd = from_rrdtool_fds[0];
31896 p->rrdtool_pid = pid;
31907 @@ -189,19 +187,19 @@
31909 static int mod_rrdtool_create_rrd(server *srv, plugin_data *p, plugin_config *s) {
31913 /* check if DB already exists */
31914 if (0 == stat(s->path_rrd->ptr, &st)) {
31915 /* check if it is plain file */
31916 if (!S_ISREG(st.st_mode)) {
31917 - log_error_write(srv, __FILE__, __LINE__, "sb",
31918 + log_error_write(srv, __FILE__, __LINE__, "sb",
31919 "not a regular file:", s->path_rrd);
31920 return HANDLER_ERROR;
31924 /* create a new one */
31927 BUFFER_COPY_STRING_CONST(p->cmd, "create ");
31928 buffer_append_string_buffer(p->cmd, s->path_rrd);
31929 buffer_append_string(p->cmd, " --step 60 ");
31930 @@ -220,158 +218,155 @@
31931 buffer_append_string(p->cmd, "RRA:MIN:0.5:6:700 ");
31932 buffer_append_string(p->cmd, "RRA:MIN:0.5:24:775 ");
31933 buffer_append_string(p->cmd, "RRA:MIN:0.5:288:797\n");
31936 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
31937 - log_error_write(srv, __FILE__, __LINE__, "ss",
31938 + log_error_write(srv, __FILE__, __LINE__, "ss",
31939 "rrdtool-write: failed", strerror(errno));
31942 return HANDLER_ERROR;
31946 buffer_prepare_copy(p->resp, 4096);
31947 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
31948 - log_error_write(srv, __FILE__, __LINE__, "ss",
31949 + log_error_write(srv, __FILE__, __LINE__, "ss",
31950 "rrdtool-read: failed", strerror(errno));
31953 return HANDLER_ERROR;
31960 if (p->resp->ptr[0] != 'O' ||
31961 p->resp->ptr[1] != 'K') {
31962 - log_error_write(srv, __FILE__, __LINE__, "sbb",
31963 + log_error_write(srv, __FILE__, __LINE__, "sbb",
31964 "rrdtool-response:", p->cmd, p->resp);
31967 return HANDLER_ERROR;
31972 return HANDLER_GO_ON;
31975 -#define PATCH(x) \
31976 - p->conf.x = s->x;
31977 static int mod_rrd_patch_connection(server *srv, connection *con, plugin_data *p) {
31979 plugin_config *s = p->config_storage[0];
31981 - PATCH(path_rrdtool_bin);
31985 + PATCH_OPTION(path_rrdtool_bin);
31986 + PATCH_OPTION(path_rrd);
31988 p->conf.bytes_written_ptr = &(s->bytes_written);
31989 p->conf.bytes_read_ptr = &(s->bytes_read);
31990 p->conf.requests_ptr = &(s->requests);
31993 /* skip the first, the global context */
31994 for (i = 1; i < srv->config_context->used; i++) {
31995 data_config *dc = (data_config *)srv->config_context->data[i];
31996 s = p->config_storage[i];
31999 /* condition didn't match */
32000 if (!config_check_cond(srv, con, dc)) continue;
32004 for (j = 0; j < dc->value->used; j++) {
32005 data_unset *du = dc->value->data[j];
32008 if (buffer_is_equal_string(du->key, CONST_STR_LEN("rrdtool.db-name"))) {
32010 + PATCH_OPTION(path_rrd);
32011 /* get pointers to double values */
32014 p->conf.bytes_written_ptr = &(s->bytes_written);
32015 p->conf.bytes_read_ptr = &(s->bytes_read);
32016 p->conf.requests_ptr = &(s->requests);
32026 SETDEFAULTS_FUNC(mod_rrd_set_defaults) {
32027 plugin_data *p = p_d;
32030 - config_values_t cv[] = {
32032 + config_values_t cv[] = {
32033 { "rrdtool.binary", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER },
32034 { "rrdtool.db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
32035 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
32039 if (!p) return HANDLER_ERROR;
32042 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
32045 for (i = 0; i < srv->config_context->used; i++) {
32049 s = calloc(1, sizeof(plugin_config));
32050 s->path_rrdtool_bin = buffer_init();
32051 s->path_rrd = buffer_init();
32053 s->bytes_written = 0;
32057 cv[0].destination = s->path_rrdtool_bin;
32058 cv[1].destination = s->path_rrd;
32061 p->config_storage[i] = s;
32064 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
32065 return HANDLER_ERROR;
32069 if (i > 0 && !buffer_is_empty(s->path_rrdtool_bin)) {
32070 /* path_rrdtool_bin is a global option */
32072 - log_error_write(srv, __FILE__, __LINE__, "s",
32074 + log_error_write(srv, __FILE__, __LINE__, "s",
32075 "rrdtool.binary can only be set as a global option.");
32078 return HANDLER_ERROR;
32085 p->conf.path_rrdtool_bin = p->config_storage[0]->path_rrdtool_bin;
32086 p->rrdtool_running = 0;
32089 /* check for dir */
32092 if (buffer_is_empty(p->conf.path_rrdtool_bin)) {
32093 - log_error_write(srv, __FILE__, __LINE__, "s",
32094 + log_error_write(srv, __FILE__, __LINE__, "s",
32095 "rrdtool.binary has to be set");
32096 return HANDLER_ERROR;
32100 /* open the pipe to rrdtool */
32101 if (mod_rrd_create_pipe(srv, p)) {
32102 return HANDLER_ERROR;
32106 p->rrdtool_running = 1;
32109 return HANDLER_GO_ON;
32112 TRIGGER_FUNC(mod_rrd_trigger) {
32113 plugin_data *p = p_d;
32117 if (!p->rrdtool_running) return HANDLER_GO_ON;
32118 if ((srv->cur_ts % 60) != 0) return HANDLER_GO_ON;
32121 for (i = 0; i < srv->config_context->used; i++) {
32122 plugin_config *s = p->config_storage[i];
32126 if (buffer_is_empty(s->path_rrd)) continue;
32129 /* write the data down every minute */
32132 if (HANDLER_GO_ON != mod_rrdtool_create_rrd(srv, p, s)) return HANDLER_ERROR;
32135 BUFFER_COPY_STRING_CONST(p->cmd, "update ");
32136 buffer_append_string_buffer(p->cmd, s->path_rrd);
32137 BUFFER_APPEND_STRING_CONST(p->cmd, " N:");
32138 @@ -381,69 +376,69 @@
32139 BUFFER_APPEND_STRING_CONST(p->cmd, ":");
32140 buffer_append_long(p->cmd, s->requests);
32141 BUFFER_APPEND_STRING_CONST(p->cmd, "\n");
32144 if (-1 == (r = write(p->write_fd, p->cmd->ptr, p->cmd->used - 1))) {
32145 p->rrdtool_running = 0;
32147 - log_error_write(srv, __FILE__, __LINE__, "ss",
32149 + log_error_write(srv, __FILE__, __LINE__, "ss",
32150 "rrdtool-write: failed", strerror(errno));
32153 return HANDLER_ERROR;
32157 buffer_prepare_copy(p->resp, 4096);
32158 if (-1 == (r = read(p->read_fd, p->resp->ptr, p->resp->size))) {
32159 p->rrdtool_running = 0;
32161 - log_error_write(srv, __FILE__, __LINE__, "ss",
32163 + log_error_write(srv, __FILE__, __LINE__, "ss",
32164 "rrdtool-read: failed", strerror(errno));
32167 return HANDLER_ERROR;
32174 if (p->resp->ptr[0] != 'O' ||
32175 p->resp->ptr[1] != 'K') {
32176 p->rrdtool_running = 0;
32178 - log_error_write(srv, __FILE__, __LINE__, "sbb",
32180 + log_error_write(srv, __FILE__, __LINE__, "sbb",
32181 "rrdtool-response:", p->cmd, p->resp);
32184 return HANDLER_ERROR;
32187 s->bytes_written = 0;
32192 return HANDLER_GO_ON;
32195 REQUESTDONE_FUNC(mod_rrd_account) {
32196 plugin_data *p = p_d;
32199 mod_rrd_patch_connection(srv, con, p);
32202 *(p->conf.requests_ptr) += 1;
32203 *(p->conf.bytes_written_ptr) += con->bytes_written;
32204 *(p->conf.bytes_read_ptr) += con->bytes_read;
32207 return HANDLER_GO_ON;
32210 int mod_rrdtool_plugin_init(plugin *p) {
32211 p->version = LIGHTTPD_VERSION_ID;
32212 p->name = buffer_init_string("rrd");
32215 p->init = mod_rrd_init;
32216 p->cleanup = mod_rrd_free;
32217 p->set_defaults= mod_rrd_set_defaults;
32220 p->handle_trigger = mod_rrd_trigger;
32221 p->handle_request_done = mod_rrd_account;
32229 --- ../lighttpd-1.4.11/src/mod_scgi.c 2006-03-04 17:15:26.000000000 +0200
32230 +++ lighttpd-1.4.12/src/mod_scgi.c 2006-07-18 13:03:40.000000000 +0300
32232 #include <sys/types.h>
32233 -#include <unistd.h>
32236 #include <string.h>
32238 #include "connections.h"
32239 #include "response.h"
32240 #include "joblist.h"
32241 +#include "http_resp.h"
32243 #include "plugin.h"
32248 #include "sys-socket.h"
32250 +#include "sys-files.h"
32251 +#include "sys-strings.h"
32252 +#include "sys-process.h"
32254 #ifndef UNIX_PATH_MAX
32255 # define UNIX_PATH_MAX 108
32256 @@ -46,30 +48,29 @@
32257 enum {EOL_UNSET, EOL_N, EOL_RN};
32265 * - add timeout for a connect to a non-scgi process
32266 * (use state_timestamp + state)
32271 typedef struct scgi_proc {
32272 size_t id; /* id will be between 1 and max_procs */
32273 buffer *socket; /* config.socket + "-" + id */
32274 unsigned port; /* config.port + pno */
32276 - pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
32278 + pid_t pid; /* PID of the spawned process (0 if not spawned locally) */
32280 size_t load; /* number of requests waiting on this process */
32282 time_t last_used; /* see idle_timeout */
32283 size_t requests; /* see max_requests */
32284 struct scgi_proc *prev, *next; /* see first */
32287 time_t disable_ts; /* replace by host->something */
32292 enum { PROC_STATE_UNSET, /* init-phase */
32294 PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
32295 PROC_STATE_DIED, /* marked as dead, should be restarted */
32296 PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
32302 @@ -86,20 +87,20 @@
32303 * sorted by lowest load
32305 * whenever a job is done move it up in the list
32306 - * until it is sorted, move it down as soon as the
32307 + * until it is sorted, move it down as soon as the
32310 - scgi_proc *first;
32311 - scgi_proc *unused_procs;
32312 + scgi_proc *first;
32313 + scgi_proc *unused_procs;
32317 * spawn at least min_procs, at max_procs.
32319 - * as soon as the load of the first entry
32320 + * as soon as the load of the first entry
32321 * is max_load_per_proc we spawn a new one
32322 - * and add it to the first entry and give it
32323 + * and add it to the first entry and give it
32329 unsigned short min_procs;
32330 @@ -111,44 +112,44 @@
32333 * kick the process from the list if it was not
32334 - * used for idle_timeout until min_procs is
32335 + * used for idle_timeout until min_procs is
32336 * reached. this helps to get the processlist
32337 * small again we had a small peak load.
32342 unsigned short idle_timeout;
32346 * time after a disabled remote connection is tried to be re-enabled
32354 unsigned short disable_time;
32357 * same scgi processes get a little bit larger
32358 - * than wanted. max_requests_per_proc kills a
32359 + * than wanted. max_requests_per_proc kills a
32360 * process after a number of handled requests.
32363 size_t max_requests_per_proc;
32374 - * if host is one of the local IP adresses the
32375 + * if host is one of the local IP adresses the
32376 * whole connection is local
32378 * if tcp/ip should be used host AND port have
32379 - * to be specified
32383 + * to be specified
32387 unsigned short port;
32390 @@ -161,7 +162,7 @@
32392 buffer *unixsocket;
32394 - /* if socket is local we can start the scgi
32395 + /* if socket is local we can start the scgi
32398 * bin-path is the path to the binary
32399 @@ -169,19 +170,19 @@
32400 * check min_procs and max_procs for the number
32401 * of process to start-up
32403 - buffer *bin_path;
32405 - /* bin-path is set bin-environment is taken to
32406 + buffer *bin_path;
32408 + /* bin-path is set bin-environment is taken to
32409 * create the environement before starting the
32417 array *bin_env_copy;
32421 - * docroot-translation between URL->phys and the
32422 + * docroot-translation between URL->phys and the
32426 @@ -192,7 +193,7 @@
32430 - * check_local tell you if the phys file is stat()ed
32431 + * check_local tell you if the phys file is stat()ed
32432 * or not. FastCGI doesn't care if the service is
32433 * remote. If the web-server side doesn't contain
32434 * the scgi-files we should not stat() for them
32435 @@ -202,33 +203,33 @@
32438 * append PATH_INFO to SCRIPT_FILENAME
32441 * php needs this if cgi.fix_pathinfo is provied
32447 ssize_t load; /* replace by host->load */
32449 size_t max_id; /* corresponds most of the time to
32453 only if a process is killed max_id waits for the process itself
32454 to die and decrements its afterwards */
32455 } scgi_extension_host;
32458 * one extension can have multiple hosts assigned
32459 - * one host can spawn additional processes on the same
32460 + * one host can spawn additional processes on the same
32461 * socket (if we control it)
32463 * ext -> host -> procs
32466 - * if the scgi process is remote that whole goes down
32467 + * if the scgi process is remote that whole goes down
32470 * ext -> host -> procs
32474 * in case of PHP and FCGI_CHILDREN we have again a procs
32475 * but we don't control it directly.
32476 @@ -239,7 +240,7 @@
32477 buffer *key; /* like .php */
32479 scgi_extension_host **hosts;
32485 @@ -253,14 +254,14 @@
32503 @@ -268,52 +269,51 @@
32504 /* generic plugin data, shared between all connections */
32513 - buffer *parse_response;
32518 plugin_config **config_storage;
32521 plugin_config conf; /* this is only used as long as no handler_ctx is setup */
32524 /* connection specific data */
32525 -typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
32526 - FCGI_STATE_WRITE, FCGI_STATE_READ
32529 + SCGI_STATE_CONNECT,
32530 + SCGI_STATE_PREPARE_WRITE,
32531 + SCGI_STATE_WRITE,
32532 + SCGI_STATE_RESPONSE_HEADER,
32533 + SCGI_STATE_RESPONSE_CONTENT,
32535 } scgi_connection_state_t;
32538 - buffer *response;
32539 - size_t response_len;
32540 - int response_type;
32541 - int response_padding;
32544 scgi_extension_host *host;
32547 scgi_connection_state_t state;
32548 time_t state_timestamp;
32551 int reconnects; /* number of reconnect attempts */
32558 - buffer *response_header;
32561 int delayed; /* flag to mark that the connect() is delayed */
32565 - int fd; /* fd to the scgi process */
32566 - int fde_ndx; /* index into the fd-event buffer */
32567 + iosocket *sock; /* fd to the scgi process */
32573 plugin_config conf;
32576 connection *remote_conn; /* dumb pointer */
32577 plugin_data *plugin_data; /* dumb pointer */
32579 @@ -328,42 +328,30 @@
32581 static handler_ctx * handler_ctx_init() {
32582 handler_ctx * hctx;
32585 hctx = calloc(1, sizeof(*hctx));
32588 - hctx->fde_ndx = -1;
32590 - hctx->response = buffer_init();
32591 - hctx->response_header = buffer_init();
32594 + hctx->sock = iosocket_init();;
32596 hctx->request_id = 0;
32597 - hctx->state = FCGI_STATE_INIT;
32598 + hctx->state = SCGI_STATE_INIT;
32601 - hctx->response_len = 0;
32602 - hctx->response_type = 0;
32603 - hctx->response_padding = 0;
32607 hctx->reconnects = 0;
32609 hctx->wb = chunkqueue_init();
32611 + hctx->rb = chunkqueue_init();
32616 static void handler_ctx_free(handler_ctx *hctx) {
32617 - buffer_free(hctx->response);
32618 - buffer_free(hctx->response_header);
32620 chunkqueue_free(hctx->wb);
32623 - if (hctx->rb->ptr) free(hctx->rb->ptr);
32627 + chunkqueue_free(hctx->rb);
32629 + iosocket_free(hctx->sock);
32634 @@ -372,20 +360,20 @@
32636 f = calloc(1, sizeof(*f));
32637 f->socket = buffer_init();
32647 void scgi_process_free(scgi_proc *f) {
32651 scgi_process_free(f->next);
32654 buffer_free(f->socket);
32660 @@ -400,62 +388,62 @@
32661 f->bin_path = buffer_init();
32662 f->bin_env = array_init();
32663 f->bin_env_copy = array_init();
32669 void scgi_host_free(scgi_extension_host *h) {
32673 buffer_free(h->host);
32674 buffer_free(h->unixsocket);
32675 buffer_free(h->docroot);
32676 buffer_free(h->bin_path);
32677 array_free(h->bin_env);
32678 array_free(h->bin_env_copy);
32681 scgi_process_free(h->first);
32682 scgi_process_free(h->unused_procs);
32690 scgi_exts *scgi_extensions_init() {
32693 f = calloc(1, sizeof(*f));
32699 void scgi_extensions_free(scgi_exts *f) {
32706 for (i = 0; i < f->used; i++) {
32707 scgi_extension *fe;
32714 for (j = 0; j < fe->used; j++) {
32715 scgi_extension_host *h;
32725 buffer_free(fe->key);
32739 @@ -504,99 +492,103 @@
32743 - fe->hosts[fe->used++] = fh;
32744 + fe->hosts[fe->used++] = fh;
32751 INIT_FUNC(mod_scgi_init) {
32755 p = calloc(1, sizeof(*p));
32758 p->scgi_env = buffer_init();
32761 p->path = buffer_init();
32762 - p->parse_response = buffer_init();
32764 + p->resp = http_response_init();
32770 FREE_FUNC(mod_scgi_free) {
32771 plugin_data *p = p_d;
32776 buffer_free(p->scgi_env);
32777 buffer_free(p->path);
32778 - buffer_free(p->parse_response);
32780 + http_response_free(p->resp);
32782 if (p->config_storage) {
32784 for (i = 0; i < srv->config_context->used; i++) {
32785 plugin_config *s = p->config_storage[i];
32794 for (j = 0; j < exts->used; j++) {
32795 scgi_extension *ex;
32798 ex = exts->exts[j];
32801 for (n = 0; n < ex->used; n++) {
32803 scgi_extension_host *host;
32806 host = ex->hosts[n];
32809 for (proc = host->first; proc; proc = proc->next) {
32811 if (proc->pid != 0) kill(proc->pid, SIGTERM);
32813 - if (proc->is_local &&
32816 + if (proc->is_local &&
32817 !buffer_is_empty(proc->socket)) {
32818 unlink(proc->socket->ptr);
32823 for (proc = host->unused_procs; proc; proc = proc->next) {
32825 if (proc->pid != 0) kill(proc->pid, SIGTERM);
32827 - if (proc->is_local &&
32830 + if (proc->is_local &&
32831 !buffer_is_empty(proc->socket)) {
32832 unlink(proc->socket->ptr);
32839 scgi_extensions_free(s->exts);
32844 free(p->config_storage);
32851 return HANDLER_GO_ON;
32854 static int env_add(char_array *env, const char *key, size_t key_len, const char *val, size_t val_len) {
32858 if (!key || !val) return -1;
32861 dst = malloc(key_len + val_len + 3);
32862 memcpy(dst, key, key_len);
32863 dst[key_len] = '=';
32864 /* add the \0 from the value */
32865 memcpy(dst + key_len + 1, val, val_len + 1);
32868 if (env->size == 0) {
32870 env->ptr = malloc(env->size * sizeof(*env->ptr));
32871 @@ -604,13 +596,13 @@
32873 env->ptr = realloc(env->ptr, env->size * sizeof(*env->ptr));
32877 env->ptr[env->used++] = dst;
32883 -static int scgi_spawn_connection(server *srv,
32884 +static int scgi_spawn_connection(server *srv,
32886 scgi_extension_host *host,
32888 @@ -622,31 +614,27 @@
32890 struct sockaddr_in scgi_addr_in;
32891 struct sockaddr *scgi_addr;
32902 if (p->conf.debug) {
32903 log_error_write(srv, __FILE__, __LINE__, "sdb",
32904 "new proc, socket:", proc->port, proc->socket);
32908 if (!buffer_is_empty(proc->socket)) {
32909 memset(&scgi_addr, 0, sizeof(scgi_addr));
32912 #ifdef HAVE_SYS_UN_H
32913 scgi_addr_un.sun_family = AF_UNIX;
32914 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
32918 servlen = SUN_LEN(&scgi_addr_un);
32920 - /* stevens says: */
32921 - servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
32924 socket_type = AF_UNIX;
32925 scgi_addr = (struct sockaddr *) &scgi_addr_un;
32927 @@ -656,115 +644,115 @@
32930 scgi_addr_in.sin_family = AF_INET;
32933 if (buffer_is_empty(host->host)) {
32934 scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
32936 struct hostent *he;
32939 /* set a usefull default */
32940 scgi_addr_in.sin_addr.s_addr = htonl(INADDR_ANY);
32945 if (NULL == (he = gethostbyname(host->host->ptr))) {
32946 - log_error_write(srv, __FILE__, __LINE__,
32947 - "sdb", "gethostbyname failed: ",
32948 + log_error_write(srv, __FILE__, __LINE__,
32949 + "sdb", "gethostbyname failed: ",
32950 h_errno, host->host);
32955 if (he->h_addrtype != AF_INET) {
32956 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
32961 if (he->h_length != sizeof(struct in_addr)) {
32962 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
32967 memcpy(&(scgi_addr_in.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
32971 scgi_addr_in.sin_port = htons(proc->port);
32972 servlen = sizeof(scgi_addr_in);
32975 socket_type = AF_INET;
32976 scgi_addr = (struct sockaddr *) &scgi_addr_in;
32980 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
32981 - log_error_write(srv, __FILE__, __LINE__, "ss",
32982 + log_error_write(srv, __FILE__, __LINE__, "ss",
32983 "failed:", strerror(errno));
32988 if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
32989 /* server is not up, spawn in */
32994 if (!buffer_is_empty(proc->socket)) {
32995 unlink(proc->socket->ptr);
33002 /* reopen socket */
33003 if (-1 == (scgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
33004 - log_error_write(srv, __FILE__, __LINE__, "ss",
33005 + log_error_write(srv, __FILE__, __LINE__, "ss",
33006 "socket failed:", strerror(errno));
33012 if (setsockopt(scgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
33013 - log_error_write(srv, __FILE__, __LINE__, "ss",
33014 + log_error_write(srv, __FILE__, __LINE__, "ss",
33015 "socketsockopt failed:", strerror(errno));
33020 /* create socket */
33021 if (-1 == bind(scgi_fd, scgi_addr, servlen)) {
33022 - log_error_write(srv, __FILE__, __LINE__, "sbds",
33023 - "bind failed for:",
33026 + log_error_write(srv, __FILE__, __LINE__, "sbds",
33027 + "bind failed for:",
33035 if (-1 == listen(scgi_fd, 1024)) {
33036 - log_error_write(srv, __FILE__, __LINE__, "ss",
33037 + log_error_write(srv, __FILE__, __LINE__, "ss",
33038 "listen failed:", strerror(errno));
33045 switch ((child = fork())) {
33055 /* create environment */
33061 /* we don't need the client socket */
33062 for (fd = 3; fd < 256; fd++) {
33063 if (fd != 2 && fd != scgi_fd) close(fd);
33067 /* build clean environment */
33068 if (host->bin_env_copy->used) {
33069 for (i = 0; i < host->bin_env_copy->used; i++) {
33070 data_string *ds = (data_string *)host->bin_env_copy->data[i];
33074 if (NULL != (ge = getenv(ds->value->ptr))) {
33075 env_add(&env, CONST_BUF_LEN(ds->value), ge, strlen(ge));
33077 @@ -772,44 +760,44 @@
33079 for (i = 0; environ[i]; i++) {
33083 if (NULL != (eq = strchr(environ[i], '='))) {
33084 env_add(&env, environ[i], eq - environ[i], eq+1, strlen(eq+1));
33090 /* create environment */
33091 for (i = 0; i < host->bin_env->used; i++) {
33092 data_string *ds = (data_string *)host->bin_env->data[i];
33095 env_add(&env, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
33099 for (i = 0; i < env.used; i++) {
33100 /* search for PHP_FCGI_CHILDREN */
33101 if (0 == strncmp(env.ptr[i], "PHP_FCGI_CHILDREN=", sizeof("PHP_FCGI_CHILDREN=") - 1)) break;
33105 /* not found, add a default */
33106 if (i == env.used) {
33107 env_add(&env, CONST_STR_LEN("PHP_FCGI_CHILDREN"), CONST_STR_LEN("1"));
33111 env.ptr[env.used] = NULL;
33115 buffer_copy_string(b, "exec ");
33116 buffer_append_string_buffer(b, host->bin_path);
33120 execle("/bin/sh", "sh", "-c", b->ptr, NULL, env.ptr);
33122 - log_error_write(srv, __FILE__, __LINE__, "sbs",
33124 + log_error_write(srv, __FILE__, __LINE__, "sbs",
33125 "execl failed for:", host->bin_path, strerror(errno));
33134 @@ -817,32 +805,32 @@
33141 select(0, NULL, NULL, NULL, &tv);
33144 switch (waitpid(child, &status, WNOHANG)) {
33146 /* child still running after timeout, good */
33149 /* no PID found ? should never happen */
33150 - log_error_write(srv, __FILE__, __LINE__, "ss",
33151 + log_error_write(srv, __FILE__, __LINE__, "ss",
33152 "pid not found:", strerror(errno));
33155 /* the child should not terminate at all */
33156 if (WIFEXITED(status)) {
33157 - log_error_write(srv, __FILE__, __LINE__, "sd",
33158 - "child exited (is this a SCGI binary ?):",
33159 + log_error_write(srv, __FILE__, __LINE__, "sd",
33160 + "child exited (is this a SCGI binary ?):",
33161 WEXITSTATUS(status));
33162 } else if (WIFSIGNALED(status)) {
33163 - log_error_write(srv, __FILE__, __LINE__, "sd",
33164 - "child signaled:",
33165 + log_error_write(srv, __FILE__, __LINE__, "sd",
33166 + "child signaled:",
33169 - log_error_write(srv, __FILE__, __LINE__, "sd",
33170 - "child died somehow:",
33171 + log_error_write(srv, __FILE__, __LINE__, "sd",
33172 + "child died somehow:",
33176 @@ -852,26 +840,26 @@
33178 proc->last_used = srv->cur_ts;
33179 proc->is_local = 1;
33186 proc->is_local = 0;
33190 if (p->conf.debug) {
33191 log_error_write(srv, __FILE__, __LINE__, "sb",
33192 "(debug) socket is already used, won't spawn:",
33198 proc->state = PROC_STATE_RUNNING;
33199 host->active_procs++;
33208 @@ -880,89 +868,89 @@
33209 plugin_data *p = p_d;
33213 - config_values_t cv[] = {
33215 + config_values_t cv[] = {
33216 { "scgi.server", NULL, T_CONFIG_LOCAL, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
33217 { "scgi.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
33218 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33222 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
33225 for (i = 0; i < srv->config_context->used; i++) {
33230 s = malloc(sizeof(plugin_config));
33231 s->exts = scgi_extensions_init();
33235 cv[0].destination = s->exts;
33236 cv[1].destination = &(s->debug);
33239 p->config_storage[i] = s;
33240 ca = ((data_config *)srv->config_context->data[i])->value;
33243 if (0 != config_insert_values_global(srv, ca, cv)) {
33244 return HANDLER_ERROR;
33254 if (NULL != (du = array_get_element(ca, "scgi.server"))) {
33256 data_array *da = (data_array *)du;
33259 if (du->type != TYPE_ARRAY) {
33260 - log_error_write(srv, __FILE__, __LINE__, "sss",
33261 + log_error_write(srv, __FILE__, __LINE__, "sss",
33262 "unexpected type for key: ", "scgi.server", "array of strings");
33265 return HANDLER_ERROR;
33270 - * scgi.server = ( "<ext>" => ( ... ),
33274 + * scgi.server = ( "<ext>" => ( ... ),
33275 * "<ext>" => ( ... ) )
33279 for (j = 0; j < da->value->used; j++) {
33281 data_array *da_ext = (data_array *)da->value->data[j];
33284 if (da->value->data[j]->type != TYPE_ARRAY) {
33285 - log_error_write(srv, __FILE__, __LINE__, "sssbs",
33286 - "unexpected type for key: ", "scgi.server",
33287 + log_error_write(srv, __FILE__, __LINE__, "sssbs",
33288 + "unexpected type for key: ", "scgi.server",
33289 "[", da->value->data[j]->key, "](string)");
33292 return HANDLER_ERROR;
33296 - * da_ext->key == name of the extension
33299 + * da_ext->key == name of the extension
33303 - * scgi.server = ( "<ext>" =>
33304 - * ( "<host>" => ( ... ),
33307 + * scgi.server = ( "<ext>" =>
33308 + * ( "<host>" => ( ... ),
33309 * "<host>" => ( ... )
33316 for (n = 0; n < da_ext->value->used; n++) {
33317 data_array *da_host = (data_array *)da_ext->value->data[n];
33320 scgi_extension_host *df;
33322 - config_values_t fcv[] = {
33324 + config_values_t fcv[] = {
33325 { "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
33326 { "docroot", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
33327 { "socket", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
33328 { "bin-path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
33331 { "check-local", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 4 */
33332 { "port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 5 */
33333 { "min-procs-not-working", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 7 this is broken for now */
33334 @@ -970,37 +958,37 @@
33335 { "max-load-per-proc", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 8 */
33336 { "idle-timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 9 */
33337 { "disable-time", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 10 */
33340 { "bin-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 11 */
33341 { "bin-copy-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 12 */
33346 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
33350 if (da_host->type != TYPE_ARRAY) {
33351 - log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33352 - "unexpected type for key:",
33354 + log_error_write(srv, __FILE__, __LINE__, "ssSBS",
33355 + "unexpected type for key:",
33357 "[", da_host->key, "](string)");
33360 return HANDLER_ERROR;
33364 df = scgi_host_init();
33367 df->check_local = 1;
33370 df->max_load_per_proc = 1;
33371 df->idle_timeout = 60;
33372 df->disable_time = 60;
33375 fcv[0].destination = df->host;
33376 fcv[1].destination = df->docroot;
33377 fcv[2].destination = df->unixsocket;
33378 fcv[3].destination = df->bin_path;
33381 fcv[4].destination = &(df->check_local);
33382 fcv[5].destination = &(df->port);
33383 fcv[6].destination = &(df->min_procs);
33384 @@ -1008,47 +996,47 @@
33385 fcv[8].destination = &(df->max_load_per_proc);
33386 fcv[9].destination = &(df->idle_timeout);
33387 fcv[10].destination = &(df->disable_time);
33390 fcv[11].destination = df->bin_env;
33391 fcv[12].destination = df->bin_env_copy;
33396 if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
33397 return HANDLER_ERROR;
33400 - if ((!buffer_is_empty(df->host) || df->port) &&
33402 + if ((!buffer_is_empty(df->host) || df->port) &&
33403 !buffer_is_empty(df->unixsocket)) {
33404 - log_error_write(srv, __FILE__, __LINE__, "s",
33405 + log_error_write(srv, __FILE__, __LINE__, "s",
33406 "either host+port or socket");
33409 return HANDLER_ERROR;
33413 if (!buffer_is_empty(df->unixsocket)) {
33414 /* unix domain socket */
33417 if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
33418 - log_error_write(srv, __FILE__, __LINE__, "s",
33419 + log_error_write(srv, __FILE__, __LINE__, "s",
33420 "path of the unixdomain socket is too large");
33421 return HANDLER_ERROR;
33426 - if (buffer_is_empty(df->host) &&
33428 + if (buffer_is_empty(df->host) &&
33429 buffer_is_empty(df->bin_path)) {
33430 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33431 - "missing key (string):",
33432 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33433 + "missing key (string):",
33440 return HANDLER_ERROR;
33441 } else if (df->port == 0) {
33442 - log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33443 - "missing key (short):",
33444 + log_error_write(srv, __FILE__, __LINE__, "sbbbs",
33445 + "missing key (short):",
33449 @@ -1056,14 +1044,14 @@
33450 return HANDLER_ERROR;
33454 - if (!buffer_is_empty(df->bin_path)) {
33456 + if (!buffer_is_empty(df->bin_path)) {
33457 /* a local socket + self spawning */
33461 if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
33462 if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
33466 log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
33467 "--- scgi spawning local",
33468 @@ -1073,7 +1061,7 @@
33469 "\n\tmin-procs:", df->min_procs,
33470 "\n\tmax-procs:", df->max_procs);
33474 for (pno = 0; pno < df->min_procs; pno++) {
33477 @@ -1088,7 +1076,7 @@
33478 buffer_append_string(proc->socket, "-");
33479 buffer_append_long(proc->socket, pno);
33484 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
33485 "--- scgi spawning",
33486 @@ -1096,53 +1084,53 @@
33487 "\n\tsocket", df->unixsocket,
33488 "\n\tcurrent:", pno, "/", df->min_procs);
33492 if (scgi_spawn_connection(srv, p, df, proc)) {
33493 log_error_write(srv, __FILE__, __LINE__, "s",
33494 "[ERROR]: spawning fcgi failed.");
33495 return HANDLER_ERROR;
33499 proc->next = df->first;
33500 if (df->first) df->first->prev = proc;
33509 fp = scgi_process_init();
33510 fp->id = df->num_procs++;
33512 df->active_procs++;
33513 fp->state = PROC_STATE_RUNNING;
33516 if (buffer_is_empty(df->unixsocket)) {
33517 fp->port = df->port;
33519 buffer_copy_string_buffer(fp->socket, df->unixsocket);
33531 /* if extension already exists, take it */
33532 scgi_extension_insert(s->exts, da_ext->key, df);
33539 return HANDLER_GO_ON;
33542 static int scgi_set_state(server *srv, handler_ctx *hctx, scgi_connection_state_t state) {
33543 hctx->state = state;
33544 hctx->state_timestamp = srv->cur_ts;
33550 @@ -1150,35 +1138,35 @@
33551 void scgi_connection_cleanup(server *srv, handler_ctx *hctx) {
33556 if (NULL == hctx) return;
33559 p = hctx->plugin_data;
33560 con = hctx->remote_conn;
33563 if (con->mode != p->id) {
33568 - if (hctx->fd != -1) {
33569 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
33570 - fdevent_unregister(srv->ev, hctx->fd);
33573 + if (hctx->sock->fd != -1) {
33574 + fdevent_event_del(srv->ev, hctx->sock);
33575 + fdevent_unregister(srv->ev, hctx->sock);
33576 + closesocket(hctx->sock->fd);
33577 + hctx->sock->fd = -1;
33582 if (hctx->host && hctx->proc) {
33583 hctx->host->load--;
33586 if (hctx->got_proc) {
33587 /* after the connect the process gets a load */
33588 hctx->proc->load--;
33591 if (p->conf.debug) {
33592 log_error_write(srv, __FILE__, __LINE__, "sddb",
33597 hctx->proc->pid, hctx->proc->socket);
33600 @@ -1186,87 +1174,87 @@
33601 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
33606 handler_ctx_free(hctx);
33607 - con->plugin_ctx[p->id] = NULL;
33608 + con->plugin_ctx[p->id] = NULL;
33611 static int scgi_reconnect(server *srv, handler_ctx *hctx) {
33612 plugin_data *p = hctx->plugin_data;
33623 * connect was ok, connection was accepted
33624 * but the php accept loop checks after the accept if it should die or not.
33626 - * if yes we can only detect it at a write()
33629 + * if yes we can only detect it at a write()
33631 * next step is resetting this attemp and setup a connection again
33634 * if we have more then 5 reconnects for the same request, die
33641 * we have a connection but the child died by some other reason
33646 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
33647 - fdevent_unregister(srv->ev, hctx->fd);
33650 + fdevent_event_del(srv->ev, hctx->sock);
33651 + fdevent_unregister(srv->ev, hctx->sock);
33652 + closesocket(hctx->sock->fd);
33655 - scgi_set_state(srv, hctx, FCGI_STATE_INIT);
33658 + scgi_set_state(srv, hctx, SCGI_STATE_INIT);
33660 hctx->request_id = 0;
33661 hctx->reconnects++;
33664 if (p->conf.debug) {
33665 log_error_write(srv, __FILE__, __LINE__, "sddb",
33670 hctx->proc->pid, hctx->proc->socket);
33674 hctx->proc->load--;
33675 scgi_proclist_sort_down(srv, hctx->host, hctx->proc);
33682 static handler_t scgi_connection_reset(server *srv, connection *con, void *p_d) {
33683 plugin_data *p = p_d;
33686 scgi_connection_cleanup(srv, con->plugin_ctx[p->id]);
33689 return HANDLER_GO_ON;
33693 static int scgi_env_add(buffer *env, const char *key, size_t key_len, const char *val, size_t val_len) {
33697 if (!key || !val) return -1;
33700 len = key_len + val_len + 2;
33703 buffer_prepare_append(env, len);
33705 - /* include the NUL */
33706 + /* include the NUL */
33707 memcpy(env->ptr + env->used, key, key_len + 1);
33708 env->used += key_len + 1;
33709 memcpy(env->ptr + env->used, val, val_len + 1);
33710 env->used += val_len + 1;
33723 @@ -1280,24 +1268,21 @@
33724 struct sockaddr_un scgi_addr_un;
33729 scgi_extension_host *host = hctx->host;
33730 scgi_proc *proc = hctx->proc;
33731 - int scgi_fd = hctx->fd;
33733 + int scgi_fd = hctx->sock->fd;
33735 memset(&scgi_addr, 0, sizeof(scgi_addr));
33738 if (!buffer_is_empty(proc->socket)) {
33739 #ifdef HAVE_SYS_UN_H
33740 /* use the unix domain socket */
33741 scgi_addr_un.sun_family = AF_UNIX;
33742 strcpy(scgi_addr_un.sun_path, proc->socket->ptr);
33745 servlen = SUN_LEN(&scgi_addr_un);
33747 - /* stevens says: */
33748 - servlen = proc->socket->used + sizeof(scgi_addr_un.sun_family);
33751 scgi_addr = (struct sockaddr *) &scgi_addr_un;
33754 @@ -1305,105 +1290,105 @@
33756 scgi_addr_in.sin_family = AF_INET;
33757 if (0 == inet_aton(host->host->ptr, &(scgi_addr_in.sin_addr))) {
33758 - log_error_write(srv, __FILE__, __LINE__, "sbs",
33759 - "converting IP-adress failed for", host->host,
33760 + log_error_write(srv, __FILE__, __LINE__, "sbs",
33761 + "converting IP-adress failed for", host->host,
33762 "\nBe sure to specify an IP address here");
33767 scgi_addr_in.sin_port = htons(proc->port);
33768 servlen = sizeof(scgi_addr_in);
33771 scgi_addr = (struct sockaddr *) &scgi_addr_in;
33775 if (-1 == connect(scgi_fd, scgi_addr, servlen)) {
33776 - if (errno == EINPROGRESS ||
33777 + if (errno == EINPROGRESS ||
33778 errno == EALREADY ||
33780 if (hctx->conf.debug) {
33781 - log_error_write(srv, __FILE__, __LINE__, "sd",
33782 + log_error_write(srv, __FILE__, __LINE__, "sd",
33783 "connect delayed, will continue later:", scgi_fd);
33789 - log_error_write(srv, __FILE__, __LINE__, "sdsddb",
33790 - "connect failed:", scgi_fd,
33791 + log_error_write(srv, __FILE__, __LINE__, "sdsddb",
33792 + "connect failed:", scgi_fd,
33793 strerror(errno), errno,
33794 proc->port, proc->socket);
33796 if (errno == EAGAIN) {
33797 /* this is Linux only */
33799 - log_error_write(srv, __FILE__, __LINE__, "s",
33801 + log_error_write(srv, __FILE__, __LINE__, "s",
33802 "If this happend on Linux: You have been run out of local ports. "
33803 "Check the manual, section Performance how to handle this.");
33811 if (hctx->conf.debug > 1) {
33812 - log_error_write(srv, __FILE__, __LINE__, "sd",
33813 + log_error_write(srv, __FILE__, __LINE__, "sd",
33814 "connect succeeded: ", scgi_fd);
33823 static int scgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
33827 for (i = 0; i < con->request.headers->used; i++) {
33831 ds = (data_string *)con->request.headers->data[i];
33834 if (ds->value->used && ds->key->used) {
33836 buffer_reset(srv->tmp_buf);
33839 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
33840 BUFFER_COPY_STRING_CONST(srv->tmp_buf, "HTTP_");
33841 srv->tmp_buf->used--;
33845 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
33846 for (j = 0; j < ds->key->used - 1; j++) {
33847 - srv->tmp_buf->ptr[srv->tmp_buf->used++] =
33848 - light_isalpha(ds->key->ptr[j]) ?
33849 + srv->tmp_buf->ptr[srv->tmp_buf->used++] =
33850 + light_isalpha(ds->key->ptr[j]) ?
33851 ds->key->ptr[j] & ~32 : '_';
33853 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
33856 scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
33861 for (i = 0; i < con->environment->used; i++) {
33865 ds = (data_string *)con->environment->data[i];
33868 if (ds->value->used && ds->key->used) {
33870 buffer_reset(srv->tmp_buf);
33873 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
33874 for (j = 0; j < ds->key->used - 1; j++) {
33875 - srv->tmp_buf->ptr[srv->tmp_buf->used++] =
33876 - isalpha((unsigned char)ds->key->ptr[j]) ?
33877 + srv->tmp_buf->ptr[srv->tmp_buf->used++] =
33878 + isalpha((unsigned char)ds->key->ptr[j]) ?
33879 toupper((unsigned char)ds->key->ptr[j]) : '_';
33881 srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
33884 scgi_env_add(p->scgi_env, CONST_BUF_LEN(srv->tmp_buf), CONST_BUF_LEN(ds->value));
33892 @@ -1415,20 +1400,20 @@
33893 char b2[INET6_ADDRSTRLEN + 1];
33898 plugin_data *p = hctx->plugin_data;
33899 scgi_extension_host *host= hctx->host;
33901 connection *con = hctx->remote_conn;
33902 server_socket *srv_sock = con->srv_socket;
33905 sock_addr our_addr;
33906 socklen_t our_addr_len;
33909 buffer_prepare_copy(p->scgi_env, 1024);
33911 /* CGI-SPEC 6.1.2, FastCGI spec 6.3 and SCGI spec */
33914 /* request.content_length < SSIZE_MAX, see request.c */
33915 ltostr(buf, con->request.content_length);
33916 scgi_env_add(p->scgi_env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
33917 @@ -1436,13 +1421,13 @@
33920 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_SOFTWARE"), CONST_STR_LEN(PACKAGE_NAME"/"PACKAGE_VERSION));
33923 if (con->server_name->used) {
33924 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), CONST_BUF_LEN(con->server_name));
33927 - s = inet_ntop(srv_sock->addr.plain.sa_family,
33928 - srv_sock->addr.plain.sa_family == AF_INET6 ?
33929 + s = inet_ntop(srv_sock->addr.plain.sa_family,
33930 + srv_sock->addr.plain.sa_family == AF_INET6 ?
33931 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
33932 (const void *) &(srv_sock->addr.ipv4.sin_addr),
33934 @@ -1451,47 +1436,47 @@
33936 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_NAME"), s, strlen(s));
33940 scgi_env_add(p->scgi_env, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1"));
33946 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
33948 ntohs(srv_sock->addr.ipv4.sin_port)
33953 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PORT"), buf, strlen(buf));
33956 /* get the server-side of the connection to the client */
33957 our_addr_len = sizeof(our_addr);
33959 - if (-1 == getsockname(con->fd, &(our_addr.plain), &our_addr_len)) {
33961 + if (-1 == getsockname(con->sock->fd, &(our_addr.plain), &our_addr_len)) {
33962 s = inet_ntop_cache_get_ip(srv, &(srv_sock->addr));
33964 s = inet_ntop_cache_get_ip(srv, &(our_addr));
33966 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_ADDR"), s, strlen(s));
33972 ntohs(con->dst_addr.plain.sa_family ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
33974 ntohs(con->dst_addr.ipv4.sin_port)
33979 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_PORT"), buf, strlen(buf));
33982 s = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
33983 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
33986 if (!buffer_is_empty(con->authed_user)) {
33987 scgi_env_add(p->scgi_env, CONST_STR_LEN("REMOTE_USER"),
33988 CONST_BUF_LEN(con->authed_user));
33994 * SCRIPT_NAME, PATH_INFO and PATH_TRANSLATED according to
33995 @@ -1500,12 +1485,12 @@
33998 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));
34001 if (!buffer_is_empty(con->request.pathinfo)) {
34002 scgi_env_add(p->scgi_env, CONST_STR_LEN("PATH_INFO"), CONST_BUF_LEN(con->request.pathinfo));
34005 /* PATH_TRANSLATED is only defined if PATH_INFO is set */
34008 if (!buffer_is_empty(host->docroot)) {
34009 buffer_copy_string_buffer(p->path, host->docroot);
34011 @@ -1526,19 +1511,19 @@
34014 if (!buffer_is_empty(host->docroot)) {
34016 - * rewrite SCRIPT_FILENAME
34019 + * rewrite SCRIPT_FILENAME
34024 buffer_copy_string_buffer(p->path, host->docroot);
34025 buffer_append_string_buffer(p->path, con->uri.path);
34028 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34029 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(host->docroot));
34031 buffer_copy_string_buffer(p->path, con->physical.path);
34034 scgi_env_add(p->scgi_env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(p->path));
34035 scgi_env_add(p->scgi_env, CONST_STR_LEN("DOCUMENT_ROOT"), CONST_BUF_LEN(con->physical.doc_root));
34037 @@ -1551,30 +1536,30 @@
34039 scgi_env_add(p->scgi_env, CONST_STR_LEN("QUERY_STRING"), CONST_STR_LEN(""));
34043 s = get_http_method_name(con->request.http_method);
34044 scgi_env_add(p->scgi_env, CONST_STR_LEN("REQUEST_METHOD"), s, strlen(s));
34045 scgi_env_add(p->scgi_env, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */
34046 s = get_http_version_name(con->request.http_version);
34047 scgi_env_add(p->scgi_env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
34051 if (srv_sock->is_ssl) {
34052 scgi_env_add(p->scgi_env, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on"));
34057 scgi_env_add_request_headers(srv, con, p);
34059 b = chunkqueue_get_append_buffer(hctx->wb);
34062 buffer_append_long(b, p->scgi_env->used);
34063 buffer_append_string_len(b, CONST_STR_LEN(":"));
34064 buffer_append_string_len(b, (const char *)p->scgi_env->ptr, p->scgi_env->used);
34065 buffer_append_string_len(b, CONST_STR_LEN(","));
34067 hctx->wb->bytes_in += b->used - 1;
34070 if (con->request.content_length) {
34071 chunkqueue *req_cq = con->request_content_queue;
34073 @@ -1587,7 +1572,7 @@
34075 /* we announce toWrite octects
34076 * now take all the request_content chunk that we need to fill this request
34080 switch (req_c->type) {
34082 @@ -1615,293 +1600,170 @@
34084 req_c->offset += weHave;
34085 req_cq->bytes_out += weHave;
34088 hctx->wb->bytes_in += weHave;
34102 for (i = 0; i < hctx->write_buffer->used; i++) {
34103 fprintf(stderr, "%02x ", hctx->write_buffer->ptr[i]);
34104 if ((i+1) % 16 == 0) {
34106 for (j = i-15; j <= i; j++) {
34107 - fprintf(stderr, "%c",
34108 + fprintf(stderr, "%c",
34109 isprint((unsigned char)hctx->write_buffer->ptr[j]) ? hctx->write_buffer->ptr[j] : '.');
34111 fprintf(stderr, "\n");
34119 -static int scgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
34126 - buffer_copy_string_buffer(p->parse_response, in);
34128 - for (s = p->parse_response->ptr;
34129 - NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
34130 - s = ns + (eol == EOL_RN ? 2 : 1), line++) {
34131 - const char *key, *value;
34138 - 0 == strncmp(s, "HTTP/1.", 7)) {
34139 - /* non-parsed header ... we parse them anyway */
34141 - if ((s[7] == '1' ||
34145 - /* after the space should be a status code for us */
34147 - status = strtol(s+9, NULL, 10);
34149 - if (con->http_status >= 100 &&
34150 - con->http_status < 1000) {
34151 - /* we expected 3 digits and didn't got them */
34152 - con->parsed_response |= HTTP_STATUS;
34153 - con->http_status = status;
34159 - if (NULL == (value = strchr(s, ':'))) {
34160 - /* we expect: "<key>: <value>\r\n" */
34164 - key_len = value - key;
34168 - while (*value == ' ' || *value == '\t') value++;
34170 - if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34171 - ds = data_response_init();
34173 - buffer_copy_string_len(ds->key, key, key_len);
34174 - buffer_copy_string(ds->value, value);
34176 - array_insert_unique(con->response.headers, (data_unset *)ds);
34178 - switch(key_len) {
34180 - if (0 == strncasecmp(key, "Date", key_len)) {
34181 - con->parsed_response |= HTTP_DATE;
34185 - if (0 == strncasecmp(key, "Status", key_len)) {
34186 - con->http_status = strtol(value, NULL, 10);
34187 - con->parsed_response |= HTTP_STATUS;
34191 - if (0 == strncasecmp(key, "Location", key_len)) {
34192 - con->parsed_response |= HTTP_LOCATION;
34196 - if (0 == strncasecmp(key, "Connection", key_len)) {
34197 - con->response.keep_alive = (0 == strcasecmp(value, "Keep-Alive")) ? 1 : 0;
34198 - con->parsed_response |= HTTP_CONNECTION;
34202 - if (0 == strncasecmp(key, "Content-Length", key_len)) {
34203 - con->response.content_length = strtol(value, NULL, 10);
34204 - con->parsed_response |= HTTP_CONTENT_LENGTH;
34213 - /* CGI/1.1 rev 03 - 7.2.1.2 */
34214 - if ((con->parsed_response & HTTP_LOCATION) &&
34215 - !(con->parsed_response & HTTP_STATUS)) {
34216 - con->http_status = 302;
34223 static int scgi_demux_response(server *srv, handler_ctx *hctx) {
34224 plugin_data *p = hctx->plugin_data;
34225 connection *con = hctx->remote_conn;
34230 - buffer_prepare_copy(hctx->response, 1024);
34231 - if (-1 == (n = read(hctx->fd, hctx->response->ptr, hctx->response->size - 1))) {
34232 - if (errno == EAGAIN || errno == EINTR) {
34233 - /* would block, wait for signal */
34237 - log_error_write(srv, __FILE__, __LINE__, "sdd", strerror(errno), con->fd, hctx->fd);
34242 - /* read finished */
34244 - con->file_finished = 1;
34246 - /* send final chunk */
34247 - http_chunk_append_mem(srv, con, NULL, 0);
34248 - joblist_append(srv, con);
34252 + switch(srv->network_backend_read(srv, con, hctx->sock, hctx->rb)) {
34253 + case NETWORK_STATUS_SUCCESS:
34254 + /* we got content */
34256 + case NETWORK_STATUS_WAIT_FOR_EVENT:
34257 + /* the ioctl will return WAIT_FOR_EVENT on a read */
34258 + if (0 == con->file_started) return -1;
34259 + case NETWORK_STATUS_CONNECTION_CLOSE:
34260 + /* we are done, get out of here */
34261 + con->file_finished = 1;
34263 + /* close the chunk-queue with a empty chunk */
34271 + /* looks like we got some content
34273 + * split off the header from the incoming stream
34276 + if (hctx->state == SCGI_STATE_RESPONSE_HEADER) {
34278 + int have_content_length = 0;
34280 + http_response_reset(p->resp);
34282 + /* the response header is not fully received yet,
34284 + * extract the http-response header from the rb-cq
34286 + switch (http_response_parse_cq(hctx->rb, p->resp)) {
34287 + case PARSE_ERROR:
34288 + /* parsing failed */
34290 + con->http_status = 502; /* Bad Gateway */
34294 - hctx->response->ptr[n] = '\0';
34295 - hctx->response->used = n+1;
34297 - /* split header from body */
34299 - if (con->file_started == 0) {
34301 - int in_header = 0;
34302 - int header_end = 0;
34303 - int cp, eol = EOL_UNSET;
34306 - buffer_append_string_buffer(hctx->response_header, hctx->response);
34308 - /* nph (non-parsed headers) */
34309 - if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
34311 - /* search for the \r\n\r\n or \n\n in the string */
34312 - for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
34313 - if (*c == ':') in_header = 1;
34314 - else if (*c == '\n') {
34315 - if (in_header == 0) {
34316 - /* got a response without a response header */
34323 - if (eol == EOL_UNSET) eol = EOL_N;
34325 - if (*(c+1) == '\n') {
34330 - } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
34331 - if (in_header == 0) {
34332 - /* got a response without a response header */
34339 - if (eol == EOL_UNSET) eol = EOL_RN;
34342 - *(c+2) == '\r' &&
34343 - *(c+3) == '\n') {
34348 - /* skip the \n */
34352 + case PARSE_NEED_MORE:
34354 + case PARSE_SUCCESS:
34355 + con->http_status = p->resp->status;
34357 + chunkqueue_remove_finished_chunks(hctx->rb);
34359 + /* copy the http-headers */
34360 + for (i = 0; i < p->resp->headers->used; i++) {
34361 + const char *ign[] = { "Status", "Connection", NULL };
34365 + data_string *header = (data_string *)p->resp->headers->data[i];
34367 + /* some headers are ignored by default */
34368 + for (j = 0; ign[j]; j++) {
34369 + if (0 == strcasecmp(ign[j], header->key->ptr)) break;
34373 - if (header_end) {
34375 - /* no header, but a body */
34377 - if (con->request.http_version == HTTP_VERSION_1_1) {
34378 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34381 - http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
34382 - joblist_append(srv, con);
34384 - size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
34385 - size_t blen = hctx->response_header->used - hlen - 1;
34387 - /* a small hack: terminate after at the second \r */
34388 - hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
34389 - hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
34391 - /* parse the response header */
34392 - scgi_response_parse(srv, con, p, hctx->response_header, eol);
34394 - /* enable chunked-transfer-encoding */
34395 - if (con->request.http_version == HTTP_VERSION_1_1 &&
34396 - !(con->parsed_response & HTTP_CONTENT_LENGTH)) {
34397 - con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34400 - if ((hctx->response->used != hlen) && blen > 0) {
34401 - http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
34402 - joblist_append(srv, con);
34404 + if (ign[j]) continue;
34406 + if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Location"))) {
34407 + /* CGI/1.1 rev 03 - 7.2.1.2 */
34408 + if (con->http_status == 0) con->http_status = 302;
34409 + } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(header->key), CONST_STR_LEN("Content-Length"))) {
34410 + have_content_length = 1;
34413 - con->file_started = 1;
34414 + if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
34415 + ds = data_response_init();
34417 + buffer_copy_string_buffer(ds->key, header->key);
34418 + buffer_copy_string_buffer(ds->value, header->value);
34420 + array_insert_unique(con->response.headers, (data_unset *)ds);
34423 - http_chunk_append_mem(srv, con, hctx->response->ptr, hctx->response->used);
34424 - joblist_append(srv, con);
34426 + con->file_started = 1;
34428 + if (con->request.http_version == HTTP_VERSION_1_1 &&
34429 + !have_content_length) {
34430 + con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
34433 + hctx->state = SCGI_STATE_RESPONSE_CONTENT;
34438 - log_error_write(srv, __FILE__, __LINE__, "ddss", con->fd, hctx->fd, connection_get_state(con->state), b->ptr);
34443 + /* FIXME: pass the response-header to the other plugins to
34444 + * setup the filter-queue
34446 + * - use next-queue instead of con->write_queue
34449 + assert(hctx->state == SCGI_STATE_RESPONSE_CONTENT);
34451 + /* FIXME: if we have a content-length or chunked-encoding
34454 + * for now we wait for EOF on the socket */
34456 + /* copy the content to the next cq */
34457 + for (c = hctx->rb->first; c; c = c->next) {
34458 + http_chunk_append_mem(srv, con, c->mem->ptr + c->offset, c->mem->used - c->offset);
34460 + c->offset = c->mem->used - 1;
34463 + chunkqueue_remove_finished_chunks(hctx->rb);
34464 + joblist_append(srv, con);
34470 int scgi_proclist_sort_up(server *srv, scgi_extension_host *host, scgi_proc *proc) {
34476 - /* we have been the smallest of the current list
34477 - * and we want to insert the node sorted as soon
34479 + /* we have been the smallest of the current list
34480 + * and we want to insert the node sorted as soon
34493 /* nothing to sort, only one element */
34494 @@ -1909,9 +1771,9 @@
34496 for (p = proc; p->next && p->next->load < proc->load; p = p->next);
34498 - /* no need to move something
34499 + /* no need to move something
34506 @@ -1930,16 +1792,16 @@
34508 if (proc->prev) proc->prev->next = proc->next;
34509 if (proc->next) proc->next->prev = proc->prev;
34512 /* proc should be right of p */
34515 proc->next = p->next;
34517 if (p->next) p->next->prev = proc;
34520 for(p = host->first; p; p = p->next) {
34521 - log_error_write(srv, __FILE__, __LINE__, "dd",
34522 + log_error_write(srv, __FILE__, __LINE__, "dd",
34526 @@ -1951,21 +1813,21 @@
34528 int scgi_proclist_sort_down(server *srv, scgi_extension_host *host, scgi_proc *proc) {
34534 - /* we have been the smallest of the current list
34535 - * and we want to insert the node sorted as soon
34537 + /* we have been the smallest of the current list
34538 + * and we want to insert the node sorted as soon
34548 * the basic is idea is:
34549 - * - the last active scgi process should be still
34550 + * - the last active scgi process should be still
34551 * in ram and is not swapped out yet
34552 * - processes that are not reused will be killed
34553 * after some time by the trigger-handler
34554 @@ -1975,7 +1837,7 @@
34555 * ice-cold processes are propably unused since more
34556 * than 'unused-timeout', are swaped out and won't be
34557 * reused in the next seconds anyway.
34562 /* nothing to sort, only one element */
34563 @@ -1984,16 +1846,16 @@
34564 for (p = host->first; p != proc && p->load < proc->load; p = p->next);
34567 - /* no need to move something
34568 + /* no need to move something
34577 if (p == proc) return 0;
34580 /* we have to move left. If we are already the first element
34582 if (host->first == proc) return 0;
34583 @@ -2009,9 +1871,9 @@
34586 if (proc->prev == NULL) host->first = proc;
34589 for(p = host->first; p; p = p->next) {
34590 - log_error_write(srv, __FILE__, __LINE__, "dd",
34591 + log_error_write(srv, __FILE__, __LINE__, "dd",
34595 @@ -2023,41 +1885,42 @@
34597 static int scgi_restart_dead_procs(server *srv, plugin_data *p, scgi_extension_host *host) {
34601 for (proc = host->first; proc; proc = proc->next) {
34602 if (p->conf.debug) {
34603 - log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
34605 - host->host, proc->port,
34606 + log_error_write(srv, __FILE__, __LINE__, "sbdbdddd",
34608 + host->host, proc->port,
34617 if (0 == proc->is_local) {
34619 - * external servers might get disabled
34621 - * enable the server again, perhaps it is back again
34623 + * external servers might get disabled
34625 + * enable the server again, perhaps it is back again
34629 if ((proc->state == PROC_STATE_DISABLED) &&
34630 (srv->cur_ts - proc->disable_ts > host->disable_time)) {
34631 proc->state = PROC_STATE_RUNNING;
34632 host->active_procs++;
34634 - log_error_write(srv, __FILE__, __LINE__, "sbdb",
34635 - "fcgi-server re-enabled:",
34636 - host->host, host->port,
34638 + log_error_write(srv, __FILE__, __LINE__, "sbdb",
34639 + "fcgi-server re-enabled:",
34640 + host->host, host->port,
34644 /* the child should not terminate at all */
34648 if (proc->state == PROC_STATE_DIED_WAIT_FOR_PID) {
34650 switch(waitpid(proc->pid, &status, WNOHANG)) {
34652 /* child is still alive */
34653 @@ -2067,33 +1930,34 @@
34655 if (WIFEXITED(status)) {
34657 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
34658 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
34659 "child exited, pid:", proc->pid,
34660 "status:", WEXITSTATUS(status));
34662 } else if (WIFSIGNALED(status)) {
34663 - log_error_write(srv, __FILE__, __LINE__, "sd",
34664 - "child signaled:",
34665 + log_error_write(srv, __FILE__, __LINE__, "sd",
34666 + "child signaled:",
34669 - log_error_write(srv, __FILE__, __LINE__, "sd",
34670 - "child died somehow:",
34671 + log_error_write(srv, __FILE__, __LINE__, "sd",
34672 + "child died somehow:",
34677 proc->state = PROC_STATE_DIED;
34686 * local servers might died, but we restart them
34690 if (proc->state == PROC_STATE_DIED &&
34692 /* restart the child */
34695 if (p->conf.debug) {
34696 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
34697 "--- scgi spawning",
34698 @@ -2101,18 +1965,18 @@
34699 "\n\tsocket", host->unixsocket,
34700 "\n\tcurrent:", 1, "/", host->min_procs);
34704 if (scgi_spawn_connection(srv, p, host, proc)) {
34705 log_error_write(srv, __FILE__, __LINE__, "s",
34706 "ERROR: spawning fcgi failed.");
34707 return HANDLER_ERROR;
34711 scgi_proclist_sort_down(srv, host, proc);
34720 @@ -2121,13 +1985,13 @@
34721 plugin_data *p = hctx->plugin_data;
34722 scgi_extension_host *host= hctx->host;
34723 connection *con = hctx->remote_conn;
34728 - /* sanity check */
34729 + /* sanity check */
34731 ((!host->host->used || !host->port) && !host->unixsocket->used)) {
34732 - log_error_write(srv, __FILE__, __LINE__, "sxddd",
34733 + log_error_write(srv, __FILE__, __LINE__, "sxddd",
34734 "write-req: error",
34737 @@ -2135,259 +1999,260 @@
34738 host->unixsocket->used);
34739 return HANDLER_ERROR;
34744 switch(hctx->state) {
34745 - case FCGI_STATE_INIT:
34746 + case SCGI_STATE_INIT:
34747 ret = host->unixsocket->used ? AF_UNIX : AF_INET;
34749 - if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
34751 + if (-1 == (hctx->sock->fd = socket(ret, SOCK_STREAM, 0))) {
34752 if (errno == EMFILE ||
34754 - log_error_write(srv, __FILE__, __LINE__, "sd",
34755 - "wait for fd at connection:", con->fd);
34757 + log_error_write(srv, __FILE__, __LINE__, "sd",
34758 + "wait for fd at connection:", con->sock->fd);
34760 return HANDLER_WAIT_FOR_FD;
34763 - log_error_write(srv, __FILE__, __LINE__, "ssdd",
34765 + log_error_write(srv, __FILE__, __LINE__, "ssdd",
34766 "socket failed:", strerror(errno), srv->cur_fds, srv->max_fds);
34767 return HANDLER_ERROR;
34769 - hctx->fde_ndx = -1;
34771 + hctx->sock->fde_ndx = -1;
34775 - fdevent_register(srv->ev, hctx->fd, scgi_handle_fdevent, hctx);
34777 - if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
34778 - log_error_write(srv, __FILE__, __LINE__, "ss",
34780 + fdevent_register(srv->ev, hctx->sock, scgi_handle_fdevent, hctx);
34782 + if (-1 == fdevent_fcntl_set(srv->ev, hctx->sock)) {
34783 + log_error_write(srv, __FILE__, __LINE__, "ss",
34784 "fcntl failed: ", strerror(errno));
34787 return HANDLER_ERROR;
34792 - case FCGI_STATE_CONNECT:
34793 - if (hctx->state == FCGI_STATE_INIT) {
34794 - for (hctx->proc = hctx->host->first;
34795 - hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
34796 + case SCGI_STATE_CONNECT:
34797 + if (hctx->state == SCGI_STATE_INIT) {
34798 + for (hctx->proc = hctx->host->first;
34799 + hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
34800 hctx->proc = hctx->proc->next);
34803 /* all childs are dead */
34804 if (hctx->proc == NULL) {
34805 - hctx->fde_ndx = -1;
34807 + hctx->sock->fde_ndx = -1;
34809 return HANDLER_ERROR;
34813 if (hctx->proc->is_local) {
34814 hctx->pid = hctx->proc->pid;
34818 switch (scgi_establish_connection(srv, hctx)) {
34820 - scgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
34822 + scgi_set_state(srv, hctx, SCGI_STATE_CONNECT);
34824 /* connection is in progress, wait for an event and call getsockopt() below */
34826 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
34829 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
34831 return HANDLER_WAIT_FOR_EVENT;
34833 /* if ECONNREFUSED choose another connection -> FIXME */
34834 - hctx->fde_ndx = -1;
34836 + hctx->sock->fde_ndx = -1;
34838 return HANDLER_ERROR;
34840 /* everything is ok, go on */
34848 socklen_t socket_error_len = sizeof(socket_error);
34851 /* try to finish the connect() */
34852 - if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
34853 - log_error_write(srv, __FILE__, __LINE__, "ss",
34854 + if (0 != getsockopt(hctx->sock->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
34855 + log_error_write(srv, __FILE__, __LINE__, "ss",
34856 "getsockopt failed:", strerror(errno));
34859 return HANDLER_ERROR;
34861 if (socket_error != 0) {
34862 if (!hctx->proc->is_local || p->conf.debug) {
34863 /* local procs get restarted */
34866 log_error_write(srv, __FILE__, __LINE__, "ss",
34867 - "establishing connection failed:", strerror(socket_error),
34868 + "establishing connection failed:", strerror(socket_error),
34869 "port:", hctx->proc->port);
34873 return HANDLER_ERROR;
34878 /* ok, we have the connection */
34881 hctx->proc->load++;
34882 hctx->proc->last_used = srv->cur_ts;
34883 hctx->got_proc = 1;
34886 if (p->conf.debug) {
34887 log_error_write(srv, __FILE__, __LINE__, "sddbdd",
34891 - hctx->proc->socket,
34895 + hctx->proc->socket,
34900 /* move the proc-list entry down the list */
34901 scgi_proclist_sort_up(srv, hctx->host, hctx->proc);
34903 - scgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
34905 + scgi_set_state(srv, hctx, SCGI_STATE_PREPARE_WRITE);
34907 - case FCGI_STATE_PREPARE_WRITE:
34908 + case SCGI_STATE_PREPARE_WRITE:
34909 scgi_create_env(srv, hctx);
34911 - scgi_set_state(srv, hctx, FCGI_STATE_WRITE);
34914 + scgi_set_state(srv, hctx, SCGI_STATE_WRITE);
34917 - case FCGI_STATE_WRITE:
34918 - ret = srv->network_backend_write(srv, con, hctx->fd, hctx->wb);
34919 + case SCGI_STATE_WRITE:
34920 + ret = srv->network_backend_write(srv, con, hctx->sock, hctx->wb);
34922 chunkqueue_remove_finished_chunks(hctx->wb);
34926 if (errno == ENOTCONN) {
34927 - /* the connection got dropped after accept()
34929 - * this is most of the time a PHP which dies
34930 + /* the connection got dropped after accept()
34932 + * this is most of the time a PHP which dies
34933 * after PHP_FCGI_MAX_REQUESTS
34938 if (hctx->wb->bytes_out == 0 &&
34939 hctx->reconnects < 5) {
34940 - usleep(10000); /* take away the load of the webserver
34941 - * to let the php a chance to restart
34943 + usleep(10000); /* take away the load of the webserver
34944 + * to let the php a chance to restart
34948 scgi_reconnect(srv, hctx);
34951 return HANDLER_WAIT_FOR_FD;
34955 /* not reconnected ... why
34958 * far@#lighttpd report this for FreeBSD
34963 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
34965 + log_error_write(srv, __FILE__, __LINE__, "ssosd",
34966 "[REPORT ME] connection was dropped after accept(). reconnect() denied:",
34967 "write-offset:", hctx->wb->bytes_out,
34968 "reconnect attempts:", hctx->reconnects);
34971 return HANDLER_ERROR;
34975 if ((errno != EAGAIN) &&
34976 (errno != EINTR)) {
34978 - log_error_write(srv, __FILE__, __LINE__, "ssd",
34980 + log_error_write(srv, __FILE__, __LINE__, "ssd",
34981 "write failed:", strerror(errno), errno);
34984 return HANDLER_ERROR;
34986 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
34988 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
34990 return HANDLER_WAIT_FOR_EVENT;
34995 if (hctx->wb->bytes_out == hctx->wb->bytes_in) {
34996 /* we don't need the out event anymore */
34997 - fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
34998 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
34999 - scgi_set_state(srv, hctx, FCGI_STATE_READ);
35000 + fdevent_event_del(srv->ev, hctx->sock);
35001 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35002 + scgi_set_state(srv, hctx, SCGI_STATE_RESPONSE_HEADER);
35004 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35006 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35008 return HANDLER_WAIT_FOR_EVENT;
35013 - case FCGI_STATE_READ:
35014 + case SCGI_STATE_RESPONSE_HEADER:
35015 /* waiting for a response */
35018 log_error_write(srv, __FILE__, __LINE__, "s", "(debug) unknown state");
35019 return HANDLER_ERROR;
35023 return HANDLER_WAIT_FOR_EVENT;
35026 SUBREQUEST_FUNC(mod_scgi_handle_subrequest) {
35027 plugin_data *p = p_d;
35030 handler_ctx *hctx = con->plugin_ctx[p->id];
35032 scgi_extension_host *host;
35035 if (NULL == hctx) return HANDLER_GO_ON;
35039 if (con->mode != p->id) return HANDLER_GO_ON;
35042 /* ok, create the request */
35043 switch(scgi_write_request(srv, hctx)) {
35044 case HANDLER_ERROR:
35051 0 == proc->is_local &&
35052 proc->state != PROC_STATE_DISABLED) {
35053 /* only disable remote servers as we don't manage them*/
35055 - log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
35057 + log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
35063 /* disable this server */
35064 proc->disable_ts = srv->cur_ts;
35065 proc->state = PROC_STATE_DISABLED;
35066 host->active_procs--;
35069 - if (hctx->state == FCGI_STATE_INIT ||
35070 - hctx->state == FCGI_STATE_CONNECT) {
35071 - /* connect() or getsockopt() failed,
35072 - * restart the request-handling
35074 + if (hctx->state == SCGI_STATE_INIT ||
35075 + hctx->state == SCGI_STATE_CONNECT) {
35076 + /* connect() or getsockopt() failed,
35077 + * restart the request-handling
35079 if (proc && proc->is_local) {
35081 if (p->conf.debug) {
35082 - log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
35083 + log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to scgi failed, restarting the request-handling:",
35091 * several hctx might reference the same proc
35094 * Only one of them should mark the proc as dead all the other
35095 * ones should just take a new one.
35098 * If a new proc was started with the old struct this might lead
35099 * the mark a perfect proc as dead otherwise
35103 if (proc->state == PROC_STATE_RUNNING &&
35104 hctx->pid == proc->pid) {
35105 @@ -2395,25 +2260,25 @@
35108 scgi_restart_dead_procs(srv, p, host);
35111 scgi_connection_cleanup(srv, hctx);
35114 buffer_reset(con->physical.path);
35115 con->mode = DIRECT;
35116 joblist_append(srv, con);
35118 - /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35119 - * and hope that the childs will be restarted
35122 + /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
35123 + * and hope that the childs will be restarted
35126 return HANDLER_WAIT_FOR_FD;
35128 scgi_connection_cleanup(srv, hctx);
35131 buffer_reset(con->physical.path);
35132 con->mode = DIRECT;
35133 con->http_status = 503;
35136 return HANDLER_FINISHED;
35138 case HANDLER_WAIT_FOR_EVENT:
35139 @@ -2433,23 +2298,23 @@
35140 static handler_t scgi_connection_close(server *srv, handler_ctx *hctx) {
35145 if (NULL == hctx) return HANDLER_GO_ON;
35148 p = hctx->plugin_data;
35149 con = hctx->remote_conn;
35152 if (con->mode != p->id) return HANDLER_GO_ON;
35154 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35155 - "emergency exit: scgi:",
35156 - "connection-fd:", con->fd,
35157 - "fcgi-fd:", hctx->fd);
35162 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35163 + "emergency exit: scgi:",
35164 + "connection-fd:", con->sock->fd,
35165 + "fcgi-fd:", hctx->sock->fd);
35169 scgi_connection_cleanup(srv, hctx);
35172 return HANDLER_FINISHED;
35175 @@ -2459,27 +2324,28 @@
35176 handler_ctx *hctx = ctx;
35177 connection *con = hctx->remote_conn;
35178 plugin_data *p = hctx->plugin_data;
35181 scgi_proc *proc = hctx->proc;
35182 scgi_extension_host *host= hctx->host;
35184 if ((revents & FDEVENT_IN) &&
35185 - hctx->state == FCGI_STATE_READ) {
35186 + (hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35187 + hctx->state == SCGI_STATE_RESPONSE_CONTENT)) {
35188 switch (scgi_demux_response(srv, hctx)) {
35193 scgi_connection_cleanup(srv, hctx);
35196 joblist_append(srv, con);
35197 return HANDLER_FINISHED;
35199 if (proc->pid && proc->state != PROC_STATE_DIED) {
35203 /* only fetch the zombie if it is not already done */
35206 switch(waitpid(proc->pid, &status, WNOHANG)) {
35208 /* child is still alive */
35209 @@ -2489,19 +2355,19 @@
35211 /* the child should not terminate at all */
35212 if (WIFEXITED(status)) {
35213 - log_error_write(srv, __FILE__, __LINE__, "sdsd",
35214 + log_error_write(srv, __FILE__, __LINE__, "sdsd",
35215 "child exited, pid:", proc->pid,
35216 "status:", WEXITSTATUS(status));
35217 } else if (WIFSIGNALED(status)) {
35218 - log_error_write(srv, __FILE__, __LINE__, "sd",
35219 - "child signaled:",
35220 + log_error_write(srv, __FILE__, __LINE__, "sd",
35221 + "child signaled:",
35224 - log_error_write(srv, __FILE__, __LINE__, "sd",
35225 - "child died somehow:",
35226 + log_error_write(srv, __FILE__, __LINE__, "sd",
35227 + "child died somehow:",
35232 if (p->conf.debug) {
35233 log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
35234 "--- scgi spawning",
35235 @@ -2509,40 +2375,41 @@
35236 "\n\tsocket", host->unixsocket,
35237 "\n\tcurrent:", 1, "/", host->min_procs);
35241 if (scgi_spawn_connection(srv, p, host, proc)) {
35243 proc->state = PROC_STATE_DIED;
35245 scgi_proclist_sort_down(srv, host, proc);
35254 if (con->file_started == 0) {
35255 /* nothing has been send out yet, try to use another child */
35258 if (hctx->wb->bytes_out == 0 &&
35259 hctx->reconnects < 5) {
35260 scgi_reconnect(srv, hctx);
35262 - log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35264 + log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35265 "response not sent, request not sent, reconnection.",
35266 - "connection-fd:", con->fd,
35267 - "fcgi-fd:", hctx->fd);
35269 + "connection-fd:", con->sock->fd,
35270 + "fcgi-fd:", hctx->sock->fd);
35272 return HANDLER_WAIT_FOR_FD;
35275 - log_error_write(srv, __FILE__, __LINE__, "sdsdsd",
35277 + log_error_write(srv, __FILE__, __LINE__, "sosdsd",
35278 "response not sent, request sent:", hctx->wb->bytes_out,
35279 - "connection-fd:", con->fd,
35280 - "fcgi-fd:", hctx->fd);
35282 + "connection-fd:", con->sock->fd,
35283 + "fcgi-fd:", hctx->sock->fd);
35285 scgi_connection_cleanup(srv, hctx);
35288 connection_set_state(srv, con, CON_STATE_HANDLE_REQUEST);
35289 buffer_reset(con->physical.path);
35290 con->http_status = 500;
35291 @@ -2550,76 +2417,77 @@
35293 /* response might have been already started, kill the connection */
35294 scgi_connection_cleanup(srv, hctx);
35296 - log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35298 + log_error_write(srv, __FILE__, __LINE__, "ssdsd",
35299 "response already sent out, termination connection",
35300 - "connection-fd:", con->fd,
35301 - "fcgi-fd:", hctx->fd);
35303 + "connection-fd:", con->sock->fd,
35304 + "fcgi-fd:", hctx->sock->fd);
35306 connection_set_state(srv, con, CON_STATE_ERROR);
35314 joblist_append(srv, con);
35315 return HANDLER_FINISHED;
35320 if (revents & FDEVENT_OUT) {
35321 - if (hctx->state == FCGI_STATE_CONNECT ||
35322 - hctx->state == FCGI_STATE_WRITE) {
35323 + if (hctx->state == SCGI_STATE_CONNECT ||
35324 + hctx->state == SCGI_STATE_WRITE) {
35325 /* we are allowed to send something out
35328 * 1. in a unfinished connect() call
35329 * 2. in a unfinished write() call (long POST request)
35331 return mod_scgi_handle_subrequest(srv, con, p);
35333 - log_error_write(srv, __FILE__, __LINE__, "sd",
35334 - "got a FDEVENT_OUT and didn't know why:",
35335 + log_error_write(srv, __FILE__, __LINE__, "sd",
35336 + "got a FDEVENT_OUT and didn't know why:",
35342 /* perhaps this issue is already handled */
35343 if (revents & FDEVENT_HUP) {
35344 - if (hctx->state == FCGI_STATE_CONNECT) {
35345 + if (hctx->state == SCGI_STATE_CONNECT) {
35346 /* getoptsock will catch this one (right ?)
35348 - * if we are in connect we might get a EINPROGRESS
35349 - * in the first call and a FDEVENT_HUP in the
35351 + * if we are in connect we might get a EINPROGRESS
35352 + * in the first call and a FDEVENT_HUP in the
35356 * FIXME: as it is a bit ugly.
35360 return mod_scgi_handle_subrequest(srv, con, p);
35361 - } else if (hctx->state == FCGI_STATE_READ &&
35362 + } else if ((hctx->state == SCGI_STATE_RESPONSE_HEADER ||
35363 + hctx->state == SCGI_STATE_RESPONSE_CONTENT ) &&
35364 hctx->proc->port == 0) {
35368 * ioctl says 8192 bytes to read from PHP and we receive directly a HUP for the socket
35369 * even if the FCGI_FIN packet is not received yet
35372 - log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35373 - "error: unexpected close of scgi connection for",
35374 + log_error_write(srv, __FILE__, __LINE__, "sbSBSDSd",
35375 + "error: unexpected close of scgi connection for",
35377 - "(no scgi process on host: ",
35378 + "(no scgi process on host: ",
35387 connection_set_state(srv, con, CON_STATE_ERROR);
35388 scgi_connection_close(srv, hctx);
35389 joblist_append(srv, con);
35391 } else if (revents & FDEVENT_ERR) {
35392 - log_error_write(srv, __FILE__, __LINE__, "s",
35393 + log_error_write(srv, __FILE__, __LINE__, "s",
35394 "fcgi: got a FDEVENT_ERR. Don't know why.");
35395 /* kill all connections to the scgi process */
35397 @@ -2628,42 +2496,39 @@
35398 scgi_connection_close(srv, hctx);
35399 joblist_append(srv, con);
35403 return HANDLER_FINISHED;
35405 -#define PATCH(x) \
35406 - p->conf.x = s->x;
35408 static int scgi_patch_connection(server *srv, connection *con, plugin_data *p) {
35410 plugin_config *s = p->config_storage[0];
35416 + PATCH_OPTION(exts);
35417 + PATCH_OPTION(debug);
35419 /* skip the first, the global context */
35420 for (i = 1; i < srv->config_context->used; i++) {
35421 data_config *dc = (data_config *)srv->config_context->data[i];
35422 s = p->config_storage[i];
35425 /* condition didn't match */
35426 if (!config_check_cond(srv, con, dc)) continue;
35430 for (j = 0; j < dc->value->used; j++) {
35431 data_unset *du = dc->value->data[j];
35434 if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.server"))) {
35436 + PATCH_OPTION(exts);
35437 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("scgi.debug"))) {
35439 + PATCH_OPTION(debug);
35450 static handler_t scgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
35451 plugin_data *p = p_d;
35452 @@ -2673,30 +2538,30 @@
35455 scgi_extension *extension = NULL;
35458 /* Possibly, we processed already this request */
35459 if (con->file_started == 1) return HANDLER_GO_ON;
35462 fn = uri_path_handler ? con->uri.path : con->physical.path;
35464 if (buffer_is_empty(fn)) return HANDLER_GO_ON;
35466 s_len = fn->used - 1;
35469 scgi_patch_connection(srv, con, p);
35471 /* check if extension matches */
35472 for (k = 0; k < p->conf.exts->used; k++) {
35476 extension = p->conf.exts->exts[k];
35479 if (extension->key->used == 0) continue;
35482 ct_len = extension->key->used - 1;
35485 if (s_len < ct_len) continue;
35488 /* check extension in the form "/scgi_pattern" */
35489 if (*(extension->key->ptr) == '/' && strncmp(fn->ptr, extension->key->ptr, ct_len) == 0) {
35491 @@ -2710,17 +2575,17 @@
35492 if (k == p->conf.exts->used) {
35493 return HANDLER_GO_ON;
35497 /* get best server */
35498 for (k = 0, ndx = -1; k < extension->used; k++) {
35499 scgi_extension_host *host = extension->hosts[k];
35502 /* we should have at least one proc that can do somthing */
35503 if (host->active_procs == 0) continue;
35505 if (used == -1 || host->load < used) {
35512 @@ -2728,12 +2593,12 @@
35513 /* found a server */
35515 scgi_extension_host *host = extension->hosts[ndx];
35518 - * if check-local is disabled, use the uri.path handler
35522 + * if check-local is disabled, use the uri.path handler
35527 /* init handler-context */
35528 if (uri_path_handler) {
35529 if (host->check_local == 0) {
35530 @@ -2741,7 +2606,7 @@
35533 hctx = handler_ctx_init();
35536 hctx->remote_conn = con;
35537 hctx->plugin_data = p;
35539 @@ -2749,45 +2614,45 @@
35541 hctx->conf.exts = p->conf.exts;
35542 hctx->conf.debug = p->conf.debug;
35545 con->plugin_ctx[p->id] = hctx;
35553 if (con->conf.log_request_handling) {
35554 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_scgi");
35557 - /* the prefix is the SCRIPT_NAME,
35558 + /* the prefix is the SCRIPT_NAME,
35559 * everthing from start to the next slash
35560 * this is important for check-local = "disable"
35563 * if prefix = /admin.fcgi
35566 * /admin.fcgi/foo/bar
35569 * SCRIPT_NAME = /admin.fcgi
35570 * PATH_INFO = /foo/bar
35573 * if prefix = /fcgi-bin/
35576 * /fcgi-bin/foo/bar
35579 * SCRIPT_NAME = /fcgi-bin/foo
35586 /* the rewrite is only done for /prefix/? matches */
35587 if (extension->key->ptr[0] == '/' &&
35588 con->uri.path->used > extension->key->used &&
35589 NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
35590 - /* rewrite uri.path and pathinfo */
35592 + /* rewrite uri.path and pathinfo */
35594 buffer_copy_string(con->request.pathinfo, pathinfo);
35597 con->uri.path->used -= con->request.pathinfo->used - 1;
35598 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
35600 @@ -2796,21 +2661,21 @@
35603 hctx = handler_ctx_init();
35606 hctx->remote_conn = con;
35607 hctx->plugin_data = p;
35612 hctx->conf.exts = p->conf.exts;
35613 hctx->conf.debug = p->conf.debug;
35616 con->plugin_ctx[p->id] = hctx;
35625 if (con->conf.log_request_handling) {
35626 log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
35628 @@ -2821,11 +2686,11 @@
35629 /* no handler found */
35630 buffer_reset(con->physical.path);
35631 con->http_status = 500;
35633 - log_error_write(srv, __FILE__, __LINE__, "sb",
35634 - "no fcgi-handler found for:",
35636 + log_error_write(srv, __FILE__, __LINE__, "sb",
35637 + "no fcgi-handler found for:",
35641 return HANDLER_FINISHED;
35643 return HANDLER_GO_ON;
35644 @@ -2844,21 +2709,22 @@
35645 JOBLIST_FUNC(mod_scgi_handle_joblist) {
35646 plugin_data *p = p_d;
35647 handler_ctx *hctx = con->plugin_ctx[p->id];
35650 if (hctx == NULL) return HANDLER_GO_ON;
35652 - if (hctx->fd != -1) {
35653 + if (hctx->sock->fd != -1) {
35654 switch (hctx->state) {
35655 - case FCGI_STATE_READ:
35656 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
35658 + case SCGI_STATE_RESPONSE_HEADER:
35659 + case SCGI_STATE_RESPONSE_CONTENT:
35660 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_IN);
35663 - case FCGI_STATE_CONNECT:
35664 - case FCGI_STATE_WRITE:
35665 - fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
35667 + case SCGI_STATE_CONNECT:
35668 + case SCGI_STATE_WRITE:
35669 + fdevent_event_add(srv->ev, hctx->sock, FDEVENT_OUT);
35672 - case FCGI_STATE_INIT:
35673 + case SCGI_STATE_INIT:
35677 @@ -2873,21 +2739,21 @@
35679 static handler_t scgi_connection_close_callback(server *srv, connection *con, void *p_d) {
35680 plugin_data *p = p_d;
35683 return scgi_connection_close(srv, con->plugin_ctx[p->id]);
35686 TRIGGER_FUNC(mod_scgi_handle_trigger) {
35687 plugin_data *p = p_d;
35693 /* perhaps we should kill a connect attempt after 10-15 seconds
35696 * currently we wait for the TCP timeout which is on Linux 180 seconds
35705 /* check all childs if they are still up */
35706 @@ -2904,47 +2770,47 @@
35707 scgi_extension *ex;
35709 ex = exts->exts[j];
35712 for (n = 0; n < ex->used; n++) {
35716 unsigned long sum_load = 0;
35717 scgi_extension_host *host;
35720 host = ex->hosts[n];
35723 scgi_restart_dead_procs(srv, p, host);
35726 for (proc = host->first; proc; proc = proc->next) {
35727 sum_load += proc->load;
35731 if (host->num_procs &&
35732 host->num_procs < host->max_procs &&
35733 (sum_load / host->num_procs) > host->max_load_per_proc) {
35734 /* overload, spawn new child */
35735 scgi_proc *fp = NULL;
35738 if (p->conf.debug) {
35739 - log_error_write(srv, __FILE__, __LINE__, "s",
35740 + log_error_write(srv, __FILE__, __LINE__, "s",
35741 "overload detected, spawning a new child");
35745 for (fp = host->unused_procs; fp && fp->pid != 0; fp = fp->next);
35749 if (fp == host->unused_procs) host->unused_procs = fp->next;
35752 if (fp->next) fp->next->prev = NULL;
35757 fp = scgi_process_init();
35758 fp->id = host->max_id++;
35765 if (buffer_is_empty(host->unixsocket)) {
35766 fp->port = host->port + fp->id;
35768 @@ -2952,13 +2818,13 @@
35769 buffer_append_string(fp->socket, "-");
35770 buffer_append_long(fp->socket, fp->id);
35774 if (scgi_spawn_connection(srv, p, host, fp)) {
35775 log_error_write(srv, __FILE__, __LINE__, "s",
35776 "ERROR: spawning fcgi failed.");
35777 return HANDLER_ERROR;
35782 fp->next = host->first;
35784 @@ -2966,56 +2832,57 @@
35790 for (proc = host->first; proc; proc = proc->next) {
35791 if (proc->load != 0) break;
35792 if (host->num_procs <= host->min_procs) break;
35793 if (proc->pid == 0) continue;
35796 if (srv->cur_ts - proc->last_used > host->idle_timeout) {
35797 /* a proc is idling for a long time now,
35801 if (p->conf.debug) {
35802 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
35803 - "idle-timeout reached, terminating child:",
35804 - "socket:", proc->socket,
35805 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
35806 + "idle-timeout reached, terminating child:",
35807 + "socket:", proc->socket,
35814 if (proc->next) proc->next->prev = proc->prev;
35815 if (proc->prev) proc->prev->next = proc->next;
35818 if (proc->prev == NULL) host->first = proc->next;
35822 proc->next = host->unused_procs;
35825 if (host->unused_procs) host->unused_procs->prev = proc;
35826 host->unused_procs = proc;
35829 kill(proc->pid, SIGTERM);
35832 proc->state = PROC_STATE_KILLED;
35834 - log_error_write(srv, __FILE__, __LINE__, "ssbsd",
35836 - "socket:", proc->socket,
35838 + log_error_write(srv, __FILE__, __LINE__, "ssbsd",
35840 + "socket:", proc->socket,
35847 /* proc is now in unused, let the next second handle the next process */
35855 for (proc = host->unused_procs; proc; proc = proc->next) {
35859 if (proc->pid == 0) continue;
35862 switch (waitpid(proc->pid, &status, WNOHANG)) {
35864 /* child still running after timeout, good */
35865 @@ -3023,10 +2890,10 @@
35867 if (errno != EINTR) {
35868 /* no PID found ? should never happen */
35869 - log_error_write(srv, __FILE__, __LINE__, "sddss",
35870 + log_error_write(srv, __FILE__, __LINE__, "sddss",
35871 "pid ", proc->pid, proc->state,
35872 "not found:", strerror(errno));
35876 if (errno == ECHILD) {
35877 /* someone else has cleaned up for us */
35878 @@ -3040,25 +2907,26 @@
35879 /* the child should not terminate at all */
35880 if (WIFEXITED(status)) {
35881 if (proc->state != PROC_STATE_KILLED) {
35882 - log_error_write(srv, __FILE__, __LINE__, "sdb",
35884 + log_error_write(srv, __FILE__, __LINE__, "sdb",
35886 WEXITSTATUS(status), proc->socket);
35888 } else if (WIFSIGNALED(status)) {
35889 if (WTERMSIG(status) != SIGTERM) {
35890 - log_error_write(srv, __FILE__, __LINE__, "sd",
35891 - "child signaled:",
35892 + log_error_write(srv, __FILE__, __LINE__, "sd",
35893 + "child signaled:",
35897 - log_error_write(srv, __FILE__, __LINE__, "sd",
35898 - "child died somehow:",
35899 + log_error_write(srv, __FILE__, __LINE__, "sd",
35900 + "child died somehow:",
35904 proc->state = PROC_STATE_UNSET;
35911 @@ -3082,8 +2950,8 @@
35912 p->handle_subrequest = mod_scgi_handle_subrequest;
35913 p->handle_joblist = mod_scgi_handle_joblist;
35914 p->handle_trigger = mod_scgi_handle_trigger;
35922 --- ../lighttpd-1.4.11/src/mod_secure_download.c 2005-12-14 14:37:29.000000000 +0200
35923 +++ lighttpd-1.4.12/src/mod_secure_download.c 2006-07-16 00:26:03.000000000 +0300
35933 @@ -36,28 +36,28 @@
35936 buffer *uri_prefix;
35939 unsigned short timeout;
35949 plugin_config **config_storage;
35951 - plugin_config conf;
35953 + plugin_config conf;
35956 /* init the plugin data */
35957 INIT_FUNC(mod_secdownload_init) {
35961 p = calloc(1, sizeof(*p));
35964 p->md5 = buffer_init();
35970 @@ -65,27 +65,27 @@
35971 FREE_FUNC(mod_secdownload_free) {
35972 plugin_data *p = p_d;
35976 if (!p) return HANDLER_GO_ON;
35979 if (p->config_storage) {
35981 for (i = 0; i < srv->config_context->used; i++) {
35982 plugin_config *s = p->config_storage[i];
35985 buffer_free(s->secret);
35986 buffer_free(s->doc_root);
35987 buffer_free(s->uri_prefix);
35992 free(p->config_storage);
35996 buffer_free(p->md5);
36002 return HANDLER_GO_ON;
36005 @@ -94,107 +94,103 @@
36006 SETDEFAULTS_FUNC(mod_secdownload_set_defaults) {
36007 plugin_data *p = p_d;
36010 - config_values_t cv[] = {
36012 + config_values_t cv[] = {
36013 { "secdownload.secret", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36014 { "secdownload.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
36015 { "secdownload.uri-prefix", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
36016 { "secdownload.timeout", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
36017 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36021 if (!p) return HANDLER_ERROR;
36024 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36027 for (i = 0; i < srv->config_context->used; i++) {
36031 s = calloc(1, sizeof(plugin_config));
36032 s->secret = buffer_init();
36033 s->doc_root = buffer_init();
36034 s->uri_prefix = buffer_init();
36038 cv[0].destination = s->secret;
36039 cv[1].destination = s->doc_root;
36040 cv[2].destination = s->uri_prefix;
36041 cv[3].destination = &(s->timeout);
36044 p->config_storage[i] = s;
36047 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36048 return HANDLER_ERROR;
36053 return HANDLER_GO_ON;
36057 * checks if the supplied string is a MD5 string
36060 * @param str a possible MD5 string
36061 * @return if the supplied string is a valid MD5 string 1 is returned otherwise 0
36064 int is_hex_len(const char *str, size_t len) {
36068 if (NULL == str) return 0;
36071 for (i = 0; i < len && *str; i++, str++) {
36072 /* illegal characters */
36073 if (!((*str >= '0' && *str <= '9') ||
36074 (*str >= 'a' && *str <= 'f') ||
36075 - (*str >= 'A' && *str <= 'F'))
36076 + (*str >= 'A' && *str <= 'F'))
36086 -#define PATCH(x) \
36087 - p->conf.x = s->x;
36088 static int mod_secdownload_patch_connection(server *srv, connection *con, plugin_data *p) {
36090 plugin_config *s = p->config_storage[0];
36094 - PATCH(uri_prefix);
36098 + PATCH_OPTION(secret);
36099 + PATCH_OPTION(doc_root);
36100 + PATCH_OPTION(uri_prefix);
36101 + PATCH_OPTION(timeout);
36103 /* skip the first, the global context */
36104 for (i = 1; i < srv->config_context->used; i++) {
36105 data_config *dc = (data_config *)srv->config_context->data[i];
36106 s = p->config_storage[i];
36109 /* condition didn't match */
36110 if (!config_check_cond(srv, con, dc)) continue;
36114 for (j = 0; j < dc->value->used; j++) {
36115 data_unset *du = dc->value->data[j];
36118 if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.secret"))) {
36120 + PATCH_OPTION(secret);
36121 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.document-root"))) {
36123 + PATCH_OPTION(doc_root);
36124 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.uri-prefix"))) {
36125 - PATCH(uri_prefix);
36126 + PATCH_OPTION(uri_prefix);
36127 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("secdownload.timeout"))) {
36129 + PATCH_OPTION(timeout);
36140 URIHANDLER_FUNC(mod_secdownload_uri_handler) {
36141 plugin_data *p = p_d;
36142 @@ -203,88 +199,88 @@
36143 const char *rel_uri, *ts_str, *md5_str;
36148 if (con->uri.path->used == 0) return HANDLER_GO_ON;
36151 mod_secdownload_patch_connection(srv, con, p);
36153 if (buffer_is_empty(p->conf.uri_prefix)) return HANDLER_GO_ON;
36156 if (buffer_is_empty(p->conf.secret)) {
36157 log_error_write(srv, __FILE__, __LINE__, "s",
36158 "secdownload.secret has to be set");
36159 return HANDLER_ERROR;
36163 if (buffer_is_empty(p->conf.doc_root)) {
36164 log_error_write(srv, __FILE__, __LINE__, "s",
36165 "secdownload.document-root has to be set");
36166 return HANDLER_ERROR;
36172 * /<uri-prefix>[a-f0-9]{32}/[a-f0-9]{8}/<rel-path>
36176 if (0 != strncmp(con->uri.path->ptr, p->conf.uri_prefix->ptr, p->conf.uri_prefix->used - 1)) return HANDLER_GO_ON;
36179 md5_str = con->uri.path->ptr + p->conf.uri_prefix->used - 1;
36182 if (!is_hex_len(md5_str, 32)) return HANDLER_GO_ON;
36183 if (*(md5_str + 32) != '/') return HANDLER_GO_ON;
36186 ts_str = md5_str + 32 + 1;
36189 if (!is_hex_len(ts_str, 8)) return HANDLER_GO_ON;
36190 if (*(ts_str + 8) != '/') return HANDLER_GO_ON;
36193 for (i = 0; i < 8; i++) {
36194 ts = (ts << 4) + hex2int(*(ts_str + i));
36199 - if (srv->cur_ts - ts > p->conf.timeout ||
36200 + if (srv->cur_ts - ts > p->conf.timeout ||
36201 srv->cur_ts - ts < -p->conf.timeout) {
36202 con->http_status = 408;
36205 return HANDLER_FINISHED;
36209 rel_uri = ts_str + 8;
36216 * <secret><rel-path><timestamp-hex>
36220 buffer_copy_string_buffer(p->md5, p->conf.secret);
36221 buffer_append_string(p->md5, rel_uri);
36222 buffer_append_string_len(p->md5, ts_str, 8);
36226 MD5_Update(&Md5Ctx, (unsigned char *)p->md5->ptr, p->md5->used - 1);
36227 MD5_Final(HA1, &Md5Ctx);
36230 buffer_copy_string_hex(p->md5, (char *)HA1, 16);
36233 if (0 != strncmp(md5_str, p->md5->ptr, 32)) {
36234 con->http_status = 403;
36236 - log_error_write(srv, __FILE__, __LINE__, "sss",
36238 + log_error_write(srv, __FILE__, __LINE__, "sss",
36240 md5_str, p->md5->ptr);
36243 return HANDLER_FINISHED;
36247 /* starting with the last / we should have relative-path to the docroot
36251 buffer_copy_string_buffer(con->physical.doc_root, p->conf.doc_root);
36252 buffer_copy_string(con->physical.rel_path, rel_uri);
36253 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
36254 buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
36257 return HANDLER_GO_ON;
36260 @@ -293,13 +289,13 @@
36261 int mod_secdownload_plugin_init(plugin *p) {
36262 p->version = LIGHTTPD_VERSION_ID;
36263 p->name = buffer_init_string("secdownload");
36266 p->init = mod_secdownload_init;
36267 p->handle_physical = mod_secdownload_uri_handler;
36268 p->set_defaults = mod_secdownload_set_defaults;
36269 p->cleanup = mod_secdownload_free;
36277 --- ../lighttpd-1.4.11/src/mod_setenv.c 2006-01-14 20:33:12.000000000 +0200
36278 +++ lighttpd-1.4.12/src/mod_setenv.c 2006-07-16 00:26:04.000000000 +0300
36279 @@ -18,25 +18,25 @@
36281 array *request_header;
36282 array *response_header;
36285 array *environment;
36292 plugin_config **config_storage;
36294 - plugin_config conf;
36296 + plugin_config conf;
36299 static handler_ctx * handler_ctx_init() {
36300 handler_ctx * hctx;
36303 hctx = calloc(1, sizeof(*hctx));
36312 @@ -48,36 +48,36 @@
36313 /* init the plugin data */
36314 INIT_FUNC(mod_setenv_init) {
36318 p = calloc(1, sizeof(*p));
36324 /* detroy the plugin data */
36325 FREE_FUNC(mod_setenv_free) {
36326 plugin_data *p = p_d;
36331 if (!p) return HANDLER_GO_ON;
36334 if (p->config_storage) {
36336 for (i = 0; i < srv->config_context->used; i++) {
36337 plugin_config *s = p->config_storage[i];
36340 array_free(s->request_header);
36341 array_free(s->response_header);
36342 array_free(s->environment);
36347 free(p->config_storage);
36354 return HANDLER_GO_ON;
36357 @@ -86,86 +86,83 @@
36358 SETDEFAULTS_FUNC(mod_setenv_set_defaults) {
36359 plugin_data *p = p_d;
36362 - config_values_t cv[] = {
36364 + config_values_t cv[] = {
36365 { "setenv.add-request-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
36366 { "setenv.add-response-header", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
36367 { "setenv.add-environment", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
36368 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36372 if (!p) return HANDLER_ERROR;
36375 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36378 for (i = 0; i < srv->config_context->used; i++) {
36382 s = calloc(1, sizeof(plugin_config));
36383 s->request_header = array_init();
36384 s->response_header = array_init();
36385 s->environment = array_init();
36388 cv[0].destination = s->request_header;
36389 cv[1].destination = s->response_header;
36390 cv[2].destination = s->environment;
36393 p->config_storage[i] = s;
36396 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36397 return HANDLER_ERROR;
36402 return HANDLER_GO_ON;
36405 -#define PATCH(x) \
36406 - p->conf.x = s->x;
36407 static int mod_setenv_patch_connection(server *srv, connection *con, plugin_data *p) {
36409 plugin_config *s = p->config_storage[0];
36411 - PATCH(request_header);
36412 - PATCH(response_header);
36413 - PATCH(environment);
36416 + PATCH_OPTION(request_header);
36417 + PATCH_OPTION(response_header);
36418 + PATCH_OPTION(environment);
36420 /* skip the first, the global context */
36421 for (i = 1; i < srv->config_context->used; i++) {
36422 data_config *dc = (data_config *)srv->config_context->data[i];
36423 s = p->config_storage[i];
36426 /* condition didn't match */
36427 if (!config_check_cond(srv, con, dc)) continue;
36431 for (j = 0; j < dc->value->used; j++) {
36432 data_unset *du = dc->value->data[j];
36435 if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-request-header"))) {
36436 - PATCH(request_header);
36437 + PATCH_OPTION(request_header);
36438 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-response-header"))) {
36439 - PATCH(response_header);
36440 + PATCH_OPTION(response_header);
36441 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("setenv.add-environment"))) {
36442 - PATCH(environment);
36443 + PATCH_OPTION(environment);
36453 URIHANDLER_FUNC(mod_setenv_uri_handler) {
36454 plugin_data *p = p_d;
36459 if (con->plugin_ctx[p->id]) {
36460 hctx = con->plugin_ctx[p->id];
36462 hctx = handler_ctx_init();
36465 con->plugin_ctx[p->id] = hctx;
36468 @@ -180,52 +177,52 @@
36469 for (k = 0; k < p->conf.request_header->used; k++) {
36470 data_string *ds = (data_string *)p->conf.request_header->data[k];
36471 data_string *ds_dst;
36474 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
36475 ds_dst = data_string_init();
36479 buffer_copy_string_buffer(ds_dst->key, ds->key);
36480 buffer_copy_string_buffer(ds_dst->value, ds->value);
36483 array_insert_unique(con->request.headers, (data_unset *)ds_dst);
36487 for (k = 0; k < p->conf.environment->used; k++) {
36488 data_string *ds = (data_string *)p->conf.environment->data[k];
36489 data_string *ds_dst;
36492 if (NULL == (ds_dst = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
36493 ds_dst = data_string_init();
36497 buffer_copy_string_buffer(ds_dst->key, ds->key);
36498 buffer_copy_string_buffer(ds_dst->value, ds->value);
36501 array_insert_unique(con->environment, (data_unset *)ds_dst);
36505 for (k = 0; k < p->conf.response_header->used; k++) {
36506 data_string *ds = (data_string *)p->conf.response_header->data[k];
36509 response_header_insert(srv, con, CONST_BUF_LEN(ds->key), CONST_BUF_LEN(ds->value));
36514 return HANDLER_GO_ON;
36517 REQUESTDONE_FUNC(mod_setenv_reset) {
36518 plugin_data *p = p_d;
36524 if (con->plugin_ctx[p->id]) {
36525 handler_ctx_free(con->plugin_ctx[p->id]);
36526 con->plugin_ctx[p->id] = NULL;
36529 - return HANDLER_GO_ON;
36530 + return HANDLER_GO_ON;
36533 /* this function is called at dlopen() time and inits the callbacks */
36534 @@ -233,15 +230,15 @@
36535 int mod_setenv_plugin_init(plugin *p) {
36536 p->version = LIGHTTPD_VERSION_ID;
36537 p->name = buffer_init_string("setenv");
36540 p->init = mod_setenv_init;
36541 p->handle_uri_clean = mod_setenv_uri_handler;
36542 p->set_defaults = mod_setenv_set_defaults;
36543 p->cleanup = mod_setenv_free;
36546 p->handle_request_done = mod_setenv_reset;
36553 --- ../lighttpd-1.4.11/src/mod_simple_vhost.c 2005-11-18 15:16:13.000000000 +0200
36554 +++ lighttpd-1.4.12/src/mod_simple_vhost.c 2006-07-16 00:26:04.000000000 +0300
36557 #include "plugin.h"
36559 +#include "sys-files.h"
36561 #ifdef HAVE_CONFIG_H
36562 #include "config.h"
36565 buffer *server_root;
36566 buffer *default_host;
36567 buffer *document_root;
36570 buffer *docroot_cache_key;
36571 buffer *docroot_cache_value;
36572 buffer *docroot_cache_servername;
36573 @@ -28,138 +30,138 @@
36582 plugin_config **config_storage;
36583 - plugin_config conf;
36584 + plugin_config conf;
36587 INIT_FUNC(mod_simple_vhost_init) {
36591 p = calloc(1, sizeof(*p));
36594 p->doc_root = buffer_init();
36600 FREE_FUNC(mod_simple_vhost_free) {
36601 plugin_data *p = p_d;
36606 if (!p) return HANDLER_GO_ON;
36609 if (p->config_storage) {
36611 for (i = 0; i < srv->config_context->used; i++) {
36612 plugin_config *s = p->config_storage[i];
36615 buffer_free(s->document_root);
36616 buffer_free(s->default_host);
36617 buffer_free(s->server_root);
36620 buffer_free(s->docroot_cache_key);
36621 buffer_free(s->docroot_cache_value);
36622 buffer_free(s->docroot_cache_servername);
36629 free(p->config_storage);
36633 buffer_free(p->doc_root);
36639 return HANDLER_GO_ON;
36642 SETDEFAULTS_FUNC(mod_simple_vhost_set_defaults) {
36643 plugin_data *p = p_d;
36646 - config_values_t cv[] = {
36648 + config_values_t cv[] = {
36649 { "simple-vhost.server-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
36650 { "simple-vhost.default-host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
36651 { "simple-vhost.document-root", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
36652 { "simple-vhost.debug", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION },
36653 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
36657 if (!p) return HANDLER_ERROR;
36660 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
36663 for (i = 0; i < srv->config_context->used; i++) {
36667 s = calloc(1, sizeof(plugin_config));
36670 s->server_root = buffer_init();
36671 s->default_host = buffer_init();
36672 s->document_root = buffer_init();
36675 s->docroot_cache_key = buffer_init();
36676 s->docroot_cache_value = buffer_init();
36677 s->docroot_cache_servername = buffer_init();
36682 cv[0].destination = s->server_root;
36683 cv[1].destination = s->default_host;
36684 cv[2].destination = s->document_root;
36685 cv[3].destination = &(s->debug);
36690 p->config_storage[i] = s;
36693 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
36694 return HANDLER_ERROR;
36699 return HANDLER_GO_ON;
36702 static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
36703 stat_cache_entry *sce = NULL;
36706 buffer_prepare_copy(out, 128);
36708 if (p->conf.server_root->used) {
36709 buffer_copy_string_buffer(out, p->conf.server_root);
36713 /* a hostname has to start with a alpha-numerical character
36714 * and must not contain a slash "/"
36718 - BUFFER_APPEND_SLASH(out);
36721 + PATHNAME_APPEND_SLASH(out);
36723 if (NULL == (dp = strchr(host->ptr, ':'))) {
36724 buffer_append_string_buffer(out, host);
36726 buffer_append_string_len(out, host->ptr, dp - host->ptr);
36729 - BUFFER_APPEND_SLASH(out);
36731 + PATHNAME_APPEND_SLASH(out);
36733 if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
36734 buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
36736 buffer_append_string_buffer(out, p->conf.document_root);
36737 - BUFFER_APPEND_SLASH(out);
36738 + PATHNAME_APPEND_SLASH(out);
36741 buffer_copy_string_buffer(out, con->conf.document_root);
36742 - BUFFER_APPEND_SLASH(out);
36743 + PATHNAME_APPEND_SLASH(out);
36747 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
36748 if (p->conf.debug) {
36749 log_error_write(srv, __FILE__, __LINE__, "sb",
36750 @@ -169,57 +171,53 @@
36751 } else if (!S_ISDIR(sce->st.st_mode)) {
36760 -#define PATCH(x) \
36761 - p->conf.x = s->x;
36762 static int mod_simple_vhost_patch_connection(server *srv, connection *con, plugin_data *p) {
36764 plugin_config *s = p->config_storage[0];
36766 - PATCH(server_root);
36767 - PATCH(default_host);
36768 - PATCH(document_root);
36770 - PATCH(docroot_cache_key);
36771 - PATCH(docroot_cache_value);
36772 - PATCH(docroot_cache_servername);
36776 + PATCH_OPTION(server_root);
36777 + PATCH_OPTION(default_host);
36778 + PATCH_OPTION(document_root);
36780 + PATCH_OPTION(docroot_cache_key);
36781 + PATCH_OPTION(docroot_cache_value);
36782 + PATCH_OPTION(docroot_cache_servername);
36784 + PATCH_OPTION(debug);
36786 /* skip the first, the global context */
36787 for (i = 1; i < srv->config_context->used; i++) {
36788 data_config *dc = (data_config *)srv->config_context->data[i];
36789 s = p->config_storage[i];
36792 /* condition didn't match */
36793 if (!config_check_cond(srv, con, dc)) continue;
36797 for (j = 0; j < dc->value->used; j++) {
36798 data_unset *du = dc->value->data[j];
36801 if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.server-root"))) {
36802 - PATCH(server_root);
36803 - PATCH(docroot_cache_key);
36804 - PATCH(docroot_cache_value);
36805 - PATCH(docroot_cache_servername);
36806 + PATCH_OPTION(server_root);
36807 + PATCH_OPTION(docroot_cache_key);
36808 + PATCH_OPTION(docroot_cache_value);
36809 + PATCH_OPTION(docroot_cache_servername);
36810 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.default-host"))) {
36811 - PATCH(default_host);
36812 + PATCH_OPTION(default_host);
36813 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.document-root"))) {
36814 - PATCH(document_root);
36815 + PATCH_OPTION(document_root);
36816 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("simple-vhost.debug"))) {
36818 + PATCH_OPTION(debug);
36828 static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
36829 plugin_data *p = p_data;
36830 @@ -227,12 +225,12 @@
36832 * cache the last successfull translation from hostname (authority) to docroot
36833 * - this saves us a stat() call
36839 mod_simple_vhost_patch_connection(srv, con, p);
36841 - if (p->conf.docroot_cache_key->used &&
36843 + if (p->conf.docroot_cache_key->used &&
36844 con->uri.authority->used &&
36845 buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
36847 @@ -243,8 +241,8 @@
36848 if ((con->uri.authority->used == 0) ||
36849 build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
36850 /* not found, fallback the default-host */
36851 - if (build_doc_root(srv, con, p,
36853 + if (build_doc_root(srv, con, p,
36855 p->conf.default_host)) {
36856 return HANDLER_GO_ON;
36858 @@ -253,15 +251,15 @@
36860 buffer_copy_string_buffer(con->server_name, con->uri.authority);
36864 /* copy to cache */
36865 buffer_copy_string_buffer(p->conf.docroot_cache_key, con->uri.authority);
36866 buffer_copy_string_buffer(p->conf.docroot_cache_value, p->doc_root);
36867 buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);
36870 buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
36874 return HANDLER_GO_ON;
36877 @@ -269,13 +267,13 @@
36878 int mod_simple_vhost_plugin_init(plugin *p) {
36879 p->version = LIGHTTPD_VERSION_ID;
36880 p->name = buffer_init_string("simple_vhost");
36883 p->init = mod_simple_vhost_init;
36884 p->set_defaults = mod_simple_vhost_set_defaults;
36885 p->handle_docroot = mod_simple_vhost_docroot;
36886 p->cleanup = mod_simple_vhost_free;
36894 --- ../lighttpd-1.4.11/src/mod_skeleton.c 2005-10-02 18:30:51.000000000 +0300
36895 +++ lighttpd-1.4.12/src/mod_skeleton.c 2006-07-16 00:26:03.000000000 +0300
36896 @@ -14,13 +14,13 @@
36899 * this is a skeleton for a lighttpd plugin
36902 * just replaces every occurance of 'skeleton' by your plugin name
36908 * :%s/skeleton/myhandler/
36914 @@ -33,12 +33,12 @@
36923 plugin_config **config_storage;
36925 - plugin_config conf;
36927 + plugin_config conf;
36931 @@ -47,36 +47,36 @@
36933 static handler_ctx * handler_ctx_init() {
36934 handler_ctx * hctx;
36937 hctx = calloc(1, sizeof(*hctx));
36943 static void handler_ctx_free(handler_ctx *hctx) {
36949 /* init the plugin data */
36950 INIT_FUNC(mod_skeleton_init) {
36954 p = calloc(1, sizeof(*p));
36957 p->match_buf = buffer_init();
36963 /* detroy the plugin data */
36964 FREE_FUNC(mod_skeleton_free) {
36965 plugin_data *p = p_d;
36970 if (!p) return HANDLER_GO_ON;
36973 if (p->config_storage) {
36976 @@ -84,18 +84,18 @@
36977 plugin_config *s = p->config_storage[i];
36982 array_free(s->match);
36987 free(p->config_storage);
36991 buffer_free(p->match_buf);
36997 return HANDLER_GO_ON;
37000 @@ -104,91 +104,88 @@
37001 SETDEFAULTS_FUNC(mod_skeleton_set_defaults) {
37002 plugin_data *p = p_d;
37005 - config_values_t cv[] = {
37007 + config_values_t cv[] = {
37008 { "skeleton.array", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
37009 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37013 if (!p) return HANDLER_ERROR;
37016 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37019 for (i = 0; i < srv->config_context->used; i++) {
37023 s = calloc(1, sizeof(plugin_config));
37024 s->match = array_init();
37027 cv[0].destination = s->match;
37030 p->config_storage[i] = s;
37033 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37034 return HANDLER_ERROR;
37039 return HANDLER_GO_ON;
37042 -#define PATCH(x) \
37043 - p->conf.x = s->x;
37044 static int mod_skeleton_patch_connection(server *srv, connection *con, plugin_data *p) {
37046 plugin_config *s = p->config_storage[0];
37051 + PATCH_OPTION(match);
37053 /* skip the first, the global context */
37054 for (i = 1; i < srv->config_context->used; i++) {
37055 data_config *dc = (data_config *)srv->config_context->data[i];
37056 s = p->config_storage[i];
37059 /* condition didn't match */
37060 if (!config_check_cond(srv, con, dc)) continue;
37064 for (j = 0; j < dc->value->used; j++) {
37065 data_unset *du = dc->value->data[j];
37068 if (buffer_is_equal_string(du->key, CONST_STR_LEN("skeleton.array"))) {
37070 + PATCH_OPTION(match);
37080 URIHANDLER_FUNC(mod_skeleton_uri_handler) {
37081 plugin_data *p = p_d;
37088 if (con->uri.path->used == 0) return HANDLER_GO_ON;
37091 mod_skeleton_patch_connection(srv, con, p);
37093 s_len = con->uri.path->used - 1;
37096 for (k = 0; k < p->conf.match->used; k++) {
37097 data_string *ds = (data_string *)p->conf.match->data[k];
37098 int ct_len = ds->value->used - 1;
37101 if (ct_len > s_len) continue;
37102 if (ds->value->used == 0) continue;
37105 if (0 == strncmp(con->uri.path->ptr + s_len - ct_len, ds->value->ptr, ct_len)) {
37106 con->http_status = 403;
37109 return HANDLER_FINISHED;
37115 return HANDLER_GO_ON;
37117 @@ -198,13 +195,13 @@
37118 int mod_skeleton_plugin_init(plugin *p) {
37119 p->version = LIGHTTPD_VERSION_ID;
37120 p->name = buffer_init_string("skeleton");
37123 p->init = mod_skeleton_init;
37124 p->handle_uri_clean = mod_skeleton_uri_handler;
37125 p->set_defaults = mod_skeleton_set_defaults;
37126 p->cleanup = mod_skeleton_free;
37134 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.c 1970-01-01 03:00:00.000000000 +0300
37135 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.c 2006-07-16 00:26:04.000000000 +0300
37137 +#include <stdio.h>
37138 +#include <errno.h>
37139 +#include <fcntl.h>
37140 +#include <string.h>
37142 +#ifdef HAVE_CONFIG_H
37143 +#include "config.h"
37146 +#include "plugin.h"
37149 +#include "stat_cache.h"
37151 +#include "mod_sql_vhost_core.h"
37153 +#define plugin_data mod_sql_vhost_core_plugin_data
37154 +#define plugin_config mod_sql_vhost_core_plugin_config
37156 +/* init the plugin data */
37157 +INIT_FUNC(mod_sql_vhost_core_init) {
37160 + p = calloc(1, sizeof(*p));
37162 + p->docroot = buffer_init();
37163 + p->host = buffer_init();
37168 +/* cleanup the plugin data */
37169 +SERVER_FUNC(mod_sql_vhost_core_cleanup) {
37170 + plugin_data *p = p_d;
37174 + if (!p) return HANDLER_GO_ON;
37176 + if (p->config_storage) {
37178 + for (i = 0; i < srv->config_context->used; i++) {
37179 + plugin_config *s = p->config_storage[i];
37181 + if (!s) continue;
37183 + buffer_free(s->db);
37184 + buffer_free(s->user);
37185 + buffer_free(s->pass);
37186 + buffer_free(s->sock);
37187 + buffer_free(s->backend);
37191 + free(p->config_storage);
37193 + buffer_free(p->docroot);
37194 + buffer_free(p->host);
37198 + return HANDLER_GO_ON;
37201 +/* set configuration values */
37202 +SERVER_FUNC(mod_sql_vhost_core_set_defaults) {
37203 + plugin_data *p = p_d;
37207 + config_values_t cv[] = {
37208 + { "sql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 0 * e.g. vhost */
37209 + { "sql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 1 * lighty */
37210 + { "sql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 2 * secrect */
37211 + { "sql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 3 * /tmp/mysql.sock */
37212 + { "sql-vhost.select-vhost", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 4 * SELECT ... FROM hosts WHERE hostname = ? */
37213 + { "sql-vhost.hostname", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 5 * 127.0.0.1 */
37214 + { "sql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 6 * 3306 */
37215 + { "sql-vhost.backend", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 7 * mysql */
37217 + /* backward compat */
37218 + { "mysql-vhost.db", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 8 == 0 */
37219 + { "mysql-vhost.user", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 9 == 1 */
37220 + { "mysql-vhost.pass", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 10 == 2 */
37221 + { "mysql-vhost.sock", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 11 == 3 */
37222 + { "mysql-vhost.sql", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_SERVER }, /* 12 == 4 */
37223 + { "mysql-vhost.hostname", NULL, T_CONFIG_STRING,T_CONFIG_SCOPE_SERVER }, /* 13 == 5 */
37224 + { "mysql-vhost.port", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_SERVER }, /* 14 == 6 */
37226 + { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37229 + p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37231 + for (i = 0; i < srv->config_context->used; i++) {
37232 + plugin_config *s;
37234 + s = calloc(1, sizeof(plugin_config));
37235 + s->db = buffer_init();
37236 + s->user = buffer_init();
37237 + s->pass = buffer_init();
37238 + s->sock = buffer_init();
37239 + s->hostname = buffer_init();
37240 + s->backend = buffer_init();
37241 + s->port = 0; /* default port for mysql */
37242 + s->select_vhost = buffer_init();
37243 + s->backend_data = NULL;
37245 + cv[0].destination = s->db;
37246 + cv[1].destination = s->user;
37247 + cv[2].destination = s->pass;
37248 + cv[3].destination = s->sock;
37249 + cv[4].destination = s->select_vhost;
37250 + cv[5].destination = s->hostname;
37251 + cv[6].destination = &(s->port);
37252 + cv[7].destination = s->backend;
37254 + /* backend compat */
37255 + cv[8].destination = cv[0].destination;
37256 + cv[9].destination = cv[1].destination;
37257 + cv[10].destination = cv[2].destination;
37258 + cv[11].destination = cv[3].destination;
37259 + cv[12].destination = cv[4].destination;
37260 + cv[13].destination = cv[5].destination;
37261 + cv[14].destination = cv[6].destination;
37263 + p->config_storage[i] = s;
37265 + if (config_insert_values_global(srv,
37266 + ((data_config *)srv->config_context->data[i])->value,
37267 + cv)) return HANDLER_ERROR;
37269 + /* we only parse the config, the backend plugin will patch itself into the plugin-struct */
37272 + return HANDLER_GO_ON;
37275 +static int mod_sql_vhost_core_patch_connection(server *srv, connection *con, plugin_data *p) {
37277 + plugin_config *s = p->config_storage[0];
37279 + PATCH_OPTION(backend_data);
37280 + PATCH_OPTION(get_vhost);
37282 + /* skip the first, the global context */
37283 + for (i = 1; i < srv->config_context->used; i++) {
37284 + data_config *dc = (data_config *)srv->config_context->data[i];
37285 + s = p->config_storage[i];
37287 + /* condition didn't match */
37288 + if (!config_check_cond(srv, con, dc)) continue;
37290 + if (s->backend_data) {
37291 + PATCH_OPTION(backend_data);
37292 + PATCH_OPTION(get_vhost);
37299 +/* handle document root request */
37300 +CONNECTION_FUNC(mod_sql_vhost_core_handle_docroot) {
37301 + plugin_data *p = p_d;
37302 + stat_cache_entry *sce;
37304 + /* no host specified? */
37305 + if (!con->uri.authority->used) return HANDLER_GO_ON;
37307 + mod_sql_vhost_core_patch_connection(srv, con, p);
37309 + /* do we have backend ? */
37310 + if (!p->conf.get_vhost) return HANDLER_GO_ON;
37312 + /* ask the backend for the data */
37313 + if (0 != p->conf.get_vhost(srv, con, p->conf.backend_data, p->docroot, p->host)) {
37314 + return HANDLER_GO_ON;
37317 + if (HANDLER_ERROR == stat_cache_get_entry(srv, con, p->docroot, &sce)) {
37318 + log_error_write(srv, __FILE__, __LINE__, "sb", strerror(errno), p->docroot);
37319 + return HANDLER_GO_ON;
37321 + if (!S_ISDIR(sce->st.st_mode)) {
37322 + log_error_write(srv, __FILE__, __LINE__, "sb", "Not a directory", p->docroot);
37323 + return HANDLER_GO_ON;
37326 + buffer_copy_string_buffer(con->server_name, p->host);
37327 + buffer_copy_string_buffer(con->physical.doc_root, p->docroot);
37329 + return HANDLER_GO_ON;
37332 +/* this function is called at dlopen() time and inits the callbacks */
37333 +int mod_sql_vhost_core_plugin_init(plugin *p) {
37334 + p->version = LIGHTTPD_VERSION_ID;
37335 + p->name = buffer_init_string("mod_sql_vhost_core");
37337 + p->init = mod_sql_vhost_core_init;
37338 + p->cleanup = mod_sql_vhost_core_cleanup;
37340 + p->set_defaults = mod_sql_vhost_core_set_defaults;
37341 + p->handle_docroot = mod_sql_vhost_core_handle_docroot;
37346 --- ../lighttpd-1.4.11/src/mod_sql_vhost_core.h 1970-01-01 03:00:00.000000000 +0300
37347 +++ lighttpd-1.4.12/src/mod_sql_vhost_core.h 2006-07-16 00:26:04.000000000 +0300
37349 +#ifndef _MOD_SQL_VHOST_CORE_H_
37350 +#define _MOD_SQL_VHOST_CORE_H_
37352 +#include "buffer.h"
37353 +#include "plugin.h"
37355 +#define SQLVHOST_BACKEND_GETVHOST_PARAMS \
37356 + (server *srv, connection *con, void *p_d, buffer *docroot, buffer *host)
37358 +#define SQLVHOST_BACKEND_GETVHOST_RETVAL handler_t
37360 +#define SQLVHOST_BACKEND_GETVHOST(name) \
37361 + SQLVHOST_BACKEND_GETVHOST_RETVAL name SQLVHOST_BACKEND_GETVHOST_PARAMS
37363 +#define SQLVHOST_BACKEND_GETVHOST_PTR(name) \
37364 + SQLVHOST_BACKEND_GETVHOST_RETVAL (* name)SQLVHOST_BACKEND_GETVHOST_PARAMS
37372 + buffer *hostname;
37373 + unsigned short port;
37376 + void *backend_data;
37378 + buffer *select_vhost;
37380 + SQLVHOST_BACKEND_GETVHOST_PTR(get_vhost);
37381 +} mod_sql_vhost_core_plugin_config;
37383 +/* global plugin data */
37390 + mod_sql_vhost_core_plugin_config **config_storage;
37392 + mod_sql_vhost_core_plugin_config conf;
37393 +} mod_sql_vhost_core_plugin_data;
37398 --- ../lighttpd-1.4.11/src/mod_ssi.c 2006-03-04 17:09:48.000000000 +0200
37399 +++ lighttpd-1.4.12/src/mod_ssi.c 2006-07-16 00:26:04.000000000 +0300
37401 #include <string.h>
37404 -#include <unistd.h>
37409 #include "inet_ntop_cache.h"
37411 #include "sys-socket.h"
37412 +#include "sys-strings.h"
37413 +#include "sys-files.h"
37417 @@ -39,15 +40,15 @@
37418 /* init the plugin data */
37419 INIT_FUNC(mod_ssi_init) {
37423 p = calloc(1, sizeof(*p));
37426 p->timefmt = buffer_init();
37427 p->stat_fn = buffer_init();
37430 p->ssi_vars = array_init();
37431 p->ssi_cgi_env = array_init();
37437 @@ -55,21 +56,21 @@
37438 FREE_FUNC(mod_ssi_free) {
37439 plugin_data *p = p_d;
37443 if (!p) return HANDLER_GO_ON;
37446 if (p->config_storage) {
37448 for (i = 0; i < srv->config_context->used; i++) {
37449 plugin_config *s = p->config_storage[i];
37452 array_free(s->ssi_extension);
37457 free(p->config_storage);
37461 array_free(p->ssi_vars);
37462 array_free(p->ssi_cgi_env);
37466 buffer_free(p->timefmt);
37467 buffer_free(p->stat_fn);
37473 return HANDLER_GO_ON;
37476 @@ -92,36 +93,36 @@
37477 const char *errptr;
37481 - config_values_t cv[] = {
37483 + config_values_t cv[] = {
37484 { "ssi.extension", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
37485 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
37489 if (!p) return HANDLER_ERROR;
37492 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
37495 for (i = 0; i < srv->config_context->used; i++) {
37499 s = calloc(1, sizeof(plugin_config));
37500 s->ssi_extension = array_init();
37503 cv[0].destination = s->ssi_extension;
37506 p->config_storage[i] = s;
37509 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
37510 return HANDLER_ERROR;
37516 /* allow 2 params */
37517 if (NULL == (p->ssi_regex = pcre_compile("<!--#([a-z]+)\\s+(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?(?:([a-z]+)=\"(.*?)(?<!\\\\)\"\\s*)?-->", 0, &errptr, &erroff, NULL))) {
37518 log_error_write(srv, __FILE__, __LINE__, "sds",
37522 return HANDLER_ERROR;
37524 @@ -130,52 +131,52 @@
37525 "mod_ssi: pcre support is missing, please recompile with pcre support or remove mod_ssi from the list of modules");
37526 return HANDLER_ERROR;
37530 return HANDLER_GO_ON;
37533 int ssi_env_add(array *env, const char *key, const char *val) {
37537 if (NULL == (ds = (data_string *)array_get_unused_element(env, TYPE_STRING))) {
37538 ds = data_string_init();
37540 buffer_copy_string(ds->key, key);
37541 buffer_copy_string(ds->value, val);
37544 array_insert_unique(env, (data_unset *)ds);
37552 * the next two functions are take from fcgi.c
37557 static int ssi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
37561 for (i = 0; i < con->request.headers->used; i++) {
37565 ds = (data_string *)con->request.headers->data[i];
37568 if (ds->value->used && ds->key->used) {
37570 buffer_reset(srv->tmp_buf);
37573 /* don't forward the Authorization: Header */
37574 if (0 == strcasecmp(ds->key->ptr, "AUTHORIZATION")) {
37579 if (0 != strcasecmp(ds->key->ptr, "CONTENT-TYPE")) {
37580 buffer_copy_string(srv->tmp_buf, "HTTP_");
37581 srv->tmp_buf->used--;
37585 buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
37586 for (j = 0; j < ds->key->used - 1; j++) {
37588 @@ -189,33 +190,33 @@
37589 srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
37591 srv->tmp_buf->ptr[srv->tmp_buf->used] = '\0';
37594 ssi_env_add(p->ssi_cgi_env, srv->tmp_buf->ptr, ds->value->ptr);
37602 static int build_ssi_cgi_vars(server *srv, connection *con, plugin_data *p) {
37606 server_socket *srv_sock = con->srv_socket;
37610 char b2[INET6_ADDRSTRLEN + 1];
37613 #define CONST_STRING(x) \
37617 array_reset(p->ssi_cgi_env);
37620 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_SOFTWARE"), PACKAGE_NAME"/"PACKAGE_VERSION);
37621 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_NAME"),
37623 - inet_ntop(srv_sock->addr.plain.sa_family,
37624 - srv_sock->addr.plain.sa_family == AF_INET6 ?
37625 + inet_ntop(srv_sock->addr.plain.sa_family,
37626 + srv_sock->addr.plain.sa_family == AF_INET6 ?
37627 (const void *) &(srv_sock->addr.ipv6.sin6_addr) :
37628 (const void *) &(srv_sock->addr.ipv4.sin_addr),
37630 @@ -224,28 +225,28 @@
37633 ssi_env_add(p->ssi_cgi_env, CONST_STRING("GATEWAY_INTERFACE"), "CGI/1.1");
37639 ntohs(srv_sock->addr.plain.sa_family ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
37641 ntohs(srv_sock->addr.ipv4.sin_port)
37646 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PORT"), buf);
37649 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_ADDR"),
37650 inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
37653 if (con->authed_user->used) {
37654 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REMOTE_USER"),
37655 con->authed_user->ptr);
37659 if (con->request.content_length > 0) {
37660 /* CGI-SPEC 6.1.2 and FastCGI spec 6.3 */
37663 /* request.content_length < SSIZE_MAX, see request.c */
37664 ltostr(buf, con->request.content_length);
37665 ssi_env_add(p->ssi_cgi_env, CONST_STRING("CONTENT_LENGTH"), buf);
37666 @@ -271,30 +272,30 @@
37667 if (con->request.pathinfo->used) {
37668 ssi_env_add(p->ssi_cgi_env, CONST_STRING("PATH_INFO"), con->request.pathinfo->ptr);
37672 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SCRIPT_FILENAME"), con->physical.path->ptr);
37673 ssi_env_add(p->ssi_cgi_env, CONST_STRING("DOCUMENT_ROOT"), con->physical.doc_root->ptr);
37676 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_URI"), con->request.uri->ptr);
37677 ssi_env_add(p->ssi_cgi_env, CONST_STRING("QUERY_STRING"), con->uri.query->used ? con->uri.query->ptr : "");
37678 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REQUEST_METHOD"), get_http_method_name(con->request.http_method));
37679 ssi_env_add(p->ssi_cgi_env, CONST_STRING("REDIRECT_STATUS"), "200");
37680 ssi_env_add(p->ssi_cgi_env, CONST_STRING("SERVER_PROTOCOL"), get_http_version_name(con->request.http_version));
37683 ssi_env_add_request_headers(srv, con, p);
37689 -static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
37690 +static int process_ssi_stmt(server *srv, connection *con, plugin_data *p,
37691 const char **l, size_t n) {
37692 size_t i, ssicmd = 0;
37700 - enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
37701 + enum { SSI_UNSET, SSI_ECHO, SSI_FSIZE, SSI_INCLUDE, SSI_FLASTMOD,
37702 SSI_CONFIG, SSI_PRINTENV, SSI_SET, SSI_IF, SSI_ELIF,
37703 SSI_ELSE, SSI_ENDIF, SSI_EXEC } type;
37705 @@ -310,27 +311,27 @@
37706 { "endif", SSI_ENDIF },
37707 { "else", SSI_ELSE },
37708 { "exec", SSI_EXEC },
37711 { NULL, SSI_UNSET }
37715 for (i = 0; ssicmds[i].var; i++) {
37716 if (0 == strcmp(l[1], ssicmds[i].var)) {
37717 ssicmd = ssicmds[i].type;
37726 int var = 0, enc = 0;
37727 const char *var_val = NULL;
37728 stat_cache_entry *sce = NULL;
37734 - enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
37735 + enum { SSI_ECHO_UNSET, SSI_ECHO_DATE_GMT, SSI_ECHO_DATE_LOCAL, SSI_ECHO_DOCUMENT_NAME, SSI_ECHO_DOCUMENT_URI,
37736 SSI_ECHO_LAST_MODIFIED, SSI_ECHO_USER_NAME } type;
37738 { "DATE_GMT", SSI_ECHO_DATE_GMT },
37739 @@ -339,27 +340,27 @@
37740 { "DOCUMENT_URI", SSI_ECHO_DOCUMENT_URI },
37741 { "LAST_MODIFIED", SSI_ECHO_LAST_MODIFIED },
37742 { "USER_NAME", SSI_ECHO_USER_NAME },
37745 { NULL, SSI_ECHO_UNSET }
37752 enum { SSI_ENC_UNSET, SSI_ENC_URL, SSI_ENC_NONE, SSI_ENC_ENTITY } type;
37754 { "url", SSI_ENC_URL },
37755 { "none", SSI_ENC_NONE },
37756 { "entity", SSI_ENC_ENTITY },
37759 { NULL, SSI_ENC_UNSET }
37763 for (i = 2; i < n; i += 2) {
37764 if (0 == strcmp(l[i], "var")) {
37771 for (j = 0; echovars[j].var; j++) {
37772 if (0 == strcmp(l[i+1], echovars[j].var)) {
37773 var = echovars[j].type;
37774 @@ -368,7 +369,7 @@
37776 } else if (0 == strcmp(l[i], "encoding")) {
37780 for (j = 0; encvars[j].var; j++) {
37781 if (0 == strcmp(l[i+1], encvars[j].var)) {
37782 enc = encvars[j].type;
37783 @@ -377,26 +378,26 @@
37786 log_error_write(srv, __FILE__, __LINE__, "sss",
37787 - "ssi: unknow attribute for ",
37788 + "ssi: unknow attribute for ",
37794 if (p->if_is_false) break;
37798 log_error_write(srv, __FILE__, __LINE__, "sss",
37801 l[1], "var is missing");
37805 stat_cache_get_entry(srv, con, con->physical.path, &sce);
37809 case SSI_ECHO_USER_NAME: {
37813 b = chunkqueue_get_append_buffer(con->write_queue);
37815 if (NULL == (pw = getpwuid(sce->st.st_uid))) {
37816 @@ -411,7 +412,7 @@
37818 case SSI_ECHO_LAST_MODIFIED: {
37819 time_t t = sce->st.st_mtime;
37822 b = chunkqueue_get_append_buffer(con->write_queue);
37823 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
37824 buffer_copy_string(b, "(none)");
37825 @@ -422,7 +423,7 @@
37827 case SSI_ECHO_DATE_LOCAL: {
37828 time_t t = time(NULL);
37831 b = chunkqueue_get_append_buffer(con->write_queue);
37832 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, localtime(&t))) {
37833 buffer_copy_string(b, "(none)");
37834 @@ -433,7 +434,7 @@
37836 case SSI_ECHO_DATE_GMT: {
37837 time_t t = time(NULL);
37840 b = chunkqueue_get_append_buffer(con->write_queue);
37841 if (0 == strftime(buf, sizeof(buf), p->timefmt->ptr, gmtime(&t))) {
37842 buffer_copy_string(b, "(none)");
37843 @@ -444,7 +445,7 @@
37845 case SSI_ECHO_DOCUMENT_NAME: {
37849 b = chunkqueue_get_append_buffer(con->write_queue);
37850 if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
37851 buffer_copy_string_buffer(b, con->physical.path);
37852 @@ -461,15 +462,15 @@
37855 /* check if it is a cgi-var */
37858 b = chunkqueue_get_append_buffer(con->write_queue);
37861 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, var_val))) {
37862 buffer_copy_string_buffer(b, ds->value);
37864 buffer_copy_string(b, "(none)");
37871 @@ -481,7 +482,7 @@
37872 const char * file_path = NULL, *virt_path = NULL;
37877 for (i = 2; i < n; i += 2) {
37878 if (0 == strcmp(l[i], "file")) {
37879 file_path = l[i+1];
37880 @@ -489,28 +490,28 @@
37881 virt_path = l[i+1];
37883 log_error_write(srv, __FILE__, __LINE__, "sss",
37884 - "ssi: unknow attribute for ",
37885 + "ssi: unknow attribute for ",
37891 if (!file_path && !virt_path) {
37892 log_error_write(srv, __FILE__, __LINE__, "sss",
37895 l[1], "file or virtual are missing");
37900 if (file_path && virt_path) {
37901 log_error_write(srv, __FILE__, __LINE__, "sss",
37904 l[1], "only one of file and virtual is allowed here");
37911 if (p->if_is_false) break;
37915 /* current doc-root */
37916 if (NULL == (sl = strrchr(con->physical.path->ptr, '/'))) {
37917 @@ -519,46 +520,46 @@
37918 buffer_copy_string_len(p->stat_fn, con->physical.path->ptr, sl - con->physical.path->ptr + 1);
37921 - buffer_copy_string(srv->tmp_buf, file_path);
37922 + buffer_copy_string(srv->tmp_buf, file_path);
37923 buffer_urldecode_path(srv->tmp_buf);
37924 - buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
37925 - buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
37926 + buffer_path_simplify(srv->tmp_buf, srv->tmp_buf);
37927 + buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
37932 if (virt_path[0] == '/') {
37933 buffer_copy_string(p->stat_fn, virt_path);
37935 /* there is always a / */
37936 sl = strrchr(con->uri.path->ptr, '/');
37939 buffer_copy_string_len(p->stat_fn, con->uri.path->ptr, sl - con->uri.path->ptr + 1);
37940 buffer_append_string(p->stat_fn, virt_path);
37944 buffer_urldecode_path(p->stat_fn);
37945 buffer_path_simplify(srv->tmp_buf, p->stat_fn);
37948 /* we have an uri */
37951 buffer_copy_string_buffer(p->stat_fn, con->physical.doc_root);
37952 buffer_append_string_buffer(p->stat_fn, srv->tmp_buf);
37956 if (0 == stat(p->stat_fn->ptr, &st)) {
37957 time_t t = st.st_mtime;
37962 b = chunkqueue_get_append_buffer(con->write_queue);
37965 const char *abr[] = { " B", " kB", " MB", " GB", " TB", NULL };
37968 off_t s = st.st_size;
37971 for (j = 0; s > 1024 && abr[j+1]; s /= 1024, j++);
37974 buffer_copy_off_t(b, s);
37975 buffer_append_string(b, abr[j]);
37977 @@ -579,7 +580,7 @@
37980 log_error_write(srv, __FILE__, __LINE__, "sbs",
37981 - "ssi: stating failed ",
37982 + "ssi: stating failed ",
37983 p->stat_fn, strerror(errno));
37986 @@ -593,33 +594,33 @@
37989 log_error_write(srv, __FILE__, __LINE__, "sss",
37990 - "ssi: unknow attribute for ",
37991 + "ssi: unknow attribute for ",
37997 if (p->if_is_false) break;
38004 if (NULL == (ds = (data_string *)array_get_unused_element(p->ssi_vars, TYPE_STRING))) {
38005 ds = data_string_init();
38007 buffer_copy_string(ds->key, key);
38008 buffer_copy_string(ds->value, val);
38011 array_insert_unique(p->ssi_vars, (data_unset *)ds);
38013 log_error_write(srv, __FILE__, __LINE__, "sss",
38014 - "ssi: var and value have to be set in",
38015 + "ssi: var and value have to be set in",
38022 if (p->if_is_false) break;
38025 for (i = 2; i < n; i += 2) {
38026 if (0 == strcmp(l[i], "timefmt")) {
38027 buffer_copy_string(p->timefmt, l[i+1]);
38028 @@ -632,63 +633,65 @@
38029 log_error_write(srv, __FILE__, __LINE__, "sssss",
38030 "ssi: unknow value for attribute '",
38037 log_error_write(srv, __FILE__, __LINE__, "sss",
38038 - "ssi: unknow attribute for ",
38039 + "ssi: unknow attribute for ",
38045 if (p->if_is_false) break;
38048 b = chunkqueue_get_append_buffer(con->write_queue);
38049 buffer_copy_string(b, "<pre>");
38050 for (i = 0; i < p->ssi_vars->used; i++) {
38051 data_string *ds = (data_string *)p->ssi_vars->data[p->ssi_vars->sorted[i]];
38054 buffer_append_string_buffer(b, ds->key);
38055 buffer_append_string(b, ": ");
38056 buffer_append_string_buffer(b, ds->value);
38057 buffer_append_string(b, "<br />");
38061 buffer_append_string(b, "</pre>");
38068 const char *cmd = NULL;
38070 int from_exec_fds[2];
38073 for (i = 2; i < n; i += 2) {
38074 if (0 == strcmp(l[i], "cmd")) {
38077 log_error_write(srv, __FILE__, __LINE__, "sss",
38078 - "ssi: unknow attribute for ",
38079 + "ssi: unknow attribute for ",
38085 if (p->if_is_false) break;
38088 /* create a return pipe and send output to the html-page
38090 - * as exec is assumed evil it is implemented synchronously
38092 + * as exec is assumed evil it is implemented synchronously
38099 if (pipe(from_exec_fds)) {
38100 - log_error_write(srv, __FILE__, __LINE__, "ss",
38101 + log_error_write(srv, __FILE__, __LINE__, "ss",
38102 "pipe failed: ", strerror(errno));
38108 switch (pid = fork()) {
38110 @@ -698,14 +701,14 @@
38111 close(from_exec_fds[1]);
38113 close(from_exec_fds[0]);
38117 close(STDIN_FILENO);
38120 execl("/bin/sh", "sh", "-c", cmd, NULL);
38123 log_error_write(srv, __FILE__, __LINE__, "sss", "spawing exec failed:", strerror(errno), cmd);
38129 @@ -718,9 +721,9 @@
38135 close(from_exec_fds[1]);
38138 /* wait for the client to end */
38139 if (-1 == waitpid(pid, &status, 0)) {
38140 log_error_write(srv, __FILE__, __LINE__, "ss", "waitpid failed:", strerror(errno));
38141 @@ -730,7 +733,7 @@
38144 if (ioctl(from_exec_fds[0], FIONREAD, &toread)) {
38145 - log_error_write(srv, __FILE__, __LINE__, "s",
38146 + log_error_write(srv, __FILE__, __LINE__, "s",
38147 "unexpected end-of-file (perhaps the ssi-exec process died)");
38150 @@ -738,10 +741,10 @@
38152 b = chunkqueue_get_append_buffer(con->write_queue);
38154 - buffer_prepare_copy(b, toread + 1);
38155 + buffer_prepare_copy(b, toread + 1);
38157 if ((r = read(from_exec_fds[0], b->ptr, b->size - 1)) < 0) {
38158 - /* read failed */
38159 + /* read failed */
38163 @@ -755,59 +758,58 @@
38164 log_error_write(srv, __FILE__, __LINE__, "s", "process exited abnormally");
38166 close(from_exec_fds[0]);
38181 const char *expr = NULL;
38184 for (i = 2; i < n; i += 2) {
38185 if (0 == strcmp(l[i], "expr")) {
38188 log_error_write(srv, __FILE__, __LINE__, "sss",
38189 - "ssi: unknow attribute for ",
38190 + "ssi: unknow attribute for ",
38197 log_error_write(srv, __FILE__, __LINE__, "sss",
38200 l[1], "expr missing");
38205 if ((!p->if_is_false) &&
38206 - ((p->if_is_false_level == 0) ||
38207 + ((p->if_is_false_level == 0) ||
38208 (p->if_level < p->if_is_false_level))) {
38209 switch (ssi_eval_expr(srv, con, p, expr)) {
38212 - p->if_is_false = 1;
38214 + p->if_is_false = 1;
38215 p->if_is_false_level = p->if_level;
38218 - p->if_is_false = 0;
38220 + p->if_is_false = 0;
38235 if (p->if_is_false) {
38236 if ((p->if_level == p->if_is_false_level) &&
38237 (p->if_is_false_endif == 0)) {
38238 @@ -815,11 +817,11 @@
38241 p->if_is_false = 1;
38244 p->if_is_false_level = p->if_level;
38251 const char *expr = NULL;
38252 @@ -828,52 +830,52 @@
38255 log_error_write(srv, __FILE__, __LINE__, "sss",
38256 - "ssi: unknow attribute for ",
38257 + "ssi: unknow attribute for ",
38264 log_error_write(srv, __FILE__, __LINE__, "sss",
38267 l[1], "expr missing");
38275 if (p->if_level == p->if_is_false_level) {
38276 if ((p->if_is_false) &&
38277 (p->if_is_false_endif == 0)) {
38278 switch (ssi_eval_expr(srv, con, p, expr)) {
38281 - p->if_is_false = 1;
38283 + p->if_is_false = 1;
38284 p->if_is_false_level = p->if_level;
38287 - p->if_is_false = 0;
38289 + p->if_is_false = 0;
38293 - p->if_is_false = 1;
38294 + p->if_is_false = 1;
38295 p->if_is_false_level = p->if_level;
38296 p->if_is_false_endif = 1;
38310 if (p->if_level == p->if_is_false_level) {
38311 p->if_is_false = 0;
38312 p->if_is_false_endif = 0;
38318 log_error_write(srv, __FILE__, __LINE__, "ss",
38319 @@ -881,41 +883,41 @@
38330 static int mod_ssi_handle_request(server *srv, connection *con, plugin_data *p) {
38341 /* get a stream to the file */
38344 array_reset(p->ssi_vars);
38345 array_reset(p->ssi_cgi_env);
38346 buffer_copy_string(p->timefmt, "%a, %d %b %Y %H:%M:%S %Z");
38348 build_ssi_cgi_vars(srv, con, p);
38349 p->if_is_false = 0;
38352 if (-1 == stream_open(&s, con->physical.path)) {
38353 log_error_write(srv, __FILE__, __LINE__, "sb",
38354 "stream-open: ", con->physical.path);
38362 - * <!--#element attribute=value attribute=value ... -->
38364 + * <!--#element attribute=value attribute=value ... -->
38367 - * errmsg -- missing
38368 + * errmsg -- missing
38372 @@ -937,13 +939,13 @@
38389 @@ -951,118 +953,115 @@
38401 - * The current date in Greenwich Mean Time.
38403 - * The current date in the local time zone.
38405 - * The filename (excluding directories) of the document requested by the user.
38407 - * 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.
38409 - * The last modification date of the document requested by the user.
38412 + * The current date in Greenwich Mean Time.
38414 + * The current date in the local time zone.
38416 + * The filename (excluding directories) of the document requested by the user.
38418 + * 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.
38420 + * The last modification date of the document requested by the user.
38422 * Contains the owner of the file which included it.
38426 -#ifdef HAVE_PCRE_H
38427 +#ifdef HAVE_PCRE_H
38428 for (i = 0; (n = pcre_exec(p->ssi_regex, NULL, s.start, s.size, i, 0, ovec, N * 3)) > 0; i = ovec[1]) {
38430 /* take everything from last offset to current match pos */
38433 if (!p->if_is_false) chunkqueue_append_file(con->write_queue, con->physical.path, i, ovec[0] - i);
38436 pcre_get_substring_list(s.start, ovec, n, &l);
38437 process_ssi_stmt(srv, con, p, l, n);
38438 pcre_free_substring_list(l);
38443 case PCRE_ERROR_NOMATCH:
38444 /* copy everything/the rest */
38445 chunkqueue_append_file(con->write_queue, con->physical.path, i, s.size - i);
38450 log_error_write(srv, __FILE__, __LINE__, "sd",
38451 "execution error while matching: ", n);
38463 con->file_started = 1;
38464 con->file_finished = 1;
38467 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
38470 /* reset physical.path */
38471 buffer_reset(con->physical.path);
38477 -#define PATCH(x) \
38478 - p->conf.x = s->x;
38479 static int mod_ssi_patch_connection(server *srv, connection *con, plugin_data *p) {
38481 plugin_config *s = p->config_storage[0];
38483 - PATCH(ssi_extension);
38486 + PATCH_OPTION(ssi_extension);
38488 /* skip the first, the global context */
38489 for (i = 1; i < srv->config_context->used; i++) {
38490 data_config *dc = (data_config *)srv->config_context->data[i];
38491 s = p->config_storage[i];
38494 /* condition didn't match */
38495 if (!config_check_cond(srv, con, dc)) continue;
38499 for (j = 0; j < dc->value->used; j++) {
38500 data_unset *du = dc->value->data[j];
38503 if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssi.extension"))) {
38504 - PATCH(ssi_extension);
38505 + PATCH_OPTION(ssi_extension);
38515 URIHANDLER_FUNC(mod_ssi_physical_path) {
38516 plugin_data *p = p_d;
38520 if (con->physical.path->used == 0) return HANDLER_GO_ON;
38523 mod_ssi_patch_connection(srv, con, p);
38526 for (k = 0; k < p->conf.ssi_extension->used; k++) {
38527 data_string *ds = (data_string *)p->conf.ssi_extension->data[k];
38530 if (ds->value->used == 0) continue;
38533 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
38534 /* handle ssi-request */
38537 if (mod_ssi_handle_request(srv, con, p)) {
38539 con->http_status = 500;
38543 return HANDLER_FINISHED;
38549 return HANDLER_GO_ON;
38551 @@ -1072,13 +1071,13 @@
38552 int mod_ssi_plugin_init(plugin *p) {
38553 p->version = LIGHTTPD_VERSION_ID;
38554 p->name = buffer_init_string("ssi");
38557 p->init = mod_ssi_init;
38558 p->handle_subrequest_start = mod_ssi_physical_path;
38559 p->set_defaults = mod_ssi_set_defaults;
38560 p->cleanup = mod_ssi_free;
38568 --- ../lighttpd-1.4.11/src/mod_ssi.h 2005-08-11 01:26:39.000000000 +0300
38569 +++ lighttpd-1.4.12/src/mod_ssi.h 2006-07-16 00:26:04.000000000 +0300
38570 @@ -19,23 +19,23 @@
38575 -#ifdef HAVE_PCRE_H
38577 +#ifdef HAVE_PCRE_H
38589 array *ssi_cgi_env;
38592 int if_level, if_is_false_level, if_is_false, if_is_false_endif;
38595 plugin_config **config_storage;
38597 - plugin_config conf;
38599 + plugin_config conf;
38602 int ssi_eval_expr(server *srv, connection *con, plugin_data *p, const char *expr);
38603 --- ../lighttpd-1.4.11/src/mod_ssi_expr.c 2005-08-11 01:26:48.000000000 +0300
38604 +++ lighttpd-1.4.12/src/mod_ssi_expr.c 2006-07-16 00:26:04.000000000 +0300
38617 @@ -21,15 +21,15 @@
38619 ssi_val_t *ssi_val_init() {
38623 s = calloc(1, sizeof(*s));
38629 void ssi_val_free(ssi_val_t *s) {
38630 if (s->str) buffer_free(s->str);
38636 @@ -45,175 +45,175 @@
38637 ssi_tokenizer_t *t, int *token_id, buffer *token) {
38644 for (tid = 0; tid == 0 && t->offset < t->size && t->input[t->offset] ; ) {
38645 char c = t->input[t->offset];
38659 buffer_copy_string(token, "(=)");
38664 if (t->input[t->offset + 1] == '=') {
38672 buffer_copy_string(token, "(>=)");
38681 buffer_copy_string(token, "(>)");
38687 if (t->input[t->offset + 1] == '=') {
38695 buffer_copy_string(token, "(<=)");
38704 buffer_copy_string(token, "(<)");
38712 if (t->input[t->offset + 1] == '=') {
38720 buffer_copy_string(token, "(!=)");
38729 buffer_copy_string(token, "(!)");
38735 if (t->input[t->offset + 1] == '&') {
38743 buffer_copy_string(token, "(&&)");
38745 - log_error_write(srv, __FILE__, __LINE__, "sds",
38746 - "pos:", t->line_pos,
38747 + log_error_write(srv, __FILE__, __LINE__, "sds",
38748 + "pos:", t->line_pos,
38749 "missing second &");
38756 if (t->input[t->offset + 1] == '|') {
38764 buffer_copy_string(token, "(||)");
38766 - log_error_write(srv, __FILE__, __LINE__, "sds",
38767 - "pos:", t->line_pos,
38768 + log_error_write(srv, __FILE__, __LINE__, "sds",
38769 + "pos:", t->line_pos,
38770 "missing second |");
38784 /* search for the terminating " */
38785 for (i = 1; t->input[t->offset + i] && t->input[t->offset + i] != '\''; i++);
38788 if (t->input[t->offset + i]) {
38792 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
38795 t->offset += i + 1;
38796 t->line_pos += i + 1;
38800 - log_error_write(srv, __FILE__, __LINE__, "sds",
38801 - "pos:", t->line_pos,
38803 + log_error_write(srv, __FILE__, __LINE__, "sds",
38804 + "pos:", t->line_pos,
38805 "missing closing quote");
38821 buffer_copy_string(token, "(");
38831 buffer_copy_string(token, ")");
38834 if (t->input[t->offset + 1] == '{') {
38835 for (i = 2; t->input[t->offset + i] && t->input[t->offset + i] != '}'; i++);
38838 if (t->input[t->offset + i] != '}') {
38839 - log_error_write(srv, __FILE__, __LINE__, "sds",
38840 - "pos:", t->line_pos,
38841 + log_error_write(srv, __FILE__, __LINE__, "sds",
38842 + "pos:", t->line_pos,
38843 "missing closing quote");
38850 buffer_copy_string_len(token, t->input + t->offset + 2, i-3);
38852 for (i = 1; isalpha(t->input[t->offset + i]) || t->input[t->offset + i] == '_'; i++);
38855 buffer_copy_string_len(token, t->input + t->offset + 1, i-1);
38862 if (NULL != (ds = (data_string *)array_get_element(p->ssi_cgi_env, token->ptr))) {
38863 buffer_copy_string_buffer(token, ds->value);
38864 } else if (NULL != (ds = (data_string *)array_get_element(p->ssi_vars, token->ptr))) {
38865 @@ -221,16 +221,16 @@
38867 buffer_copy_string(token, "");
38877 for (i = 0; isgraph(t->input[t->offset + i]); i++) {
38878 char d = t->input[t->offset + i];
38885 @@ -244,25 +244,25 @@
38894 buffer_copy_string_len(token, t->input + t->offset, i);
38911 } else if (t->offset < t->size) {
38912 - log_error_write(srv, __FILE__, __LINE__, "sds",
38913 - "pos:", t->line_pos,
38914 + log_error_write(srv, __FILE__, __LINE__, "sds",
38915 + "pos:", t->line_pos,
38919 @@ -275,50 +275,50 @@
38927 t.size = strlen(expr);
38940 /* default context */
38943 pParser = ssiexprparserAlloc( malloc );
38944 token = buffer_init();
38945 while((1 == (ret = ssi_expr_tokenizer(srv, con, p, &t, &token_id, token))) && context.ok) {
38946 ssiexprparser(pParser, token_id, token, &context);
38949 token = buffer_init();
38951 ssiexprparser(pParser, 0, token, &context);
38952 ssiexprparserFree(pParser, free );
38955 buffer_free(token);
38959 - log_error_write(srv, __FILE__, __LINE__, "s",
38960 + log_error_write(srv, __FILE__, __LINE__, "s",
38961 "expr parser failed");
38966 if (context.ok == 0) {
38967 - log_error_write(srv, __FILE__, __LINE__, "sds",
38968 - "pos:", t.line_pos,
38969 + log_error_write(srv, __FILE__, __LINE__, "sds",
38970 + "pos:", t.line_pos,
38971 "parser failed somehow near here");
38975 - log_error_write(srv, __FILE__, __LINE__, "ssd",
38976 + log_error_write(srv, __FILE__, __LINE__, "ssd",
38982 return context.val.bo;
38984 --- ../lighttpd-1.4.11/src/mod_ssi_expr.h 2005-08-11 01:26:48.000000000 +0300
38985 +++ lighttpd-1.4.12/src/mod_ssi_expr.h 2006-07-16 00:26:04.000000000 +0300
38989 enum { SSI_TYPE_UNSET, SSI_TYPE_BOOL, SSI_TYPE_STRING } type;
39006 --- ../lighttpd-1.4.11/src/mod_ssi_exprparser.c 2005-10-03 00:40:25.000000000 +0300
39007 +++ lighttpd-1.4.12/src/mod_ssi_exprparser.c 2006-07-17 22:02:23.000000000 +0300
39008 @@ -18,10 +18,10 @@
39009 /* Next is all token values, in a form suitable for use by makeheaders.
39010 ** This section will be null unless lemon is run with the -m switch.
39014 ** These constants (all generated automatically by the parser generator)
39015 ** specify the various kinds of tokens (terminals) that the parser
39019 ** Each symbol here is a terminal symbol in the grammar.
39022 ** and nonterminals. "int" is used otherwise.
39023 ** YYNOCODE is a number of type YYCODETYPE which corresponds
39024 ** to no legal terminal or nonterminal number. This
39025 -** number is used to fill in empty slots of the hash
39026 +** number is used to fill in empty slots of the hash
39028 ** YYFALLBACK If defined, this indicates that one or more tokens
39029 ** have fall-back values which should be used if the
39031 ** and nonterminal numbers. "unsigned char" is
39032 ** used if there are fewer than 250 rules and
39033 ** states combined. "int" is used otherwise.
39034 -** ssiexprparserTOKENTYPE is the data type used for minor tokens given
39035 +** ssiexprparserTOKENTYPE is the data type used for minor tokens given
39036 ** directly to the parser from the tokenizer.
39037 ** YYMINORTYPE is the data type used for all minor tokens.
39038 ** This is typically a union of many types, one of
39040 /* Next are that tables used to determine what action to take based on the
39041 ** current state and lookahead token. These tables are used to implement
39042 ** functions that take a state number and lookahead value and return an
39043 -** action integer.
39044 +** action integer.
39046 ** Suppose the action integer is N. Then the action is determined as
39048 @@ -116,7 +116,7 @@
39049 ** If the index value yy_shift_ofst[S]+X is out of range or if the value
39050 ** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S]
39051 ** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table
39052 -** and that yy_default[S] should be used instead.
39053 +** and that yy_default[S] should be used instead.
39055 ** The formula above is for computing the action when the lookahead is
39056 ** a terminal symbol. If the lookahead is a non-terminal (as occurs after
39057 @@ -168,7 +168,7 @@
39059 /* The next table maps tokens into fallback tokens. If a construct
39060 ** like the following:
39063 ** %fallback ID X Y Z.
39065 ** appears in the grammer, then ID becomes a fallback token for X, Y,
39066 @@ -219,10 +219,10 @@
39067 #endif /* NDEBUG */
39072 ** Turn parser tracing on by giving a stream to which to write the trace
39073 ** and a prompt to preface each trace message. Tracing is turned off
39074 -** by making either argument NULL
39075 +** by making either argument NULL
39079 @@ -247,7 +247,7 @@
39081 /* For tracing shifts, the names of all terminals and nonterminals
39082 ** are required. The following table supplies these names */
39083 -static const char *yyTokenName[] = {
39084 +static const char *yyTokenName[] = {
39085 "$", "AND", "OR", "EQ",
39086 "NE", "GT", "GE", "LT",
39087 "LE", "NOT", "LPARAN", "RPARAN",
39088 @@ -295,7 +295,7 @@
39094 ** This function allocates a new parser.
39095 ** The only argument is a pointer to a function which works like
39097 @@ -326,7 +326,7 @@
39098 /* Here is inserted the actions which take place when a
39099 ** terminal or non-terminal is destroyed. This can happen
39100 ** when the symbol is popped from the stack during a
39101 - ** reduce or during error processing or when a parser is
39102 + ** reduce or during error processing or when a parser is
39103 ** being destroyed before it is finished parsing.
39105 ** Note: during a reduce, the only symbols destroyed are those
39106 @@ -379,7 +379,7 @@
39112 ** Deallocate and destroy a parser. Destructors are all called for
39113 ** all stack elements before shutting the parser down.
39115 @@ -415,7 +415,7 @@
39118 int stateno = pParser->yystack[pParser->yyidx].stateno;
39121 /* if( pParser->yyidx<0 ) return YY_NO_ACTION; */
39122 i = yy_shift_ofst[stateno];
39123 if( i==YY_SHIFT_USE_DFLT ){
39124 @@ -459,7 +459,7 @@
39127 int stateno = pParser->yystack[pParser->yyidx].stateno;
39130 i = yy_reduce_ofst[stateno];
39131 if( i==YY_REDUCE_USE_DFLT ){
39132 return yy_default[stateno];
39133 @@ -559,7 +559,7 @@
39134 ssiexprparserARG_FETCH;
39135 yymsp = &yypParser->yystack[yypParser->yyidx];
39137 - if( yyTraceFILE && yyruleno>=0
39138 + if( yyTraceFILE && yyruleno>=0
39139 && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
39140 fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
39141 yyRuleName[yyruleno]);
39142 @@ -872,7 +872,7 @@
39143 #ifdef YYERRORSYMBOL
39144 /* A syntax error has occurred.
39145 ** The response to an error depends upon whether or not the
39146 - ** grammar defines an error token "ERROR".
39147 + ** grammar defines an error token "ERROR".
39149 ** This is what we do if the grammar does define ERROR:
39151 --- ../lighttpd-1.4.11/src/mod_staticfile.c 2006-02-15 14:31:14.000000000 +0200
39152 +++ lighttpd-1.4.12/src/mod_staticfile.c 2006-07-16 00:26:03.000000000 +0300
39154 #include "http_chunk.h"
39155 #include "response.h"
39157 +#include "sys-files.h"
39158 +#include "sys-strings.h"
39160 * this is a staticfile for a lighttpd plugin
39166 @@ -29,48 +31,48 @@
39175 plugin_config **config_storage;
39177 - plugin_config conf;
39179 + plugin_config conf;
39182 /* init the plugin data */
39183 INIT_FUNC(mod_staticfile_init) {
39187 p = calloc(1, sizeof(*p));
39190 p->range_buf = buffer_init();
39196 -/* detroy the plugin data */
39197 +/* destroy the plugin data */
39198 FREE_FUNC(mod_staticfile_free) {
39199 plugin_data *p = p_d;
39204 if (!p) return HANDLER_GO_ON;
39207 if (p->config_storage) {
39209 for (i = 0; i < srv->config_context->used; i++) {
39210 plugin_config *s = p->config_storage[i];
39213 array_free(s->exclude_ext);
39218 free(p->config_storage);
39220 buffer_free(p->range_buf);
39226 return HANDLER_GO_ON;
39229 @@ -79,63 +81,60 @@
39230 SETDEFAULTS_FUNC(mod_staticfile_set_defaults) {
39231 plugin_data *p = p_d;
39234 - config_values_t cv[] = {
39236 + config_values_t cv[] = {
39237 { "static-file.exclude-extensions", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
39238 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39242 if (!p) return HANDLER_ERROR;
39245 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39248 for (i = 0; i < srv->config_context->used; i++) {
39252 s = calloc(1, sizeof(plugin_config));
39253 s->exclude_ext = array_init();
39256 cv[0].destination = s->exclude_ext;
39259 p->config_storage[i] = s;
39262 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39263 return HANDLER_ERROR;
39268 return HANDLER_GO_ON;
39271 -#define PATCH(x) \
39272 - p->conf.x = s->x;
39273 static int mod_staticfile_patch_connection(server *srv, connection *con, plugin_data *p) {
39275 plugin_config *s = p->config_storage[0];
39277 - PATCH(exclude_ext);
39280 + PATCH_OPTION(exclude_ext);
39282 /* skip the first, the global context */
39283 for (i = 1; i < srv->config_context->used; i++) {
39284 data_config *dc = (data_config *)srv->config_context->data[i];
39285 s = p->config_storage[i];
39288 /* condition didn't match */
39289 if (!config_check_cond(srv, con, dc)) continue;
39293 for (j = 0; j < dc->value->used; j++) {
39294 data_unset *du = dc->value->data[j];
39297 if (buffer_is_equal_string(du->key, CONST_STR_LEN("static-file.exclude-extensions"))) {
39298 - PATCH(exclude_ext);
39299 + PATCH_OPTION(exclude_ext);
39309 static int http_response_parse_range(server *srv, connection *con, plugin_data *p) {
39311 @@ -146,69 +145,69 @@
39313 stat_cache_entry *sce = NULL;
39314 buffer *content_type = NULL;
39317 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39323 end = sce->st.st_size - 1;
39326 con->response.content_length = 0;
39329 if (NULL != (ds = (data_string *)array_get_element(con->response.headers, "Content-Type"))) {
39330 content_type = ds->value;
39334 for (s = con->request.http_range, error = 0;
39335 !error && *s && NULL != (minus = strchr(s, '-')); ) {
39344 le = strtoll(s, &err, 10);
39348 /* RFC 2616 - 14.35.1 */
39351 con->http_status = 416;
39353 } else if (*err == '\0') {
39358 end = sce->st.st_size - 1;
39359 start = sce->st.st_size + le;
39360 } else if (*err == ',') {
39365 end = sce->st.st_size - 1;
39366 start = sce->st.st_size + le;
39372 } else if (*(minus+1) == '\0' || *(minus+1) == ',') {
39376 la = strtoll(s, &err, 10);
39379 if (err == minus) {
39383 if (*(err + 1) == '\0') {
39387 end = sce->st.st_size - 1;
39391 } else if (*(err + 1) == ',') {
39396 end = sce->st.st_size - 1;
39399 @@ -220,64 +219,64 @@
39402 /* <start>-<stop> */
39405 la = strtoll(s, &err, 10);
39408 if (err == minus) {
39409 le = strtoll(minus+1, &err, 10);
39412 /* RFC 2616 - 14.35.1 */
39418 if (*err == '\0') {
39425 } else if (*err == ',') {
39448 if (start < 0) start = 0;
39451 /* RFC 2616 - 14.35.1 */
39452 if (end > sce->st.st_size - 1) end = sce->st.st_size - 1;
39455 if (start > sce->st.st_size - 1) {
39459 con->http_status = 416;
39466 /* write boundary-header */
39470 b = chunkqueue_get_append_buffer(con->write_queue);
39473 buffer_copy_string(b, "\r\n--");
39474 buffer_append_string(b, boundary);
39477 /* write Content-Range */
39478 buffer_append_string(b, "\r\nContent-Range: bytes ");
39479 buffer_append_off_t(b, start);
39480 @@ -285,54 +284,54 @@
39481 buffer_append_off_t(b, end);
39482 buffer_append_string(b, "/");
39483 buffer_append_off_t(b, sce->st.st_size);
39486 buffer_append_string(b, "\r\nContent-Type: ");
39487 buffer_append_string_buffer(b, content_type);
39490 /* write END-OF-HEADER */
39491 buffer_append_string(b, "\r\n\r\n");
39494 con->response.content_length += b->used - 1;
39500 chunkqueue_append_file(con->write_queue, con->physical.path, start, end - start + 1);
39501 con->response.content_length += end - start + 1;
39506 /* something went wrong */
39507 if (error) return -1;
39511 /* add boundary end */
39515 b = chunkqueue_get_append_buffer(con->write_queue);
39518 buffer_copy_string_len(b, "\r\n--", 4);
39519 buffer_append_string(b, boundary);
39520 buffer_append_string_len(b, "--\r\n", 4);
39523 con->response.content_length += b->used - 1;
39526 /* set header-fields */
39529 buffer_copy_string(p->range_buf, "multipart/byteranges; boundary=");
39530 buffer_append_string(p->range_buf, boundary);
39533 /* overwrite content-type */
39534 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(p->range_buf));
39536 /* add Content-Range-header */
39539 buffer_copy_string(p->range_buf, "bytes ");
39540 buffer_append_off_t(p->range_buf, start);
39541 buffer_append_string(p->range_buf, "-");
39542 buffer_append_off_t(p->range_buf, end);
39543 buffer_append_string(p->range_buf, "/");
39544 buffer_append_off_t(p->range_buf, sce->st.st_size);
39547 response_header_insert(srv, con, CONST_STR_LEN("Content-Range"), CONST_BUF_LEN(p->range_buf));
39550 @@ -347,12 +346,12 @@
39551 stat_cache_entry *sce = NULL;
39556 /* someone else has done a decision for us */
39557 if (con->http_status != 0) return HANDLER_GO_ON;
39558 if (con->uri.path->used == 0) return HANDLER_GO_ON;
39559 if (con->physical.path->used == 0) return HANDLER_GO_ON;
39562 /* someone else has handled this request */
39563 if (con->mode != DIRECT) return HANDLER_GO_ON;
39565 @@ -365,52 +364,52 @@
39567 return HANDLER_GO_ON;
39571 mod_staticfile_patch_connection(srv, con, p);
39574 s_len = con->uri.path->used - 1;
39577 /* ignore certain extensions */
39578 for (k = 0; k < p->conf.exclude_ext->used; k++) {
39579 - ds = (data_string *)p->conf.exclude_ext->data[k];
39581 + ds = (data_string *)p->conf.exclude_ext->data[k];
39583 if (ds->value->used == 0) continue;
39585 if (buffer_is_equal_right_len(con->physical.path, ds->value, ds->value->used - 1)) {
39586 return HANDLER_GO_ON;
39592 if (con->conf.log_request_handling) {
39593 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling file as static file");
39597 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
39598 con->http_status = 403;
39601 log_error_write(srv, __FILE__, __LINE__, "sbsb",
39602 "not a regular file:", con->uri.path,
39603 "->", con->physical.path);
39606 return HANDLER_FINISHED;
39609 - /* we only handline regular files */
39611 + /* we only handle regular files */
39612 if (!S_ISREG(sce->st.st_mode)) {
39613 con->http_status = 404;
39616 if (con->conf.log_file_not_found) {
39617 log_error_write(srv, __FILE__, __LINE__, "sbsb",
39618 "not a regular file:", con->uri.path,
39623 return HANDLER_FINISHED;
39626 - /* mod_compress might set several data directly, don't overwrite them */
39628 + /* mod_compress might set several parameters directly; don't overwrite them */
39630 /* set response content-type, if not set already */
39632 if (NULL == array_get_element(con->response.headers, "Content-Type")) {
39633 @@ -420,15 +419,15 @@
39634 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_BUF_LEN(sce->content_type));
39639 if (NULL == array_get_element(con->response.headers, "ETag")) {
39640 /* generate e-tag */
39641 etag_mutate(con->physical.etag, sce->etag);
39644 response_header_overwrite(srv, con, CONST_STR_LEN("ETag"), CONST_BUF_LEN(con->physical.etag));
39646 response_header_overwrite(srv, con, CONST_STR_LEN("Accept-Ranges"), CONST_STR_LEN("bytes"));
39649 /* prepare header */
39650 if (NULL == (ds = (data_string *)array_get_element(con->response.headers, "Last-Modified"))) {
39651 mtime = strftime_cache_get(srv, sce->st.st_mtime);
39652 @@ -444,34 +443,34 @@
39653 /* check if we have a conditional GET */
39655 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If-Range"))) {
39656 - /* if the value is the same as our ETag, we do a Range-request,
39657 + /* if the value is the same as our ETag, we do a Range-request,
39658 * otherwise a full 200 */
39660 if (!buffer_is_equal(ds->value, con->physical.etag)) {
39661 do_range_request = 0;
39666 if (do_range_request) {
39667 /* content prepared, I'm done */
39668 con->file_finished = 1;
39671 if (0 == http_response_parse_range(srv, con, p)) {
39672 con->http_status = 206;
39674 return HANDLER_FINISHED;
39679 /* if we are still here, prepare body */
39681 - /* we add it here for all requests
39682 - * the HEAD request will drop it afterwards again
39684 + /* we add it here for all requests
39685 + * the HEAD request will drop it afterwards again
39687 http_chunk_append_file(srv, con, con->physical.path, 0, sce->st.st_size);
39690 con->file_finished = 1;
39693 return HANDLER_FINISHED;
39696 @@ -480,13 +479,13 @@
39697 int mod_staticfile_plugin_init(plugin *p) {
39698 p->version = LIGHTTPD_VERSION_ID;
39699 p->name = buffer_init_string("staticfile");
39702 p->init = mod_staticfile_init;
39703 p->handle_subrequest_start = mod_staticfile_subrequest;
39704 p->set_defaults = mod_staticfile_set_defaults;
39705 p->cleanup = mod_staticfile_free;
39713 --- ../lighttpd-1.4.11/src/mod_status.c 2006-01-10 21:45:32.000000000 +0200
39714 +++ lighttpd-1.4.12/src/mod_status.c 2006-07-16 00:26:04.000000000 +0300
39717 #include <stdlib.h>
39718 #include <string.h>
39719 -#include <unistd.h>
39723 @@ -29,114 +28,114 @@
39729 double traffic_out;
39733 double mod_5s_traffic_out[5];
39734 double mod_5s_requests[5];
39738 double rel_traffic_out;
39739 double rel_requests;
39742 double abs_traffic_out;
39743 double abs_requests;
39746 double bytes_written;
39749 buffer *module_list;
39752 plugin_config **config_storage;
39754 - plugin_config conf;
39756 + plugin_config conf;
39759 INIT_FUNC(mod_status_init) {
39764 p = calloc(1, sizeof(*p));
39767 p->traffic_out = p->requests = 0;
39768 p->rel_traffic_out = p->rel_requests = 0;
39769 p->abs_traffic_out = p->abs_requests = 0;
39770 p->bytes_written = 0;
39771 p->module_list = buffer_init();
39774 for (i = 0; i < 5; i++) {
39775 p->mod_5s_traffic_out[i] = p->mod_5s_requests[i] = 0;
39782 FREE_FUNC(mod_status_free) {
39783 plugin_data *p = p_d;
39788 if (!p) return HANDLER_GO_ON;
39791 buffer_free(p->module_list);
39794 if (p->config_storage) {
39796 for (i = 0; i < srv->config_context->used; i++) {
39797 plugin_config *s = p->config_storage[i];
39800 buffer_free(s->status_url);
39801 buffer_free(s->statistics_url);
39802 buffer_free(s->config_url);
39807 free(p->config_storage);
39816 return HANDLER_GO_ON;
39819 SETDEFAULTS_FUNC(mod_status_set_defaults) {
39820 plugin_data *p = p_d;
39823 - config_values_t cv[] = {
39825 + config_values_t cv[] = {
39826 { "status.status-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
39827 { "status.config-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
39828 { "status.enable-sort", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION },
39829 { "status.statistics-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },
39830 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
39834 if (!p) return HANDLER_ERROR;
39837 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
39840 for (i = 0; i < srv->config_context->used; i++) {
39844 s = calloc(1, sizeof(plugin_config));
39845 s->config_url = buffer_init();
39846 s->status_url = buffer_init();
39848 s->statistics_url = buffer_init();
39851 cv[0].destination = s->status_url;
39852 cv[1].destination = s->config_url;
39853 cv[2].destination = &(s->sort);
39854 cv[3].destination = s->statistics_url;
39857 p->config_storage[i] = s;
39860 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
39861 return HANDLER_ERROR;
39866 return HANDLER_GO_ON;
39869 @@ -151,7 +150,7 @@
39870 buffer_append_string(b, value);
39871 BUFFER_APPEND_STRING_CONST(b, "</td>\n");
39872 BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
39878 @@ -161,13 +160,13 @@
39879 buffer_append_string(b, key);
39880 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
39881 BUFFER_APPEND_STRING_CONST(b, " </tr>\n");
39887 static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
39888 plugin_data *p = p_d;
39891 if (p->conf.sort) {
39892 BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
39893 buffer_append_string(b, key);
39894 @@ -177,13 +176,13 @@
39895 buffer_append_string(b, key);
39896 BUFFER_APPEND_STRING_CONST(b, "</th>\n");
39903 static int mod_status_get_multiplier(double *avg, char *multiplier, int size) {
39907 if (*avg > size) { *avg /= size; *multiplier = 'k'; }
39908 if (*avg > size) { *avg /= size; *multiplier = 'M'; }
39909 if (*avg > size) { *avg /= size; *multiplier = 'G'; }
39910 @@ -202,21 +201,21 @@
39913 char multiplier = '\0';
39919 int days, hours, mins, seconds;
39922 b = chunkqueue_get_append_buffer(con->write_queue);
39924 - BUFFER_COPY_STRING_CONST(b,
39925 + BUFFER_COPY_STRING_CONST(b,
39926 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
39927 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
39928 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
39929 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
39931 " <title>Status</title>\n");
39934 BUFFER_APPEND_STRING_CONST(b,
39935 " <style type=\"text/css\">\n"
39936 " table.status { border: black solid thin; }\n"
39937 @@ -226,14 +225,14 @@
39938 " a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
39939 " span.sortarrow { color: white; text-decoration: none; }\n"
39943 if (p->conf.sort) {
39944 BUFFER_APPEND_STRING_CONST(b,
39945 "<script type=\"text/javascript\">\n"
39947 "var sort_column;\n"
39948 "var prev_span = null;\n");
39951 BUFFER_APPEND_STRING_CONST(b,
39952 "function get_inner_text(el) {\n"
39953 " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
39954 @@ -251,7 +250,7 @@
39960 BUFFER_APPEND_STRING_CONST(b,
39961 "function sortfn(a,b) {\n"
39962 " var at = get_inner_text(a.cells[sort_column]);\n"
39963 @@ -266,7 +265,7 @@
39964 " else return 1;\n"
39969 BUFFER_APPEND_STRING_CONST(b,
39970 "function resort(lnk) {\n"
39971 " var span = lnk.childNodes[1];\n"
39972 @@ -276,7 +275,7 @@
39973 " rows[j-1] = table.rows[j];\n"
39974 " sort_column = lnk.parentNode.cellIndex;\n"
39975 " rows.sort(sortfn);\n");
39978 BUFFER_APPEND_STRING_CONST(b,
39979 " if (prev_span != null) prev_span.innerHTML = '';\n"
39980 " if (span.getAttribute('sortdir')=='down') {\n"
39981 @@ -294,175 +293,175 @@
39986 - BUFFER_APPEND_STRING_CONST(b,
39988 + BUFFER_APPEND_STRING_CONST(b,
39997 /* connection listing */
39998 BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");
40000 - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">");
40001 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
40003 + BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" id=\"status\" summary=\"Server Status\">");
40004 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\"><span id=\"host_addr\">");
40005 buffer_append_string_buffer(b, con->uri.authority);
40006 - BUFFER_APPEND_STRING_CONST(b, " (");
40007 + BUFFER_APPEND_STRING_CONST(b, "</span> (<span id=\"host_name\">");
40008 buffer_append_string_buffer(b, con->server_name);
40009 - BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
40010 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");
40012 + BUFFER_APPEND_STRING_CONST(b, "</span>)</td></tr>\n");
40013 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\" id=\"uptime\">");
40015 ts = srv->cur_ts - srv->startup_ts;
40018 days = ts / (60 * 60 * 24);
40019 ts %= (60 * 60 * 24);
40022 hours = ts / (60 * 60);
40034 buffer_append_long(b, days);
40035 BUFFER_APPEND_STRING_CONST(b, " days ");
40040 buffer_append_long(b, hours);
40041 BUFFER_APPEND_STRING_CONST(b, " hours ");
40046 buffer_append_long(b, mins);
40047 BUFFER_APPEND_STRING_CONST(b, " min ");
40051 buffer_append_long(b, seconds);
40052 BUFFER_APPEND_STRING_CONST(b, " s");
40055 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40056 BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");
40059 ts = srv->startup_ts;
40061 - strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
40063 + strftime(buf, sizeof(buf) - 1, "<span id=\"start_date\">%Y-%m-%d</span> <span id=\"start_time\">%H:%M:%S</span>", localtime(&ts));
40064 buffer_append_string(b, buf);
40065 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40070 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");
40072 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40074 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\" ><span id=\"requests\">");
40075 avg = p->abs_requests;
40077 mod_status_get_multiplier(&avg, &multiplier, 1000);
40080 buffer_append_long(b, avg);
40081 - BUFFER_APPEND_STRING_CONST(b, " ");
40082 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_mult\">");
40083 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40084 - BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");
40086 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40087 + BUFFER_APPEND_STRING_CONST(b, "</span>req</td></tr>\n");
40089 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic\">");
40090 avg = p->abs_traffic_out;
40092 mod_status_get_multiplier(&avg, &multiplier, 1024);
40094 sprintf(buf, "%.2f", avg);
40095 buffer_append_string(b, buf);
40096 - BUFFER_APPEND_STRING_CONST(b, " ");
40097 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_mult\">");
40098 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40099 - BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");
40100 + BUFFER_APPEND_STRING_CONST(b, "</span>byte</td></tr>\n");
40104 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");
40106 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40108 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_avg\">");
40109 avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);
40111 mod_status_get_multiplier(&avg, &multiplier, 1000);
40113 buffer_append_long(b, avg);
40114 - BUFFER_APPEND_STRING_CONST(b, " ");
40115 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_avg_mult\">");
40116 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40117 - BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40119 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40120 + BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40122 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"traffic_avg\">");
40123 avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);
40125 mod_status_get_multiplier(&avg, &multiplier, 1024);
40127 sprintf(buf, "%.2f", avg);
40128 buffer_append_string(b, buf);
40129 - BUFFER_APPEND_STRING_CONST(b, " ");
40130 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"traffic_avg_mult\">");
40131 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40132 - BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40133 + BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40139 BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
40140 for (j = 0, avg = 0; j < 5; j++) {
40141 avg += p->mod_5s_requests[j];
40147 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
40149 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\"><span id=\"requests_sliding_avg\">");
40151 mod_status_get_multiplier(&avg, &multiplier, 1000);
40153 buffer_append_long(b, avg);
40154 - BUFFER_APPEND_STRING_CONST(b, " ");
40155 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_avg_mult\">");
40156 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40158 - BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");
40161 + BUFFER_APPEND_STRING_CONST(b, "</span>req/s</td></tr>\n");
40163 for (j = 0, avg = 0; j < 5; j++) {
40164 avg += p->mod_5s_traffic_out[j];
40170 - BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
40172 + BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\"><span id=\"requests_sliding_traffic\">");
40174 mod_status_get_multiplier(&avg, &multiplier, 1024);
40176 sprintf(buf, "%.2f", avg);
40177 buffer_append_string(b, buf);
40178 - BUFFER_APPEND_STRING_CONST(b, " ");
40179 + BUFFER_APPEND_STRING_CONST(b, "</span> <span id=\"requests_sliding_traffic_mult\">");
40180 if (multiplier) buffer_append_string_len(b, &multiplier, 1);
40181 - BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");
40183 + BUFFER_APPEND_STRING_CONST(b, "</span>byte/s</td></tr>\n");
40185 BUFFER_APPEND_STRING_CONST(b, "</table>\n");
40190 BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
40191 BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
40192 BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
40193 BUFFER_APPEND_STRING_CONST(b, "q = request-start, Q = request-end\n");
40194 BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");
40196 - BUFFER_APPEND_STRING_CONST(b, "<b>");
40198 + BUFFER_APPEND_STRING_CONST(b, "<strong><span id=\"connections\">");
40199 buffer_append_long(b, srv->conns->used);
40200 - BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");
40202 + BUFFER_APPEND_STRING_CONST(b, "</span> connections</strong>\n");
40204 for (j = 0; j < srv->conns->used; j++) {
40205 connection *c = srv->conns->ptr[j];
40206 const char *state = connection_get_short_state(c->state);
40209 buffer_append_string_len(b, state, 1);
40212 if (((j + 1) % 50) == 0) {
40213 BUFFER_APPEND_STRING_CONST(b, "\n");
40218 BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");
40220 - BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\">\n");
40222 + BUFFER_APPEND_STRING_CONST(b, "<table class=\"status\" summary=\"Current connections\" id=\"clients\">\n");
40223 BUFFER_APPEND_STRING_CONST(b, "<tr>");
40224 mod_status_header_append_sort(b, p_d, "Client IP");
40225 mod_status_header_append_sort(b, p_d, "Read");
40226 @@ -473,16 +472,16 @@
40227 mod_status_header_append_sort(b, p_d, "URI");
40228 mod_status_header_append_sort(b, p_d, "File");
40229 BUFFER_APPEND_STRING_CONST(b, "</tr>\n");
40232 for (j = 0; j < srv->conns->used; j++) {
40233 connection *c = srv->conns->ptr[j];
40235 - BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");
40238 + BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string ip\">");
40240 buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));
40242 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40245 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_read\">");
40247 if (con->request.content_length) {
40248 buffer_append_long(b, c->request_content_queue->bytes_in);
40249 BUFFER_APPEND_STRING_CONST(b, "/");
40250 @@ -490,55 +489,55 @@
40252 BUFFER_APPEND_STRING_CONST(b, "0/0");
40255 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40258 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int bytes_written\">");
40260 buffer_append_off_t(b, chunkqueue_written(c->write_queue));
40261 BUFFER_APPEND_STRING_CONST(b, "/");
40262 buffer_append_off_t(b, chunkqueue_length(c->write_queue));
40264 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40267 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string state\">");
40269 buffer_append_string(b, connection_get_state(c->state));
40271 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");
40274 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int time\">");
40276 buffer_append_long(b, srv->cur_ts - c->request_start);
40278 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40281 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string host\">");
40283 if (buffer_is_empty(c->server_name)) {
40284 buffer_append_string_buffer(b, c->uri.authority);
40287 buffer_append_string_buffer(b, c->server_name);
40290 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40293 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string uri\">");
40295 if (!buffer_is_empty(c->uri.path)) {
40296 buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
40299 - BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");
40302 + BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string file\">");
40304 buffer_append_string_buffer(b, c->physical.path);
40307 BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
40311 - BUFFER_APPEND_STRING_CONST(b,
40314 + BUFFER_APPEND_STRING_CONST(b,
40318 - BUFFER_APPEND_STRING_CONST(b,
40321 + BUFFER_APPEND_STRING_CONST(b,
40327 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40333 @@ -548,7 +547,7 @@
40339 b = chunkqueue_get_append_buffer(con->write_queue);
40341 /* output total number of requests */
40342 @@ -556,19 +555,19 @@
40343 avg = p->abs_requests;
40344 buffer_append_long(b, avg);
40345 BUFFER_APPEND_STRING_CONST(b, "\n");
40348 /* output total traffic out in kbytes */
40349 BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
40350 avg = p->abs_traffic_out / 1024;
40351 buffer_append_long(b, avg);
40352 BUFFER_APPEND_STRING_CONST(b, "\n");
40355 /* output uptime */
40356 BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
40357 ts = srv->cur_ts - srv->startup_ts;
40358 buffer_append_long(b, ts);
40359 BUFFER_APPEND_STRING_CONST(b, "\n");
40362 /* output busy servers */
40363 BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
40364 buffer_append_long(b, srv->conns->used);
40365 @@ -577,7 +576,7 @@
40366 /* set text/plain output */
40368 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40374 @@ -591,10 +590,10 @@
40375 /* we have nothing to send */
40376 con->http_status = 204;
40377 con->file_finished = 1;
40380 return HANDLER_FINISHED;
40384 b = chunkqueue_get_append_buffer(con->write_queue);
40386 for (i = 0; i < st->used; i++) {
40387 @@ -605,27 +604,27 @@
40388 buffer_append_long(b, ((data_integer *)(st->data[ndx]))->value);
40389 buffer_append_string(b, "\n");
40393 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));
40396 con->http_status = 200;
40397 con->file_finished = 1;
40400 return HANDLER_FINISHED;
40404 static handler_t mod_status_handle_server_status(server *srv, connection *con, void *p_d) {
40407 if (buffer_is_equal_string(con->uri.query, CONST_STR_LEN("auto"))) {
40408 mod_status_handle_server_status_text(srv, con, p_d);
40410 mod_status_handle_server_status_html(srv, con, p_d);
40414 con->http_status = 200;
40415 con->file_finished = 1;
40418 return HANDLER_FINISHED;
40421 @@ -634,9 +633,9 @@
40422 plugin_data *p = p_d;
40423 buffer *b, *m = p->module_list;
40426 - struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
40429 + struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
40431 /* - poll is most reliable
40432 * - select works everywhere
40433 * - linux-* are experimental
40434 @@ -661,10 +660,10 @@
40436 { FDEVENT_HANDLER_UNSET, NULL }
40440 b = chunkqueue_get_append_buffer(con->write_queue);
40442 - BUFFER_COPY_STRING_CONST(b,
40444 + BUFFER_COPY_STRING_CONST(b,
40445 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
40446 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
40447 " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
40448 @@ -675,7 +674,7 @@
40450 " <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
40451 " <table border=\"1\">\n");
40454 mod_status_header_append(b, "Server-Features");
40456 mod_status_row_append(b, "RegEx Conditionals", "enabled");
40457 @@ -683,21 +682,21 @@
40458 mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
40460 mod_status_header_append(b, "Network Engine");
40463 for (i = 0; event_handlers[i].name; i++) {
40464 if (event_handlers[i].et == srv->event_handler) {
40465 mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
40471 mod_status_header_append(b, "Config-File-Settings");
40474 for (i = 0; i < srv->plugins.used; i++) {
40475 plugin **ps = srv->plugins.ptr;
40478 plugin *pl = ps[i];
40482 buffer_copy_string_buffer(m, pl->name);
40484 @@ -705,137 +704,135 @@
40485 buffer_append_string_buffer(m, pl->name);
40490 mod_status_row_append(b, "Loaded Modules", m->ptr);
40493 BUFFER_APPEND_STRING_CONST(b, " </table>\n");
40495 - BUFFER_APPEND_STRING_CONST(b,
40497 + BUFFER_APPEND_STRING_CONST(b,
40503 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));
40506 con->http_status = 200;
40507 con->file_finished = 1;
40510 return HANDLER_FINISHED;
40513 -#define PATCH(x) \
40514 - p->conf.x = s->x;
40515 static int mod_status_patch_connection(server *srv, connection *con, plugin_data *p) {
40517 plugin_config *s = p->config_storage[0];
40519 - PATCH(status_url);
40520 - PATCH(config_url);
40522 - PATCH(statistics_url);
40525 + PATCH_OPTION(status_url);
40526 + PATCH_OPTION(config_url);
40527 + PATCH_OPTION(sort);
40528 + PATCH_OPTION(statistics_url);
40530 /* skip the first, the global context */
40531 for (i = 1; i < srv->config_context->used; i++) {
40532 data_config *dc = (data_config *)srv->config_context->data[i];
40533 s = p->config_storage[i];
40536 /* condition didn't match */
40537 if (!config_check_cond(srv, con, dc)) continue;
40541 for (j = 0; j < dc->value->used; j++) {
40542 data_unset *du = dc->value->data[j];
40545 if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.status-url"))) {
40546 - PATCH(status_url);
40547 + PATCH_OPTION(status_url);
40548 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.config-url"))) {
40549 - PATCH(config_url);
40550 + PATCH_OPTION(config_url);
40551 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.enable-sort"))) {
40553 + PATCH_OPTION(sort);
40554 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("status.statistics-url"))) {
40555 - PATCH(statistics_url);
40557 + PATCH_OPTION(statistics_url);
40566 static handler_t mod_status_handler(server *srv, connection *con, void *p_d) {
40567 plugin_data *p = p_d;
40570 mod_status_patch_connection(srv, con, p);
40572 - if (!buffer_is_empty(p->conf.status_url) &&
40574 + if (!buffer_is_empty(p->conf.status_url) &&
40575 buffer_is_equal(p->conf.status_url, con->uri.path)) {
40576 return mod_status_handle_server_status(srv, con, p_d);
40577 - } else if (!buffer_is_empty(p->conf.config_url) &&
40578 + } else if (!buffer_is_empty(p->conf.config_url) &&
40579 buffer_is_equal(p->conf.config_url, con->uri.path)) {
40580 return mod_status_handle_server_config(srv, con, p_d);
40581 - } else if (!buffer_is_empty(p->conf.statistics_url) &&
40582 + } else if (!buffer_is_empty(p->conf.statistics_url) &&
40583 buffer_is_equal(p->conf.statistics_url, con->uri.path)) {
40584 return mod_status_handle_server_statistics(srv, con, p_d);
40588 return HANDLER_GO_ON;
40591 TRIGGER_FUNC(mod_status_trigger) {
40592 plugin_data *p = p_d;
40596 /* check all connections */
40597 for (i = 0; i < srv->conns->used; i++) {
40598 connection *c = srv->conns->ptr[i];
40601 p->bytes_written += c->bytes_written_cur_second;
40605 /* a sliding average */
40606 p->mod_5s_traffic_out[p->mod_5s_ndx] = p->bytes_written;
40607 p->mod_5s_requests [p->mod_5s_ndx] = p->requests;
40610 p->mod_5s_ndx = (p->mod_5s_ndx+1) % 5;
40613 p->abs_traffic_out += p->bytes_written;
40614 p->rel_traffic_out += p->bytes_written;
40617 p->bytes_written = 0;
40620 /* reset storage - second */
40621 p->traffic_out = 0;
40625 return HANDLER_GO_ON;
40628 REQUESTDONE_FUNC(mod_status_account) {
40629 plugin_data *p = p_d;
40639 p->bytes_written += con->bytes_written_cur_second;
40642 return HANDLER_GO_ON;
40645 int mod_status_plugin_init(plugin *p) {
40646 p->version = LIGHTTPD_VERSION_ID;
40647 p->name = buffer_init_string("status");
40650 p->init = mod_status_init;
40651 p->cleanup = mod_status_free;
40652 p->set_defaults= mod_status_set_defaults;
40655 p->handle_uri_clean = mod_status_handler;
40656 p->handle_trigger = mod_status_trigger;
40657 p->handle_request_done = mod_status_account;
40665 --- ../lighttpd-1.4.11/src/mod_trigger_b4_dl.c 2005-09-23 22:53:55.000000000 +0300
40666 +++ lighttpd-1.4.12/src/mod_trigger_b4_dl.c 2006-07-16 00:26:03.000000000 +0300
40667 @@ -24,18 +24,18 @@
40670 * this is a trigger_b4_dl for a lighttpd plugin
40675 /* plugin config for all request/connections */
40678 buffer *db_filename;
40681 buffer *trigger_url;
40682 buffer *download_url;
40687 buffer *mc_namespace;
40688 #if defined(HAVE_PCRE_H)
40689 @@ -46,58 +46,58 @@
40693 -#if defined(HAVE_MEMCACHE_H)
40694 +#if defined(HAVE_MEMCACHE_H)
40695 struct memcache *mc;
40699 unsigned short trigger_timeout;
40700 unsigned short debug;
40710 plugin_config **config_storage;
40712 - plugin_config conf;
40714 + plugin_config conf;
40717 /* init the plugin data */
40718 INIT_FUNC(mod_trigger_b4_dl_init) {
40722 p = calloc(1, sizeof(*p));
40725 p->tmp_buf = buffer_init();
40731 /* detroy the plugin data */
40732 FREE_FUNC(mod_trigger_b4_dl_free) {
40733 plugin_data *p = p_d;
40738 if (!p) return HANDLER_GO_ON;
40741 if (p->config_storage) {
40743 for (i = 0; i < srv->config_context->used; i++) {
40744 plugin_config *s = p->config_storage[i];
40749 buffer_free(s->db_filename);
40750 buffer_free(s->download_url);
40751 buffer_free(s->trigger_url);
40752 buffer_free(s->deny_url);
40755 buffer_free(s->mc_namespace);
40756 array_free(s->mc_hosts);
40759 #if defined(HAVE_PCRE_H)
40760 if (s->trigger_regex) pcre_free(s->trigger_regex);
40761 if (s->download_regex) pcre_free(s->download_regex);
40762 @@ -108,16 +108,16 @@
40763 #if defined(HAVE_MEMCACHE_H)
40764 if (s->mc) mc_free(s->mc);
40770 free(p->config_storage);
40774 buffer_free(p->tmp_buf);
40780 return HANDLER_GO_ON;
40783 @@ -126,9 +126,9 @@
40784 SETDEFAULTS_FUNC(mod_trigger_b4_dl_set_defaults) {
40785 plugin_data *p = p_d;
40789 - config_values_t cv[] = {
40792 + config_values_t cv[] = {
40793 { "trigger-before-download.gdbm-filename", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
40794 { "trigger-before-download.trigger-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
40795 { "trigger-before-download.download-url", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
40796 @@ -139,18 +139,18 @@
40797 { "trigger-before-download.debug", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 7 */
40798 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
40802 if (!p) return HANDLER_ERROR;
40805 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
40808 for (i = 0; i < srv->config_context->used; i++) {
40810 #if defined(HAVE_PCRE_H)
40811 const char *errptr;
40816 s = calloc(1, sizeof(plugin_config));
40817 s->db_filename = buffer_init();
40818 s->download_url = buffer_init();
40819 @@ -158,7 +158,7 @@
40820 s->deny_url = buffer_init();
40821 s->mc_hosts = array_init();
40822 s->mc_namespace = buffer_init();
40825 cv[0].destination = s->db_filename;
40826 cv[1].destination = s->trigger_url;
40827 cv[2].destination = s->download_url;
40828 @@ -167,41 +167,41 @@
40829 cv[5].destination = s->mc_hosts;
40830 cv[6].destination = s->mc_namespace;
40831 cv[7].destination = &(s->debug);
40834 p->config_storage[i] = s;
40837 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
40838 return HANDLER_ERROR;
40840 #if defined(HAVE_GDBM_H)
40841 if (!buffer_is_empty(s->db_filename)) {
40842 if (NULL == (s->db = gdbm_open(s->db_filename->ptr, 4096, GDBM_WRCREAT | GDBM_NOLOCK, S_IRUSR | S_IWUSR, 0))) {
40843 - log_error_write(srv, __FILE__, __LINE__, "s",
40844 + log_error_write(srv, __FILE__, __LINE__, "s",
40845 "gdbm-open failed");
40846 return HANDLER_ERROR;
40850 -#if defined(HAVE_PCRE_H)
40851 +#if defined(HAVE_PCRE_H)
40852 if (!buffer_is_empty(s->download_url)) {
40853 if (NULL == (s->download_regex = pcre_compile(s->download_url->ptr,
40854 0, &errptr, &erroff, NULL))) {
40856 - log_error_write(srv, __FILE__, __LINE__, "sbss",
40857 - "compiling regex for download-url failed:",
40859 + log_error_write(srv, __FILE__, __LINE__, "sbss",
40860 + "compiling regex for download-url failed:",
40861 s->download_url, "pos:", erroff);
40862 return HANDLER_ERROR;
40867 if (!buffer_is_empty(s->trigger_url)) {
40868 if (NULL == (s->trigger_regex = pcre_compile(s->trigger_url->ptr,
40869 0, &errptr, &erroff, NULL))) {
40871 - log_error_write(srv, __FILE__, __LINE__, "sbss",
40872 - "compiling regex for trigger-url failed:",
40874 + log_error_write(srv, __FILE__, __LINE__, "sbss",
40875 + "compiling regex for trigger-url failed:",
40876 s->trigger_url, "pos:", erroff);
40879 return HANDLER_ERROR;
40882 @@ -211,100 +211,97 @@
40883 #if defined(HAVE_MEMCACHE_H)
40888 for (k = 0; k < s->mc_hosts->used; k++) {
40889 data_string *ds = (data_string *)s->mc_hosts->data[k];
40892 if (0 != mc_server_add4(s->mc, ds->value->ptr)) {
40893 - log_error_write(srv, __FILE__, __LINE__, "sb",
40894 - "connection to host failed:",
40895 + log_error_write(srv, __FILE__, __LINE__, "sb",
40896 + "connection to host failed:",
40900 return HANDLER_ERROR;
40904 - log_error_write(srv, __FILE__, __LINE__, "s",
40905 + log_error_write(srv, __FILE__, __LINE__, "s",
40906 "memcache support is not compiled in but trigger-before-download.memcache-hosts is set, aborting");
40907 return HANDLER_ERROR;
40913 #if (!defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)) || !defined(HAVE_PCRE_H)
40914 - log_error_write(srv, __FILE__, __LINE__, "s",
40915 + log_error_write(srv, __FILE__, __LINE__, "s",
40916 "(either gdbm or libmemcache) and pcre are require, but were not found, aborting");
40917 return HANDLER_ERROR;
40922 return HANDLER_GO_ON;
40925 -#define PATCH(x) \
40926 - p->conf.x = s->x;
40927 static int mod_trigger_b4_dl_patch_connection(server *srv, connection *con, plugin_data *p) {
40929 plugin_config *s = p->config_storage[0];
40932 #if defined(HAVE_GDBM)
40935 + PATCH_OPTION(db);
40937 #if defined(HAVE_PCRE_H)
40938 - PATCH(download_regex);
40939 - PATCH(trigger_regex);
40941 - PATCH(trigger_timeout);
40943 - PATCH(mc_namespace);
40945 + PATCH_OPTION(download_regex);
40946 + PATCH_OPTION(trigger_regex);
40948 + PATCH_OPTION(trigger_timeout);
40949 + PATCH_OPTION(deny_url);
40950 + PATCH_OPTION(mc_namespace);
40951 + PATCH_OPTION(debug);
40952 #if defined(HAVE_MEMCACHE_H)
40954 + PATCH_OPTION(mc);
40958 /* skip the first, the global context */
40959 for (i = 1; i < srv->config_context->used; i++) {
40960 data_config *dc = (data_config *)srv->config_context->data[i];
40961 s = p->config_storage[i];
40964 /* condition didn't match */
40965 if (!config_check_cond(srv, con, dc)) continue;
40969 for (j = 0; j < dc->value->used; j++) {
40970 data_unset *du = dc->value->data[j];
40972 if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.download-url"))) {
40973 #if defined(HAVE_PCRE_H)
40974 - PATCH(download_regex);
40975 + PATCH_OPTION(download_regex);
40977 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-url"))) {
40978 # if defined(HAVE_PCRE_H)
40979 - PATCH(trigger_regex);
40980 + PATCH_OPTION(trigger_regex);
40982 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.gdbm-filename"))) {
40983 #if defined(HAVE_GDBM_H)
40985 + PATCH_OPTION(db);
40987 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.trigger-timeout"))) {
40988 - PATCH(trigger_timeout);
40989 + PATCH_OPTION(trigger_timeout);
40990 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.debug"))) {
40992 + PATCH_OPTION(debug);
40993 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.deny-url"))) {
40995 + PATCH_OPTION(deny_url);
40996 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-namespace"))) {
40997 - PATCH(mc_namespace);
40998 + PATCH_OPTION(mc_namespace);
40999 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("trigger-before-download.memcache-hosts"))) {
41000 #if defined(HAVE_MEMCACHE_H)
41002 + PATCH_OPTION(mc);
41013 URIHANDLER_FUNC(mod_trigger_b4_dl_uri_handler) {
41014 plugin_data *p = p_d;
41015 @@ -315,20 +312,20 @@
41021 if (con->uri.path->used == 0) return HANDLER_GO_ON;
41024 mod_trigger_b4_dl_patch_connection(srv, con, p);
41027 if (!p->conf.trigger_regex || !p->conf.download_regex) return HANDLER_GO_ON;
41030 # if !defined(HAVE_GDBM_H) && !defined(HAVE_MEMCACHE_H)
41031 return HANDLER_GO_ON;
41032 # elif defined(HAVE_GDBM_H) && defined(HAVE_MEMCACHE_H)
41033 if (!p->conf.db && !p->conf.mc) return HANDLER_GO_ON;
41034 if (p->conf.db && p->conf.mc) {
41035 /* can't decide which one */
41038 return HANDLER_GO_ON;
41040 # elif defined(HAVE_GDBM_H)
41041 @@ -336,12 +333,12 @@
41043 if (!p->conf.mc) return HANDLER_GO_ON;
41047 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "X-Forwarded-For"))) {
41048 /* X-Forwarded-For contains the ip behind the proxy */
41051 remote_ip = ds->value->ptr;
41054 /* memcache can't handle spaces */
41056 remote_ip = inet_ntop_cache_get_ip(srv, &(con->dst_addr));
41057 @@ -350,13 +347,13 @@
41058 if (p->conf.debug) {
41059 log_error_write(srv, __FILE__, __LINE__, "ss", "(debug) remote-ip:", remote_ip);
41063 /* check if URL is a trigger -> insert IP into DB */
41064 if ((n = pcre_exec(p->conf.trigger_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41065 if (n != PCRE_ERROR_NOMATCH) {
41066 log_error_write(srv, __FILE__, __LINE__, "sd",
41067 "execution error while matching:", n);
41070 return HANDLER_ERROR;
41073 @@ -364,34 +361,34 @@
41075 /* the trigger matched */
41079 key.dptr = (char *)remote_ip;
41080 key.dsize = strlen(remote_ip);
41083 val.dptr = (char *)&(srv->cur_ts);
41084 val.dsize = sizeof(srv->cur_ts);
41087 if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41088 log_error_write(srv, __FILE__, __LINE__, "s",
41093 -# if defined(HAVE_MEMCACHE_H)
41094 +# if defined(HAVE_MEMCACHE_H)
41097 buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41098 buffer_append_string(p->tmp_buf, remote_ip);
41101 for (i = 0; i < p->tmp_buf->used - 1; i++) {
41102 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41106 if (p->conf.debug) {
41107 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) triggered IP:", p->tmp_buf);
41110 - if (0 != mc_set(p->conf.mc,
41111 + if (0 != mc_set(p->conf.mc,
41112 CONST_BUF_LEN(p->tmp_buf),
41113 (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41114 p->conf.trigger_timeout, 0)) {
41115 @@ -401,7 +398,7 @@
41121 /* check if URL is a download -> check IP in DB, update timestamp */
41122 if ((n = pcre_exec(p->conf.download_regex, NULL, con->uri.path->ptr, con->uri.path->used - 1, 0, 0, ovec, 3 * N)) < 0) {
41123 if (n != PCRE_ERROR_NOMATCH) {
41124 @@ -411,93 +408,93 @@
41127 /* the download uri matched */
41128 -# if defined(HAVE_GDBM_H)
41129 +# if defined(HAVE_GDBM_H)
41135 key.dptr = (char *)remote_ip;
41136 key.dsize = strlen(remote_ip);
41139 val = gdbm_fetch(p->conf.db, key);
41142 if (val.dptr == NULL) {
41143 /* not found, redirect */
41146 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41149 con->http_status = 307;
41152 return HANDLER_FINISHED;
41156 last_hit = *(time_t *)(val.dptr);
41162 if (srv->cur_ts - last_hit > p->conf.trigger_timeout) {
41163 /* found, but timeout, redirect */
41166 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41167 con->http_status = 307;
41171 if (0 != gdbm_delete(p->conf.db, key)) {
41172 log_error_write(srv, __FILE__, __LINE__, "s",
41178 return HANDLER_FINISHED;
41182 val.dptr = (char *)&(srv->cur_ts);
41183 val.dsize = sizeof(srv->cur_ts);
41186 if (0 != gdbm_store(p->conf.db, key, val, GDBM_REPLACE)) {
41187 log_error_write(srv, __FILE__, __LINE__, "s",
41193 -# if defined(HAVE_MEMCACHE_H)
41195 +# if defined(HAVE_MEMCACHE_H)
41201 buffer_copy_string_buffer(p->tmp_buf, p->conf.mc_namespace);
41202 buffer_append_string(p->tmp_buf, remote_ip);
41205 for (i = 0; i < p->tmp_buf->used - 1; i++) {
41206 if (p->tmp_buf->ptr[i] == ' ') p->tmp_buf->ptr[i] = '-';
41210 if (p->conf.debug) {
41211 log_error_write(srv, __FILE__, __LINE__, "sb", "(debug) checking IP:", p->tmp_buf);
41217 * memcached is do expiration for us, as long as we can fetch it every thing is ok
41218 - * and the timestamp is updated
41220 + * and the timestamp is updated
41223 - if (NULL == (r = mc_aget(p->conf.mc,
41224 + if (NULL == (r = mc_aget(p->conf.mc,
41225 CONST_BUF_LEN(p->tmp_buf)
41229 response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->conf.deny_url));
41232 con->http_status = 307;
41235 return HANDLER_FINISHED;
41242 /* set a new timeout */
41243 - if (0 != mc_set(p->conf.mc,
41244 + if (0 != mc_set(p->conf.mc,
41245 CONST_BUF_LEN(p->tmp_buf),
41246 (char *)&(srv->cur_ts), sizeof(srv->cur_ts),
41247 p->conf.trigger_timeout, 0)) {
41248 @@ -507,13 +504,13 @@
41261 return HANDLER_GO_ON;
41264 @@ -521,21 +518,21 @@
41265 TRIGGER_FUNC(mod_trigger_b4_dl_handle_trigger) {
41266 plugin_data *p = p_d;
41270 /* check DB each minute */
41271 if (srv->cur_ts % 60 != 0) return HANDLER_GO_ON;
41275 for (i = 0; i < srv->config_context->used; i++) {
41276 plugin_config *s = p->config_storage[i];
41277 datum key, val, okey;
41280 if (!s->db) continue;
41285 - /* according to the manual this loop + delete does delete all entries on its way
41288 + /* according to the manual this loop + delete does delete all entries on its way
41290 * we don't care as the next round will remove them. We don't have to perfect here.
41292 for (key = gdbm_firstkey(s->db); key.dptr; key = gdbm_nextkey(s->db, okey)) {
41293 @@ -544,21 +541,21 @@
41299 val = gdbm_fetch(s->db, key);
41302 last_hit = *(time_t *)(val.dptr);
41308 if (srv->cur_ts - last_hit > s->trigger_timeout) {
41309 gdbm_delete(s->db, key);
41315 if (okey.dptr) free(okey.dptr);
41318 /* reorg once a day */
41319 if ((srv->cur_ts % (60 * 60 * 24) != 0)) gdbm_reorganize(s->db);
41321 @@ -571,7 +568,7 @@
41322 int mod_trigger_b4_dl_plugin_init(plugin *p) {
41323 p->version = LIGHTTPD_VERSION_ID;
41324 p->name = buffer_init_string("trigger_b4_dl");
41327 p->init = mod_trigger_b4_dl_init;
41328 p->handle_uri_clean = mod_trigger_b4_dl_uri_handler;
41329 p->set_defaults = mod_trigger_b4_dl_set_defaults;
41330 @@ -579,8 +576,8 @@
41331 p->handle_trigger = mod_trigger_b4_dl_handle_trigger;
41333 p->cleanup = mod_trigger_b4_dl_free;
41341 --- ../lighttpd-1.4.11/src/mod_userdir.c 2005-10-28 16:48:28.000000000 +0300
41342 +++ lighttpd-1.4.12/src/mod_userdir.c 2006-07-16 00:26:04.000000000 +0300
41344 #include "response.h"
41346 #include "plugin.h"
41347 +#include "sys-files.h"
41351 @@ -25,54 +26,54 @@
41361 plugin_config **config_storage;
41363 - plugin_config conf;
41365 + plugin_config conf;
41368 /* init the plugin data */
41369 INIT_FUNC(mod_userdir_init) {
41373 p = calloc(1, sizeof(*p));
41376 p->username = buffer_init();
41377 p->temp_path = buffer_init();
41383 /* detroy the plugin data */
41384 FREE_FUNC(mod_userdir_free) {
41385 plugin_data *p = p_d;
41388 if (!p) return HANDLER_GO_ON;
41391 if (p->config_storage) {
41395 for (i = 0; i < srv->config_context->used; i++) {
41396 plugin_config *s = p->config_storage[i];
41399 array_free(s->include_user);
41400 array_free(s->exclude_user);
41401 buffer_free(s->path);
41402 buffer_free(s->basepath);
41407 free(p->config_storage);
41411 buffer_free(p->username);
41412 buffer_free(p->temp_path);
41418 return HANDLER_GO_ON;
41421 @@ -81,81 +82,78 @@
41422 SETDEFAULTS_FUNC(mod_userdir_set_defaults) {
41423 plugin_data *p = p_d;
41426 - config_values_t cv[] = {
41428 + config_values_t cv[] = {
41429 { "userdir.path", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
41430 { "userdir.exclude-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
41431 { "userdir.include-user", NULL, T_CONFIG_ARRAY, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
41432 { "userdir.basepath", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
41433 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41437 if (!p) return HANDLER_ERROR;
41440 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41443 for (i = 0; i < srv->config_context->used; i++) {
41447 s = calloc(1, sizeof(plugin_config));
41448 s->exclude_user = array_init();
41449 s->include_user = array_init();
41450 s->path = buffer_init();
41451 s->basepath = buffer_init();
41454 cv[0].destination = s->path;
41455 cv[1].destination = s->exclude_user;
41456 cv[2].destination = s->include_user;
41457 cv[3].destination = s->basepath;
41460 p->config_storage[i] = s;
41463 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41464 return HANDLER_ERROR;
41469 return HANDLER_GO_ON;
41472 -#define PATCH(x) \
41473 - p->conf.x = s->x;
41474 static int mod_userdir_patch_connection(server *srv, connection *con, plugin_data *p) {
41476 plugin_config *s = p->config_storage[0];
41479 - PATCH(exclude_user);
41480 - PATCH(include_user);
41484 + PATCH_OPTION(path);
41485 + PATCH_OPTION(exclude_user);
41486 + PATCH_OPTION(include_user);
41487 + PATCH_OPTION(basepath);
41489 /* skip the first, the global context */
41490 for (i = 1; i < srv->config_context->used; i++) {
41491 data_config *dc = (data_config *)srv->config_context->data[i];
41492 s = p->config_storage[i];
41495 /* condition didn't match */
41496 if (!config_check_cond(srv, con, dc)) continue;
41500 for (j = 0; j < dc->value->used; j++) {
41501 data_unset *du = dc->value->data[j];
41504 if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.path"))) {
41506 + PATCH_OPTION(path);
41507 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.exclude-user"))) {
41508 - PATCH(exclude_user);
41509 + PATCH_OPTION(exclude_user);
41510 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.include-user"))) {
41511 - PATCH(include_user);
41512 + PATCH_OPTION(include_user);
41513 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("userdir.basepath"))) {
41515 + PATCH_OPTION(basepath);
41525 URIHANDLER_FUNC(mod_userdir_docroot_handler) {
41526 plugin_data *p = p_d;
41527 @@ -169,18 +167,18 @@
41528 if (con->uri.path->used == 0) return HANDLER_GO_ON;
41530 mod_userdir_patch_connection(srv, con, p);
41533 uri_len = con->uri.path->used - 1;
41536 /* /~user/foo.html -> /home/user/public_html/foo.html */
41539 if (con->uri.path->ptr[0] != '/' ||
41540 con->uri.path->ptr[1] != '~') return HANDLER_GO_ON;
41543 if (NULL == (rel_url = strchr(con->uri.path->ptr + 2, '/'))) {
41544 /* / is missing -> redirect to .../ as we are a user - DIRECTORY ! :) */
41545 http_response_redirect_to_directory(srv, con);
41548 return HANDLER_FINISHED;
41551 @@ -188,10 +186,10 @@
41552 if (0 == rel_url - (con->uri.path->ptr + 2)) {
41553 return HANDLER_GO_ON;
41557 buffer_copy_string_len(p->username, con->uri.path->ptr + 2, rel_url - (con->uri.path->ptr + 2));
41559 - if (buffer_is_empty(p->conf.basepath)
41561 + if (buffer_is_empty(p->conf.basepath)
41563 && NULL == (pwd = getpwnam(p->username->ptr))
41565 @@ -200,31 +198,31 @@
41566 return HANDLER_GO_ON;
41571 for (k = 0; k < p->conf.exclude_user->used; k++) {
41572 data_string *ds = (data_string *)p->conf.exclude_user->data[k];
41575 if (buffer_is_equal(ds->value, p->username)) {
41576 /* user in exclude list */
41577 return HANDLER_GO_ON;
41582 if (p->conf.include_user->used) {
41583 int found_user = 0;
41584 for (k = 0; k < p->conf.include_user->used; k++) {
41585 data_string *ds = (data_string *)p->conf.include_user->data[k];
41588 if (buffer_is_equal(ds->value, p->username)) {
41589 /* user in include list */
41596 if (!found_user) return HANDLER_GO_ON;
41600 /* we build the physical path */
41602 if (buffer_is_empty(p->conf.basepath)) {
41603 @@ -252,23 +250,23 @@
41606 buffer_copy_string_buffer(p->temp_path, p->conf.basepath);
41607 - BUFFER_APPEND_SLASH(p->temp_path);
41608 + PATHNAME_APPEND_SLASH(p->temp_path);
41609 buffer_append_string_buffer(p->temp_path, p->username);
41611 - BUFFER_APPEND_SLASH(p->temp_path);
41612 - buffer_append_string_buffer(p->temp_path, p->conf.path);
41613 + PATHNAME_APPEND_SLASH(p->temp_path);
41614 + buffer_append_string_buffer(p->temp_path, p->conf.path);
41616 if (buffer_is_empty(p->conf.basepath)) {
41621 ret = stat(p->temp_path->ptr, &st);
41622 if (ret < 0 || S_ISDIR(st.st_mode) != 1) {
41623 return HANDLER_GO_ON;
41628 - BUFFER_APPEND_SLASH(p->temp_path);
41629 + PATHNAME_APPEND_SLASH(p->temp_path);
41630 buffer_append_string(p->temp_path, rel_url + 1); /* skip the / */
41631 buffer_copy_string_buffer(con->physical.path, p->temp_path);
41633 @@ -282,13 +280,13 @@
41634 int mod_userdir_plugin_init(plugin *p) {
41635 p->version = LIGHTTPD_VERSION_ID;
41636 p->name = buffer_init_string("userdir");
41639 p->init = mod_userdir_init;
41640 p->handle_physical = mod_userdir_docroot_handler;
41641 p->set_defaults = mod_userdir_set_defaults;
41642 p->cleanup = mod_userdir_free;
41650 --- ../lighttpd-1.4.11/src/mod_usertrack.c 2006-01-31 15:01:20.000000000 +0200
41651 +++ lighttpd-1.4.12/src/mod_usertrack.c 2006-07-16 00:26:04.000000000 +0300
41652 @@ -24,44 +24,44 @@
41658 plugin_config **config_storage;
41660 - plugin_config conf;
41662 + plugin_config conf;
41665 /* init the plugin data */
41666 INIT_FUNC(mod_usertrack_init) {
41670 p = calloc(1, sizeof(*p));
41676 /* detroy the plugin data */
41677 FREE_FUNC(mod_usertrack_free) {
41678 plugin_data *p = p_d;
41684 if (!p) return HANDLER_GO_ON;
41687 if (p->config_storage) {
41689 for (i = 0; i < srv->config_context->used; i++) {
41690 plugin_config *s = p->config_storage[i];
41693 buffer_free(s->cookie_name);
41694 buffer_free(s->cookie_domain);
41699 free(p->config_storage);
41706 return HANDLER_GO_ON;
41709 @@ -70,38 +70,38 @@
41710 SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
41711 plugin_data *p = p_d;
41714 - config_values_t cv[] = {
41716 + config_values_t cv[] = {
41717 { "usertrack.cookie-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
41718 { "usertrack.cookie-max-age", NULL, T_CONFIG_SHORT, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
41719 { "usertrack.cookie-domain", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
41721 - { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
41723 + { "usertrack.cookiename", NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
41724 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
41728 if (!p) return HANDLER_ERROR;
41731 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
41734 for (i = 0; i < srv->config_context->used; i++) {
41738 s = calloc(1, sizeof(plugin_config));
41739 s->cookie_name = buffer_init();
41740 s->cookie_domain = buffer_init();
41741 s->cookie_max_age = 0;
41744 cv[0].destination = s->cookie_name;
41745 cv[1].destination = &(s->cookie_max_age);
41746 cv[2].destination = s->cookie_domain;
41749 p->config_storage[i] = s;
41752 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
41753 return HANDLER_ERROR;
41757 if (buffer_is_empty(s->cookie_name)) {
41758 buffer_copy_string(s->cookie_name, "TRACKID");
41760 @@ -109,68 +109,65 @@
41761 for (j = 0; j < s->cookie_name->used - 1; j++) {
41762 char c = s->cookie_name->ptr[j] | 32;
41763 if (c < 'a' || c > 'z') {
41764 - log_error_write(srv, __FILE__, __LINE__, "sb",
41765 - "invalid character in usertrack.cookie-name:",
41766 + log_error_write(srv, __FILE__, __LINE__, "sb",
41767 + "invalid character in usertrack.cookie-name:",
41771 return HANDLER_ERROR;
41777 if (!buffer_is_empty(s->cookie_domain)) {
41779 for (j = 0; j < s->cookie_domain->used - 1; j++) {
41780 char c = s->cookie_domain->ptr[j];
41781 if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
41782 - log_error_write(srv, __FILE__, __LINE__, "sb",
41783 - "invalid character in usertrack.cookie-domain:",
41784 + log_error_write(srv, __FILE__, __LINE__, "sb",
41785 + "invalid character in usertrack.cookie-domain:",
41789 return HANDLER_ERROR;
41796 return HANDLER_GO_ON;
41799 -#define PATCH(x) \
41800 - p->conf.x = s->x;
41801 static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
41803 plugin_config *s = p->config_storage[0];
41805 - PATCH(cookie_name);
41806 - PATCH(cookie_domain);
41807 - PATCH(cookie_max_age);
41810 + PATCH_OPTION(cookie_name);
41811 + PATCH_OPTION(cookie_domain);
41812 + PATCH_OPTION(cookie_max_age);
41814 /* skip the first, the global context */
41815 for (i = 1; i < srv->config_context->used; i++) {
41816 data_config *dc = (data_config *)srv->config_context->data[i];
41817 s = p->config_storage[i];
41820 /* condition didn't match */
41821 if (!config_check_cond(srv, con, dc)) continue;
41825 for (j = 0; j < dc->value->used; j++) {
41826 data_unset *du = dc->value->data[j];
41829 if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
41830 - PATCH(cookie_name);
41831 + PATCH_OPTION(cookie_name);
41832 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
41833 - PATCH(cookie_max_age);
41834 + PATCH_OPTION(cookie_max_age);
41835 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
41836 - PATCH(cookie_domain);
41837 + PATCH_OPTION(cookie_domain);
41847 URIHANDLER_FUNC(mod_usertrack_uri_handler) {
41848 plugin_data *p = p_d;
41849 @@ -178,38 +175,38 @@
41850 unsigned char h[16];
41855 if (con->uri.path->used == 0) return HANDLER_GO_ON;
41858 mod_usertrack_patch_connection(srv, con, p);
41861 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
41863 /* we have a cookie, does it contain a valid name ? */
41865 - /* parse the cookie
41868 + /* parse the cookie
41870 * check for cookiename + (WS | '=')
41876 if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
41881 for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
41885 /* ok, found the key of our own cookie */
41888 if (strlen(nc) > 32) {
41890 return HANDLER_GO_ON;
41899 if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
41900 ds = data_response_init();
41901 @@ -217,39 +214,39 @@
41902 buffer_copy_string(ds->key, "Set-Cookie");
41903 buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
41904 buffer_append_string(ds->value, "=");
41908 /* taken from mod_auth.c */
41911 /* generate shared-secret */
41913 MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
41914 MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
41917 /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
41918 ltostr(hh, srv->cur_ts);
41919 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
41920 ltostr(hh, rand());
41921 MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
41924 MD5_Final(h, &Md5Ctx);
41927 buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
41928 buffer_append_string(ds->value, "; Path=/");
41929 buffer_append_string(ds->value, "; Version=1");
41932 if (!buffer_is_empty(p->conf.cookie_domain)) {
41933 buffer_append_string(ds->value, "; Domain=");
41934 buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
41938 if (p->conf.cookie_max_age) {
41939 buffer_append_string(ds->value, "; max-age=");
41940 buffer_append_long(ds->value, p->conf.cookie_max_age);
41944 array_insert_unique(con->response.headers, (data_unset *)ds);
41947 return HANDLER_GO_ON;
41950 @@ -258,13 +255,13 @@
41951 int mod_usertrack_plugin_init(plugin *p) {
41952 p->version = LIGHTTPD_VERSION_ID;
41953 p->name = buffer_init_string("usertrack");
41956 p->init = mod_usertrack_init;
41957 p->handle_uri_clean = mod_usertrack_uri_handler;
41958 p->set_defaults = mod_usertrack_set_defaults;
41959 p->cleanup = mod_usertrack_free;
41967 --- ../lighttpd-1.4.11/src/mod_webdav.c 2006-03-03 01:28:58.000000000 +0200
41968 +++ lighttpd-1.4.12/src/mod_webdav.c 2006-07-18 13:03:40.000000000 +0300
41971 #include <stdlib.h>
41972 #include <string.h>
41973 -#include <dirent.h>
41975 -#include <unistd.h>
41978 #include <assert.h>
41979 -#include <sys/mman.h>
41981 #ifdef HAVE_CONFIG_H
41982 #include "config.h"
41984 #include <sqlite3.h>
41987 +#if defined(HAVE_LIBXML_H) && defined(HAVE_SQLITE3_H) && defined(HAVE_UUID_H)
41989 +#include <uuid/uuid.h>
41994 #include "buffer.h"
41995 @@ -33,13 +35,16 @@
41996 #include "stream.h"
41997 #include "stat_cache.h"
41999 +#include "sys-files.h"
42000 +#include "sys-mmap.h"
42001 +#include "sys-strings.h"
42004 * this is a webdav for a lighttpd plugin
42006 - * at least a very basic one.
42007 + * at least a very basic one.
42008 * - for now it is read-only and we only support PROPFIND
42014 @@ -58,64 +63,70 @@
42015 sqlite3_stmt *stmt_delete_prop;
42016 sqlite3_stmt *stmt_select_prop;
42017 sqlite3_stmt *stmt_select_propnames;
42020 sqlite3_stmt *stmt_delete_uri;
42021 sqlite3_stmt *stmt_move_uri;
42022 sqlite3_stmt *stmt_copy_uri;
42024 + sqlite3_stmt *stmt_remove_lock;
42025 + sqlite3_stmt *stmt_create_lock;
42026 + sqlite3_stmt *stmt_read_lock;
42027 + sqlite3_stmt *stmt_read_lock_by_uri;
42028 + sqlite3_stmt *stmt_refresh_lock;
42040 plugin_config **config_storage;
42042 - plugin_config conf;
42044 + plugin_config conf;
42047 /* init the plugin data */
42048 INIT_FUNC(mod_webdav_init) {
42052 p = calloc(1, sizeof(*p));
42055 p->tmp_buf = buffer_init();
42057 p->uri.scheme = buffer_init();
42058 p->uri.path_raw = buffer_init();
42059 p->uri.path = buffer_init();
42060 p->uri.authority = buffer_init();
42063 p->physical.path = buffer_init();
42064 p->physical.rel_path = buffer_init();
42065 p->physical.doc_root = buffer_init();
42066 p->physical.basedir = buffer_init();
42072 /* detroy the plugin data */
42073 FREE_FUNC(mod_webdav_free) {
42074 plugin_data *p = p_d;
42079 if (!p) return HANDLER_GO_ON;
42082 if (p->config_storage) {
42084 for (i = 0; i < srv->config_context->used; i++) {
42085 plugin_config *s = p->config_storage[i];
42090 buffer_free(s->sqlite_db_name);
42091 #ifdef USE_PROPPATCH
42094 sqlite3_finalize(s->stmt_delete_prop);
42095 sqlite3_finalize(s->stmt_delete_uri);
42096 sqlite3_finalize(s->stmt_copy_uri);
42097 @@ -123,9 +134,15 @@
42098 sqlite3_finalize(s->stmt_update_prop);
42099 sqlite3_finalize(s->stmt_select_prop);
42100 sqlite3_finalize(s->stmt_select_propnames);
42102 + sqlite3_finalize(s->stmt_read_lock);
42103 + sqlite3_finalize(s->stmt_read_lock_by_uri);
42104 + sqlite3_finalize(s->stmt_create_lock);
42105 + sqlite3_finalize(s->stmt_remove_lock);
42106 + sqlite3_finalize(s->stmt_refresh_lock);
42107 sqlite3_close(s->sql);
42113 free(p->config_storage);
42114 @@ -135,16 +152,16 @@
42115 buffer_free(p->uri.path_raw);
42116 buffer_free(p->uri.path);
42117 buffer_free(p->uri.authority);
42120 buffer_free(p->physical.path);
42121 buffer_free(p->physical.rel_path);
42122 buffer_free(p->physical.doc_root);
42123 buffer_free(p->physical.basedir);
42126 buffer_free(p->tmp_buf);
42132 return HANDLER_GO_ON;
42135 @@ -153,32 +170,32 @@
42136 SETDEFAULTS_FUNC(mod_webdav_set_defaults) {
42137 plugin_data *p = p_d;
42140 - config_values_t cv[] = {
42142 + config_values_t cv[] = {
42143 { "webdav.activate", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
42144 { "webdav.is-readonly", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 1 */
42145 { "webdav.sqlite-db-name", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 2 */
42146 { "webdav.log-xml", NULL, T_CONFIG_BOOLEAN, T_CONFIG_SCOPE_CONNECTION }, /* 3 */
42147 { NULL, NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
42151 if (!p) return HANDLER_ERROR;
42154 p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
42157 for (i = 0; i < srv->config_context->used; i++) {
42161 s = calloc(1, sizeof(plugin_config));
42162 s->sqlite_db_name = buffer_init();
42165 cv[0].destination = &(s->enabled);
42166 cv[1].destination = &(s->is_readonly);
42167 cv[2].destination = s->sqlite_db_name;
42168 cv[3].destination = &(s->log_xml);
42171 p->config_storage[i] = s;
42174 if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
42175 return HANDLER_ERROR;
42177 @@ -193,8 +210,26 @@
42178 return HANDLER_ERROR;
42181 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42182 - CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42183 + if (SQLITE_OK != sqlite3_exec(s->sql,
42184 + "CREATE TABLE properties ("
42185 + " resource TEXT NOT NULL,"
42186 + " prop TEXT NOT NULL,"
42187 + " ns TEXT NOT NULL,"
42188 + " value TEXT NOT NULL,"
42189 + " PRIMARY KEY(resource, prop, ns))",
42190 + NULL, NULL, &err)) {
42192 + if (0 != strcmp(err, "table properties already exists")) {
42193 + log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42194 + sqlite3_free(err);
42196 + return HANDLER_ERROR;
42198 + sqlite3_free(err);
42201 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42202 + CONST_STR_LEN("SELECT value FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42203 &(s->stmt_select_prop), &next_stmt)) {
42204 /* prepare failed */
42206 @@ -202,8 +237,8 @@
42207 return HANDLER_ERROR;
42210 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42211 - CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42212 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42213 + CONST_STR_LEN("SELECT ns, prop FROM properties WHERE resource = ?"),
42214 &(s->stmt_select_propnames), &next_stmt)) {
42215 /* prepare failed */
42217 @@ -211,16 +246,67 @@
42218 return HANDLER_ERROR;
42221 - if (SQLITE_OK != sqlite3_exec(s->sql,
42222 - "CREATE TABLE properties ("
42224 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42225 + CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42226 + &(s->stmt_update_prop), &next_stmt)) {
42227 + /* prepare failed */
42229 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42230 + return HANDLER_ERROR;
42233 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42234 + CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42235 + &(s->stmt_delete_prop), &next_stmt)) {
42236 + /* prepare failed */
42237 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42239 + return HANDLER_ERROR;
42242 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42243 + CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42244 + &(s->stmt_delete_uri), &next_stmt)) {
42245 + /* prepare failed */
42246 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42248 + return HANDLER_ERROR;
42251 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42252 + CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42253 + &(s->stmt_copy_uri), &next_stmt)) {
42254 + /* prepare failed */
42255 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42257 + return HANDLER_ERROR;
42260 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42261 + CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42262 + &(s->stmt_move_uri), &next_stmt)) {
42263 + /* prepare failed */
42264 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42266 + return HANDLER_ERROR;
42271 + if (SQLITE_OK != sqlite3_exec(s->sql,
42272 + "CREATE TABLE locks ("
42273 + " locktoken TEXT NOT NULL,"
42274 " resource TEXT NOT NULL,"
42275 - " prop TEXT NOT NULL,"
42276 - " ns TEXT NOT NULL,"
42277 - " value TEXT NOT NULL,"
42278 - " PRIMARY KEY(resource, prop, ns))",
42279 + " lockscope TEXT NOT NULL,"
42280 + " locktype TEXT NOT NULL,"
42281 + " owner TEXT NOT NULL,"
42282 + " depth INT NOT NULL,"
42283 + " timeout TIMESTAMP NOT NULL,"
42284 + " PRIMARY KEY(locktoken))",
42285 NULL, NULL, &err)) {
42287 - if (0 != strcmp(err, "table properties already exists")) {
42288 + if (0 != strcmp(err, "table locks already exists")) {
42289 log_error_write(srv, __FILE__, __LINE__, "ss", "can't open transaction:", err);
42292 @@ -228,127 +314,138 @@
42297 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42298 - CONST_STR_LEN("REPLACE INTO properties (resource, prop, ns, value) VALUES (?, ?, ?, ?)"),
42299 - &(s->stmt_update_prop), &next_stmt)) {
42301 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42302 + CONST_STR_LEN("INSERT INTO locks (locktoken, resource, lockscope, locktype, owner, depth, timeout) VALUES (?,?,?,?,?,?, CURRENT_TIME + 600)"),
42303 + &(s->stmt_create_lock), &next_stmt)) {
42304 /* prepare failed */
42305 + log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42307 - log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed:", sqlite3_errmsg(s->sql));
42308 return HANDLER_ERROR;
42311 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42312 - CONST_STR_LEN("DELETE FROM properties WHERE resource = ? AND prop = ? AND ns = ?"),
42313 - &(s->stmt_delete_prop), &next_stmt)) {
42314 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42315 + CONST_STR_LEN("DELETE FROM locks WHERE locktoken = ?"),
42316 + &(s->stmt_remove_lock), &next_stmt)) {
42317 /* prepare failed */
42318 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42320 return HANDLER_ERROR;
42323 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42324 - CONST_STR_LEN("DELETE FROM properties WHERE resource = ?"),
42325 - &(s->stmt_delete_uri), &next_stmt)) {
42326 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42327 + CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE locktoken = ?"),
42328 + &(s->stmt_read_lock), &next_stmt)) {
42329 /* prepare failed */
42330 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42332 return HANDLER_ERROR;
42335 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42336 - CONST_STR_LEN("INSERT INTO properties SELECT ?, prop, ns, value FROM properties WHERE resource = ?"),
42337 - &(s->stmt_copy_uri), &next_stmt)) {
42338 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42339 + CONST_STR_LEN("SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout FROM locks WHERE resource = ?"),
42340 + &(s->stmt_read_lock_by_uri), &next_stmt)) {
42341 /* prepare failed */
42342 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42344 return HANDLER_ERROR;
42347 - if (SQLITE_OK != sqlite3_prepare(s->sql,
42348 - CONST_STR_LEN("UPDATE properties SET resource = ? WHERE resource = ?"),
42349 - &(s->stmt_move_uri), &next_stmt)) {
42350 + if (SQLITE_OK != sqlite3_prepare(s->sql,
42351 + CONST_STR_LEN("UPDATE locks SET timeout = CURRENT_TIME + 600 WHERE locktoken = ?"),
42352 + &(s->stmt_refresh_lock), &next_stmt)) {
42353 /* prepare failed */
42354 log_error_write(srv, __FILE__, __LINE__, "ss", "sqlite3_prepare failed", sqlite3_errmsg(s->sql));
42356 return HANDLER_ERROR;
42361 log_error_write(srv, __FILE__, __LINE__, "s", "Sorry, no sqlite3 and libxml2 support include, compile with --with-webdav-props");
42362 return HANDLER_ERROR;
42368 return HANDLER_GO_ON;
42371 -#define PATCH(x) \
42372 - p->conf.x = s->x;
42373 static int mod_webdav_patch_connection(server *srv, connection *con, plugin_data *p) {
42375 plugin_config *s = p->config_storage[0];
42378 - PATCH(is_readonly);
42382 + PATCH_OPTION(enabled);
42383 + PATCH_OPTION(is_readonly);
42384 + PATCH_OPTION(log_xml);
42386 #ifdef USE_PROPPATCH
42388 - PATCH(stmt_update_prop);
42389 - PATCH(stmt_delete_prop);
42390 - PATCH(stmt_select_prop);
42391 - PATCH(stmt_select_propnames);
42393 - PATCH(stmt_delete_uri);
42394 - PATCH(stmt_move_uri);
42395 - PATCH(stmt_copy_uri);
42396 + PATCH_OPTION(sql);
42397 + PATCH_OPTION(stmt_update_prop);
42398 + PATCH_OPTION(stmt_delete_prop);
42399 + PATCH_OPTION(stmt_select_prop);
42400 + PATCH_OPTION(stmt_select_propnames);
42402 + PATCH_OPTION(stmt_delete_uri);
42403 + PATCH_OPTION(stmt_move_uri);
42404 + PATCH_OPTION(stmt_copy_uri);
42406 + PATCH_OPTION(stmt_remove_lock);
42407 + PATCH_OPTION(stmt_refresh_lock);
42408 + PATCH_OPTION(stmt_create_lock);
42409 + PATCH_OPTION(stmt_read_lock);
42410 + PATCH_OPTION(stmt_read_lock_by_uri);
42412 /* skip the first, the global context */
42413 for (i = 1; i < srv->config_context->used; i++) {
42414 data_config *dc = (data_config *)srv->config_context->data[i];
42415 s = p->config_storage[i];
42418 /* condition didn't match */
42419 if (!config_check_cond(srv, con, dc)) continue;
42423 for (j = 0; j < dc->value->used; j++) {
42424 data_unset *du = dc->value->data[j];
42427 if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.activate"))) {
42429 + PATCH_OPTION(enabled);
42430 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.is-readonly"))) {
42431 - PATCH(is_readonly);
42432 + PATCH_OPTION(is_readonly);
42433 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.log-xml"))) {
42435 + PATCH_OPTION(log_xml);
42436 } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("webdav.sqlite-db-name"))) {
42437 #ifdef USE_PROPPATCH
42439 - PATCH(stmt_update_prop);
42440 - PATCH(stmt_delete_prop);
42441 - PATCH(stmt_select_prop);
42442 - PATCH(stmt_select_propnames);
42444 - PATCH(stmt_delete_uri);
42445 - PATCH(stmt_move_uri);
42446 - PATCH(stmt_copy_uri);
42447 + PATCH_OPTION(sql);
42448 + PATCH_OPTION(stmt_update_prop);
42449 + PATCH_OPTION(stmt_delete_prop);
42450 + PATCH_OPTION(stmt_select_prop);
42451 + PATCH_OPTION(stmt_select_propnames);
42453 + PATCH_OPTION(stmt_delete_uri);
42454 + PATCH_OPTION(stmt_move_uri);
42455 + PATCH_OPTION(stmt_copy_uri);
42457 + PATCH_OPTION(stmt_remove_lock);
42458 + PATCH_OPTION(stmt_refresh_lock);
42459 + PATCH_OPTION(stmt_create_lock);
42460 + PATCH_OPTION(stmt_read_lock);
42461 + PATCH_OPTION(stmt_read_lock_by_uri);
42472 URIHANDLER_FUNC(mod_webdav_uri_handler) {
42473 plugin_data *p = p_d;
42478 if (con->uri.path->used == 0) return HANDLER_GO_ON;
42481 mod_webdav_patch_connection(srv, con, p);
42483 if (!p->conf.enabled) return HANDLER_GO_ON;
42484 @@ -362,20 +459,20 @@
42485 if (p->conf.is_readonly) {
42486 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND"));
42488 - response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH"));
42489 + response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("PROPFIND, DELETE, MKCOL, PUT, MOVE, COPY, PROPPATCH, LOCK, UNLOCK"));
42498 return HANDLER_GO_ON;
42500 -static int webdav_gen_prop_tag(server *srv, connection *con,
42504 +static int webdav_gen_prop_tag(server *srv, connection *con,
42511 @@ -414,7 +511,7 @@
42512 buffer_append_string_buffer(b, dst->rel_path);
42513 buffer_append_string(b,"</D:href>\n");
42514 buffer_append_string(b,"<D:status>\n");
42517 if (con->request.http_version == HTTP_VERSION_1_1) {
42518 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
42520 @@ -458,14 +555,13 @@
42522 /* bind the values to the insert */
42524 - sqlite3_bind_text(stmt, 1,
42525 - dst->rel_path->ptr,
42526 + sqlite3_bind_text(stmt, 1,
42527 + dst->rel_path->ptr,
42528 dst->rel_path->used - 1,
42532 if (SQLITE_DONE != sqlite3_step(stmt)) {
42538 @@ -493,14 +589,14 @@
42539 (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
42541 /* ignore the parent dir */
42545 buffer_copy_string_buffer(d.path, dst->path);
42546 - BUFFER_APPEND_SLASH(d.path);
42547 + PATHNAME_APPEND_SLASH(d.path);
42548 buffer_append_string(d.path, de->d_name);
42551 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
42552 - BUFFER_APPEND_SLASH(d.rel_path);
42553 + PATHNAME_APPEND_SLASH(d.rel_path);
42554 buffer_append_string(d.rel_path, de->d_name);
42556 /* stat and unlink afterwards */
42557 @@ -508,7 +604,7 @@
42558 /* don't about it yet, rmdir will fail too */
42559 } else if (S_ISDIR(st.st_mode)) {
42560 have_multi_status = webdav_delete_dir(srv, con, p, &d, b);
42563 /* try to unlink it */
42564 if (-1 == rmdir(d.path->ptr)) {
42566 @@ -535,14 +631,13 @@
42568 /* bind the values to the insert */
42570 - sqlite3_bind_text(stmt, 1,
42572 + sqlite3_bind_text(stmt, 1,
42574 d.rel_path->used - 1,
42578 if (SQLITE_DONE != sqlite3_step(stmt)) {
42584 @@ -569,7 +664,7 @@
42585 if (stream_open(&s, src->path)) {
42590 if (-1 == (ofd = open(dst->path->ptr, O_WRONLY|O_TRUNC|O_CREAT|(overwrite ? 0 : O_EXCL), 0600))) {
42591 /* opening the destination failed for some reason */
42593 @@ -601,7 +696,7 @@
42602 @@ -614,19 +709,18 @@
42603 sqlite3_reset(stmt);
42605 /* bind the values to the insert */
42606 - sqlite3_bind_text(stmt, 1,
42607 - dst->rel_path->ptr,
42608 + sqlite3_bind_text(stmt, 1,
42609 + dst->rel_path->ptr,
42610 dst->rel_path->used - 1,
42613 - sqlite3_bind_text(stmt, 2,
42614 - src->rel_path->ptr,
42615 + sqlite3_bind_text(stmt, 2,
42616 + src->rel_path->ptr,
42617 src->rel_path->used - 1,
42621 if (SQLITE_DONE != sqlite3_step(stmt)) {
42627 @@ -655,21 +749,21 @@
42628 (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')) {
42633 buffer_copy_string_buffer(s.path, src->path);
42634 - BUFFER_APPEND_SLASH(s.path);
42635 + PATHNAME_APPEND_SLASH(s.path);
42636 buffer_append_string(s.path, de->d_name);
42638 buffer_copy_string_buffer(d.path, dst->path);
42639 - BUFFER_APPEND_SLASH(d.path);
42640 + PATHNAME_APPEND_SLASH(d.path);
42641 buffer_append_string(d.path, de->d_name);
42643 buffer_copy_string_buffer(s.rel_path, src->rel_path);
42644 - BUFFER_APPEND_SLASH(s.rel_path);
42645 + PATHNAME_APPEND_SLASH(s.rel_path);
42646 buffer_append_string(s.rel_path, de->d_name);
42648 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
42649 - BUFFER_APPEND_SLASH(d.rel_path);
42650 + PATHNAME_APPEND_SLASH(d.rel_path);
42651 buffer_append_string(d.rel_path, de->d_name);
42653 if (-1 == stat(s.path->ptr, &st)) {
42654 @@ -692,19 +786,18 @@
42655 sqlite3_reset(stmt);
42657 /* bind the values to the insert */
42658 - sqlite3_bind_text(stmt, 1,
42659 - dst->rel_path->ptr,
42660 + sqlite3_bind_text(stmt, 1,
42661 + dst->rel_path->ptr,
42662 dst->rel_path->used - 1,
42665 - sqlite3_bind_text(stmt, 2,
42666 - src->rel_path->ptr,
42667 + sqlite3_bind_text(stmt, 2,
42668 + src->rel_path->ptr,
42669 src->rel_path->used - 1,
42673 if (SQLITE_DONE != sqlite3_step(stmt)) {
42679 @@ -721,7 +814,7 @@
42680 buffer_free(s.rel_path);
42681 buffer_free(d.path);
42682 buffer_free(d.rel_path);
42688 @@ -748,12 +841,12 @@
42689 if (S_ISDIR(sce->st.st_mode)) {
42690 buffer_append_string(b, "<D:getcontenttype>httpd/unix-directory</D:getcontenttype>");
42692 - } else if(S_ISREG(sce->st.st_mode)) {
42693 + } else if(S_ISREG(sce->st.st_mode)) {
42694 for (k = 0; k < con->conf.mimetypes->used; k++) {
42695 data_string *ds = (data_string *)con->conf.mimetypes->data[k];
42698 if (ds->key->used == 0) continue;
42701 if (buffer_is_equal_right_len(dst->path, ds->key, ds->key->used - 1)) {
42702 buffer_append_string(b,"<D:getcontenttype>");
42703 buffer_append_string_buffer(b, ds->value);
42704 @@ -807,23 +900,23 @@
42706 /* bind the values to the insert */
42708 - sqlite3_bind_text(stmt, 1,
42709 - dst->rel_path->ptr,
42710 + sqlite3_bind_text(stmt, 1,
42711 + dst->rel_path->ptr,
42712 dst->rel_path->used - 1,
42714 - sqlite3_bind_text(stmt, 2,
42715 + sqlite3_bind_text(stmt, 2,
42719 - sqlite3_bind_text(stmt, 3,
42720 + sqlite3_bind_text(stmt, 3,
42726 - while (SQLITE_ROW == sqlite3_step(p->conf.stmt_select_prop)) {
42727 + while (SQLITE_ROW == sqlite3_step(stmt)) {
42728 /* there is a row for us, we only expect a single col 'value' */
42729 - webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(p->conf.stmt_select_prop, 0), b);
42730 + webdav_gen_prop_tag(srv, con, prop_name, prop_ns, (char *)sqlite3_column_text(stmt, 0), b);
42734 @@ -840,7 +933,7 @@
42738 -webdav_property live_properties[] = {
42739 +webdav_property live_properties[] = {
42740 { "DAV:", "creationdate" },
42741 { "DAV:", "displayname" },
42742 { "DAV:", "getcontentlanguage" },
42743 @@ -871,8 +964,8 @@
42744 webdav_property *prop;
42746 prop = props->ptr[i];
42748 - if (0 != webdav_get_property(srv, con, p,
42750 + if (0 != webdav_get_property(srv, con, p,
42751 dst, prop->prop, prop->ns, b_200)) {
42752 webdav_gen_prop_tag(srv, con, prop->prop, prop->ns, NULL, b_404);
42754 @@ -916,12 +1009,12 @@
42755 if (-1 == c->file.fd && /* open the file if not already open */
42756 -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
42757 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
42764 if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
42765 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
42766 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
42767 strerror(errno), c->file.name, c->file.fd);
42770 @@ -938,7 +1031,7 @@
42771 if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->file.mmap.start + c->offset, weHave, 0))) {
42772 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
42776 c->offset += weHave;
42777 cq->bytes_out += weHave;
42779 @@ -956,7 +1049,7 @@
42780 if (XML_ERR_OK != (err = xmlParseChunk(ctxt, c->mem->ptr + c->offset, weHave, 0))) {
42781 log_error_write(srv, __FILE__, __LINE__, "sddd", "xmlParseChunk failed at:", cq->bytes_out, weHave, err);
42785 c->offset += weHave;
42786 cq->bytes_out += weHave;
42788 @@ -991,6 +1084,113 @@
42792 +int webdav_lockdiscovery(server *srv, connection *con,
42793 + buffer *locktoken, const char *lockscope, const char *locktype, int depth) {
42797 + response_header_overwrite(srv, con, CONST_STR_LEN("Lock-Token"), CONST_BUF_LEN(locktoken));
42799 + response_header_overwrite(srv, con,
42800 + CONST_STR_LEN("Content-Type"),
42801 + CONST_STR_LEN("text/xml; charset=\"utf-8\""));
42803 + b = chunkqueue_get_append_buffer(con->write_queue);
42805 + buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
42807 + buffer_append_string(b,"<D:prop xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
42808 + buffer_append_string(b,"<D:lockdiscovery>\n");
42809 + buffer_append_string(b,"<D:activelock>\n");
42811 + buffer_append_string(b,"<D:lockscope>");
42812 + buffer_append_string(b,"<D:");
42813 + buffer_append_string(b, lockscope);
42814 + buffer_append_string(b, "/>");
42815 + buffer_append_string(b,"</D:lockscope>\n");
42817 + buffer_append_string(b,"<D:locktype>");
42818 + buffer_append_string(b,"<D:");
42819 + buffer_append_string(b, locktype);
42820 + buffer_append_string(b, "/>");
42821 + buffer_append_string(b,"</D:locktype>\n");
42823 + buffer_append_string(b,"<D:depth>");
42824 + buffer_append_string(b, depth == 0 ? "0" : "infinity");
42825 + buffer_append_string(b,"</D:depth>\n");
42827 + buffer_append_string(b,"<D:timeout>");
42828 + buffer_append_string(b, "Second-600");
42829 + buffer_append_string(b,"</D:timeout>\n");
42831 + buffer_append_string(b,"<D:owner>");
42832 + buffer_append_string(b,"</D:owner>\n");
42834 + buffer_append_string(b,"<D:locktoken>");
42835 + buffer_append_string(b, "<D:href>");
42836 + buffer_append_string_buffer(b, locktoken);
42837 + buffer_append_string(b, "</D:href>");
42838 + buffer_append_string(b,"</D:locktoken>\n");
42840 + buffer_append_string(b,"</D:activelock>\n");
42841 + buffer_append_string(b,"</D:lockdiscovery>\n");
42842 + buffer_append_string(b,"</D:prop>\n");
42847 + * check if resource is having the right locks to access to resource
42852 +int webdav_has_lock(server *srv, connection *con, plugin_data *p, buffer *uri) {
42853 + int has_lock = 1;
42863 + * there is NOT, AND and OR
42864 + * and a list can be tagged
42866 + * (<lock-token>) is untagged
42867 + * <tag> (<lock-token>) is tagged
42869 + * as long as we don't handle collections it is simple. :)
42871 + * X-Litmus: locks: 11 (owner_modify)
42872 + * If: <http://127.0.0.1:1025/dav/litmus/lockme> (<opaquelocktoken:2165478d-0611-49c4-be92-e790d68a38f1>)
42874 + * X-Litmus: locks: 16 (fail_cond_put)
42875 + * If: (<DAV:no-lock> ["-1622396671"])
42877 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
42879 + /* we didn't provided a lock-token -> */
42880 + /* if the resource is locked -> 423 */
42882 + sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
42884 + sqlite3_reset(stmt);
42886 + sqlite3_bind_text(stmt, 1,
42887 + CONST_BUF_LEN(uri),
42888 + SQLITE_TRANSIENT);
42890 + while (SQLITE_ROW == sqlite3_step(stmt)) {
42899 URIHANDLER_FUNC(mod_webdav_subrequest_handler) {
42900 plugin_data *p = p_d;
42902 @@ -1001,7 +1201,8 @@
42905 webdav_properties *req_props;
42907 + stat_cache_entry *sce = NULL;
42911 if (!p->conf.enabled) return HANDLER_GO_ON;
42912 @@ -1019,7 +1220,19 @@
42915 /* is there a content-body ? */
42918 + switch (stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
42919 + case HANDLER_ERROR:
42920 + if (errno == ENOENT) {
42921 + con->http_status = 404;
42922 + return HANDLER_FINISHED;
42930 #ifdef USE_PROPPATCH
42931 /* any special requests or just allprop ? */
42932 if (con->request.content_length) {
42933 @@ -1087,14 +1300,13 @@
42934 /* get all property names (EMPTY) */
42935 sqlite3_reset(stmt);
42936 /* bind the values to the insert */
42938 - sqlite3_bind_text(stmt, 1,
42939 - con->uri.path->ptr,
42941 + sqlite3_bind_text(stmt, 1,
42942 + con->uri.path->ptr,
42943 con->uri.path->used - 1,
42947 if (SQLITE_DONE != sqlite3_step(stmt)) {
42951 } else if (0 == xmlStrcmp(cmd->name, BAD_CAST "allprop")) {
42952 @@ -1115,13 +1327,13 @@
42953 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
42955 b = chunkqueue_get_append_buffer(con->write_queue);
42958 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
42960 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\" xmlns:ns0=\"urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/\">\n");
42965 prop_200 = buffer_init();
42966 prop_404 = buffer_init();
42968 @@ -1129,7 +1341,7 @@
42971 webdav_get_props(srv, con, p, &(con->physical), req_props, prop_200, prop_404);
42974 buffer_append_string(b,"<D:response>\n");
42975 buffer_append_string(b,"<D:href>");
42976 buffer_append_string_buffer(b, con->uri.scheme);
42977 @@ -1145,9 +1357,9 @@
42978 buffer_append_string_buffer(b, prop_200);
42980 buffer_append_string(b,"</D:prop>\n");
42983 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
42986 buffer_append_string(b,"</D:propstat>\n");
42988 if (!buffer_is_empty(prop_404)) {
42989 @@ -1157,16 +1369,16 @@
42990 buffer_append_string_buffer(b, prop_404);
42992 buffer_append_string(b,"</D:prop>\n");
42995 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
42998 buffer_append_string(b,"</D:propstat>\n");
43001 buffer_append_string(b,"</D:response>\n");
43006 if (NULL != (dir = opendir(con->physical.path->ptr))) {
43009 @@ -1179,16 +1391,16 @@
43010 if (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0') {
43012 /* ignore the parent dir */
43016 buffer_copy_string_buffer(d.path, dst->path);
43017 - BUFFER_APPEND_SLASH(d.path);
43018 + PATHNAME_APPEND_SLASH(d.path);
43020 buffer_copy_string_buffer(d.rel_path, dst->rel_path);
43021 - BUFFER_APPEND_SLASH(d.rel_path);
43022 + PATHNAME_APPEND_SLASH(d.rel_path);
43024 if (de->d_name[0] == '.' && de->d_name[1] == '\0') {
43025 - /* don't append the . */
43026 + /* don't append the . */
43028 buffer_append_string(d.path, de->d_name);
43029 buffer_append_string(d.rel_path, de->d_name);
43030 @@ -1198,7 +1410,7 @@
43031 buffer_reset(prop_404);
43033 webdav_get_props(srv, con, p, &d, req_props, prop_200, prop_404);
43036 buffer_append_string(b,"<D:response>\n");
43037 buffer_append_string(b,"<D:href>");
43038 buffer_append_string_buffer(b, con->uri.scheme);
43039 @@ -1214,9 +1426,9 @@
43040 buffer_append_string_buffer(b, prop_200);
43042 buffer_append_string(b,"</D:prop>\n");
43045 buffer_append_string(b,"<D:status>HTTP/1.1 200 OK</D:status>\n");
43048 buffer_append_string(b,"</D:propstat>\n");
43050 if (!buffer_is_empty(prop_404)) {
43051 @@ -1226,9 +1438,9 @@
43052 buffer_append_string_buffer(b, prop_404);
43054 buffer_append_string(b,"</D:prop>\n");
43057 buffer_append_string(b,"<D:status>HTTP/1.1 404 Not Found</D:status>\n");
43060 buffer_append_string(b,"</D:propstat>\n");
43063 @@ -1275,7 +1487,7 @@
43065 return HANDLER_FINISHED;
43069 /* let's create the directory */
43071 if (-1 == mkdir(con->physical.path->ptr, 0700)) {
43072 @@ -1303,7 +1515,13 @@
43073 con->http_status = 403;
43074 return HANDLER_FINISHED;
43078 + /* does the client have a lock for this connection ? */
43079 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43080 + con->http_status = 423;
43081 + return HANDLER_FINISHED;
43084 /* stat and unlink afterwards */
43085 if (-1 == stat(con->physical.path->ptr, &st)) {
43086 /* don't about it yet, unlink will fail too */
43087 @@ -1323,7 +1541,7 @@
43088 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/xml; charset=\"utf-8\""));
43090 b = chunkqueue_get_append_buffer(con->write_queue);
43093 buffer_copy_string(b, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
43095 buffer_append_string(b,"<D:multistatus xmlns:D=\"DAV:\">\n");
43096 @@ -1331,7 +1549,7 @@
43097 buffer_append_string_buffer(b, multi_status_resp);
43099 buffer_append_string(b,"</D:multistatus>\n");
43102 if (p->conf.log_xml) {
43103 log_error_write(srv, __FILE__, __LINE__, "sb", "XML-response-body:", b);
43105 @@ -1340,7 +1558,7 @@
43106 con->file_finished = 1;
43108 /* everything went fine, remove the directory */
43111 if (-1 == rmdir(con->physical.path->ptr)) {
43114 @@ -1375,97 +1593,174 @@
43115 case HTTP_METHOD_PUT: {
43117 chunkqueue *cq = con->request_content_queue;
43119 + data_string *ds_range;
43121 if (p->conf.is_readonly) {
43122 con->http_status = 403;
43123 return HANDLER_FINISHED;
43126 + /* is a exclusive lock set on the source */
43127 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43128 + con->http_status = 423;
43129 + return HANDLER_FINISHED;
43133 assert(chunkqueue_length(cq) == (off_t)con->request.content_length);
43135 - /* taken what we have in the request-body and write it to a file */
43136 - if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC, 0600))) {
43137 - /* we can't open the file */
43138 - con->http_status = 403;
43141 + /* RFC2616 Section 9.6 PUT requires us to send 501 on all Content-* we don't support
43142 + * - most important Content-Range
43145 + * Example: Content-Range: bytes 100-1037/1038 */
43147 - con->http_status = 201; /* created */
43148 - con->file_finished = 1;
43149 + if (NULL != (ds_range = (data_string *)array_get_element(con->request.headers, "Content-Range"))) {
43150 + const char *num = ds_range->value->ptr;
43152 + char *err = NULL;
43154 - for (c = cq->first; c; c = cq->first) {
43156 + if (0 != strncmp(num, "bytes ", 6)) {
43157 + con->http_status = 501; /* not implemented */
43159 - /* copy all chunks */
43160 - switch(c->type) {
43163 - if (c->file.mmap.start == MAP_FAILED) {
43164 - if (-1 == c->file.fd && /* open the file if not already open */
43165 - -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43166 - log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43171 - if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43172 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43173 - strerror(errno), c->file.name, c->file.fd);
43174 + return HANDLER_FINISHED;
43179 + /* we only support <num>- ... */
43181 - c->file.mmap.length = c->file.length;
43184 - close(c->file.fd);
43187 - /* chunk_reset() or chunk_free() will cleanup for us */
43190 - if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43193 - con->http_status = 507;
43197 - con->http_status = 403;
43203 - if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43206 - con->http_status = 507;
43210 - con->http_status = 403;
43215 + while (*num == ' ' || *num == '\t') num++;
43217 + if (*num == '\0') {
43218 + con->http_status = 501; /* not implemented */
43220 + return HANDLER_FINISHED;
43223 + offset = strtoll(num, &err, 10);
43225 + if (*err != '-' || offset < 0) {
43226 + con->http_status = 501; /* not implemented */
43228 + return HANDLER_FINISHED;
43231 + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY, 0600))) {
43234 + con->http_status = 404; /* not found */
43236 - case UNUSED_CHUNK:
43238 + con->http_status = 403; /* not found */
43241 + return HANDLER_FINISHED;
43244 + if (-1 == lseek(fd, offset, SEEK_SET)) {
43245 + con->http_status = 501; /* not implemented */
43249 + return HANDLER_FINISHED;
43251 + con->http_status = 200; /* modified */
43253 + /* take what we have in the request-body and write it to a file */
43255 + /* if the file doesn't exist, create it */
43256 + if (-1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_TRUNC, 0600))) {
43257 + if (errno == ENOENT &&
43258 + -1 == (fd = open(con->physical.path->ptr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0600))) {
43259 + /* we can't open the file */
43260 + con->http_status = 403;
43264 - cq->bytes_out += r;
43265 + return HANDLER_FINISHED;
43268 + con->http_status = 201; /* created */
43271 + con->http_status = 200; /* modified */
43275 + con->file_finished = 1;
43277 + for (c = cq->first; c; c = cq->first) {
43280 + /* copy all chunks */
43281 + switch(c->type) {
43284 + if (c->file.mmap.start == MAP_FAILED) {
43285 + if (-1 == c->file.fd && /* open the file if not already open */
43286 + -1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
43287 + log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
43292 + if (MAP_FAILED == (c->file.mmap.start = mmap(0, c->file.length, PROT_READ, MAP_SHARED, c->file.fd, 0))) {
43293 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed: ",
43294 + strerror(errno), c->file.name, c->file.fd);
43299 + c->file.mmap.length = c->file.length;
43301 + close(c->file.fd);
43304 + /* chunk_reset() or chunk_free() will cleanup for us */
43307 + if ((r = write(fd, c->file.mmap.start + c->offset, c->file.length - c->offset)) < 0) {
43310 + con->http_status = 507;
43314 + con->http_status = 403;
43318 - chunkqueue_remove_finished_chunks(cq);
43321 + if ((r = write(fd, c->mem->ptr + c->offset, c->mem->used - c->offset - 1)) < 0) {
43324 + con->http_status = 507;
43328 + con->http_status = 403;
43333 + case UNUSED_CHUNK:
43340 + cq->bytes_out += r;
43344 + chunkqueue_remove_finished_chunks(cq);
43348 return HANDLER_FINISHED;
43350 - case HTTP_METHOD_MOVE:
43351 + case HTTP_METHOD_MOVE:
43352 case HTTP_METHOD_COPY: {
43353 buffer *destination = NULL;
43355 @@ -1475,7 +1770,15 @@
43356 con->http_status = 403;
43357 return HANDLER_FINISHED;
43361 + /* is a exclusive lock set on the source */
43362 + if (con->request.http_method == HTTP_METHOD_MOVE) {
43363 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43364 + con->http_status = 423;
43365 + return HANDLER_FINISHED;
43369 if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Destination"))) {
43370 destination = ds->value;
43372 @@ -1549,10 +1852,10 @@
43375 buffer_copy_string_buffer(p->physical.path, p->physical.doc_root);
43376 - BUFFER_APPEND_SLASH(p->physical.path);
43377 + PATHNAME_APPEND_SLASH(p->physical.path);
43378 buffer_copy_string_buffer(p->physical.basedir, p->physical.path);
43380 - /* don't add a second / */
43381 + /* don't add a second / */
43382 if (p->physical.rel_path->ptr[0] == '/') {
43383 buffer_append_string_len(p->physical.path, p->physical.rel_path->ptr + 1, p->physical.rel_path->used - 2);
43385 @@ -1613,6 +1916,12 @@
43386 /* it is just a file, good */
43389 + /* does the client have a lock for this connection ? */
43390 + if (!webdav_has_lock(srv, con, p, p->uri.path)) {
43391 + con->http_status = 423;
43392 + return HANDLER_FINISHED;
43395 /* destination exists */
43396 if (0 == (r = stat(p->physical.path->ptr, &st))) {
43397 if (S_ISDIR(st.st_mode)) {
43398 @@ -1636,7 +1945,7 @@
43399 return HANDLER_FINISHED;
43401 } else if (overwrite == 0) {
43402 - /* destination exists, but overwrite is not set */
43403 + /* destination exists, but overwrite is not set */
43404 con->http_status = 412;
43405 return HANDLER_FINISHED;
43407 @@ -1655,16 +1964,16 @@
43408 sqlite3_reset(stmt);
43410 /* bind the values to the insert */
43411 - sqlite3_bind_text(stmt, 1,
43412 - p->uri.path->ptr,
43413 + sqlite3_bind_text(stmt, 1,
43414 + p->uri.path->ptr,
43415 p->uri.path->used - 1,
43418 - sqlite3_bind_text(stmt, 2,
43419 - con->uri.path->ptr,
43420 + sqlite3_bind_text(stmt, 2,
43421 + con->uri.path->ptr,
43422 con->uri.path->used - 1,
43426 if (SQLITE_DONE != sqlite3_step(stmt)) {
43427 log_error_write(srv, __FILE__, __LINE__, "ss", "sql-move failed:", sqlite3_errmsg(p->conf.sql));
43429 @@ -1691,12 +2000,17 @@
43431 return HANDLER_FINISHED;
43433 - case HTTP_METHOD_PROPPATCH: {
43434 + case HTTP_METHOD_PROPPATCH:
43435 if (p->conf.is_readonly) {
43436 con->http_status = 403;
43437 return HANDLER_FINISHED;
43440 + if (!webdav_has_lock(srv, con, p, con->uri.path)) {
43441 + con->http_status = 423;
43442 + return HANDLER_FINISHED;
43445 /* check if destination exists */
43446 if (-1 == stat(con->physical.path->ptr, &st)) {
43448 @@ -1737,7 +2051,7 @@
43450 sqlite3_stmt *stmt;
43452 - stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
43453 + stmt = (0 == xmlStrcmp(cmd->name, BAD_CAST "remove")) ?
43454 p->conf.stmt_delete_prop : p->conf.stmt_update_prop;
43456 for (props = cmd->children; props; props = props->next) {
43457 @@ -1762,34 +2076,35 @@
43459 /* bind the values to the insert */
43461 - sqlite3_bind_text(stmt, 1,
43462 - con->uri.path->ptr,
43463 + sqlite3_bind_text(stmt, 1,
43464 + con->uri.path->ptr,
43465 con->uri.path->used - 1,
43467 - sqlite3_bind_text(stmt, 2,
43468 + sqlite3_bind_text(stmt, 2,
43469 (char *)prop->name,
43470 strlen((char *)prop->name),
43473 - sqlite3_bind_text(stmt, 3,
43474 + sqlite3_bind_text(stmt, 3,
43475 (char *)prop->ns->href,
43476 strlen((char *)prop->ns->href),
43479 - sqlite3_bind_text(stmt, 3,
43480 + sqlite3_bind_text(stmt, 3,
43485 if (stmt == p->conf.stmt_update_prop) {
43486 - sqlite3_bind_text(stmt, 4,
43487 + sqlite3_bind_text(stmt, 4,
43488 (char *)xmlNodeGetContent(prop),
43489 strlen((char *)xmlNodeGetContent(prop)),
43494 if (SQLITE_DONE != (r = sqlite3_step(stmt))) {
43495 - log_error_write(srv, __FILE__, __LINE__, "ss", "sql-set failed:", sqlite3_errmsg(p->conf.sql));
43496 + log_error_write(srv, __FILE__, __LINE__, "ss",
43497 + "sql-set failed:", sqlite3_errmsg(p->conf.sql));
43501 @@ -1804,7 +2119,7 @@
43503 goto propmatch_cleanup;
43507 con->http_status = 400;
43509 if (SQLITE_OK != sqlite3_exec(p->conf.sql, "COMMIT", NULL, NULL, &err)) {
43510 @@ -1821,6 +2136,7 @@
43517 con->http_status = 400;
43518 @@ -1830,11 +2146,307 @@
43520 con->http_status = 501;
43521 return HANDLER_FINISHED;
43523 + case HTTP_METHOD_LOCK:
43525 + * a mac wants to write
43527 + * LOCK /dav/expire.txt HTTP/1.1\r\n
43528 + * User-Agent: WebDAVFS/1.3 (01308000) Darwin/8.1.0 (Power Macintosh)\r\n
43529 + * Accept: * / *\r\n
43531 + * Timeout: Second-600\r\n
43532 + * Content-Type: text/xml; charset=\"utf-8\"\r\n
43533 + * Content-Length: 229\r\n
43534 + * Connection: keep-alive\r\n
43535 + * Host: 192.168.178.23:1025\r\n
43537 + * <?xml version=\"1.0\" encoding=\"utf-8\"?>\n
43538 + * <D:lockinfo xmlns:D=\"DAV:\">\n
43539 + * <D:lockscope><D:exclusive/></D:lockscope>\n
43540 + * <D:locktype><D:write/></D:locktype>\n
43542 + * <D:href>http://www.apple.com/webdav_fs/</D:href>\n
43544 + * </D:lockinfo>\n
43547 + if (depth != 0 && depth != -1) {
43548 + con->http_status = 400;
43550 + return HANDLER_FINISHED;
43554 + if (con->request.content_length) {
43556 + buffer *hdr_if = NULL;
43558 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43559 + hdr_if = ds->value;
43562 + /* we don't support Depth: Infinity on locks */
43563 + if (hdr_if == NULL && depth == -1) {
43564 + con->http_status = 409; /* Conflict */
43566 + return HANDLER_FINISHED;
43569 + if (1 == webdav_parse_chunkqueue(srv, con, p, con->request_content_queue, &xml)) {
43570 + xmlNode *rootnode = xmlDocGetRootElement(xml);
43572 + assert(rootnode);
43574 + if (0 == xmlStrcmp(rootnode->name, BAD_CAST "lockinfo")) {
43575 + xmlNode *lockinfo;
43576 + const xmlChar *lockscope = NULL, *locktype = NULL, *owner = NULL;
43578 + for (lockinfo = rootnode->children; lockinfo; lockinfo = lockinfo->next) {
43579 + if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "lockscope")) {
43581 + for (value = lockinfo->children; value; value = value->next) {
43582 + if ((0 == xmlStrcmp(value->name, BAD_CAST "exclusive")) ||
43583 + (0 == xmlStrcmp(value->name, BAD_CAST "shared"))) {
43584 + lockscope = value->name;
43586 + con->http_status = 400;
43589 + return HANDLER_FINISHED;
43592 + } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "locktype")) {
43594 + for (value = lockinfo->children; value; value = value->next) {
43595 + if ((0 == xmlStrcmp(value->name, BAD_CAST "write"))) {
43596 + locktype = value->name;
43598 + con->http_status = 400;
43601 + return HANDLER_FINISHED;
43605 + } else if (0 == xmlStrcmp(lockinfo->name, BAD_CAST "owner")) {
43609 + if (lockscope && locktype) {
43610 + sqlite3_stmt *stmt = p->conf.stmt_read_lock_by_uri;
43612 + /* is this resourse already locked ? */
43614 + /* SELECT locktoken, resource, lockscope, locktype, owner, depth, timeout
43616 + * WHERE resource = ? */
43620 + sqlite3_reset(stmt);
43622 + sqlite3_bind_text(stmt, 1,
43623 + p->uri.path->ptr,
43624 + p->uri.path->used - 1,
43625 + SQLITE_TRANSIENT);
43627 + /* it is the PK */
43628 + while (SQLITE_ROW == sqlite3_step(stmt)) {
43629 + /* we found a lock
43630 + * 1. is it compatible ?
43631 + * 2. is it ours */
43632 + char *sql_lockscope = (char *)sqlite3_column_text(stmt, 2);
43634 + if (strcmp(sql_lockscope, "exclusive")) {
43635 + con->http_status = 423;
43636 + } else if (0 == xmlStrcmp(lockscope, BAD_CAST "exclusive")) {
43637 + /* resourse is locked with a shared lock
43638 + * client wants exclusive */
43639 + con->http_status = 423;
43642 + if (con->http_status == 423) {
43644 + return HANDLER_FINISHED;
43648 + stmt = p->conf.stmt_create_lock;
43650 + /* create a lock-token */
43652 + char uuid[37] /* 36 + \0 */;
43654 + uuid_generate(id);
43655 + uuid_unparse(id, uuid);
43657 + buffer_copy_string(p->tmp_buf, "opaquelocktoken:");
43658 + buffer_append_string(p->tmp_buf, uuid);
43660 + /* "CREATE TABLE locks ("
43661 + * " locktoken TEXT NOT NULL,"
43662 + * " resource TEXT NOT NULL,"
43663 + * " lockscope TEXT NOT NULL,"
43664 + * " locktype TEXT NOT NULL,"
43665 + * " owner TEXT NOT NULL,"
43666 + * " depth INT NOT NULL,"
43669 + sqlite3_reset(stmt);
43671 + sqlite3_bind_text(stmt, 1,
43672 + CONST_BUF_LEN(p->tmp_buf),
43673 + SQLITE_TRANSIENT);
43675 + sqlite3_bind_text(stmt, 2,
43676 + CONST_BUF_LEN(con->uri.path),
43677 + SQLITE_TRANSIENT);
43679 + sqlite3_bind_text(stmt, 3,
43681 + xmlStrlen(lockscope),
43682 + SQLITE_TRANSIENT);
43684 + sqlite3_bind_text(stmt, 4,
43686 + xmlStrlen(locktype),
43687 + SQLITE_TRANSIENT);
43690 + sqlite3_bind_text(stmt, 5,
43693 + SQLITE_TRANSIENT);
43696 + sqlite3_bind_int(stmt, 6,
43700 + if (SQLITE_DONE != sqlite3_step(stmt)) {
43701 + log_error_write(srv, __FILE__, __LINE__, "ss",
43702 + "create lock:", sqlite3_errmsg(p->conf.sql));
43705 + /* looks like we survived */
43706 + webdav_lockdiscovery(srv, con, p->tmp_buf, lockscope, locktype, depth);
43708 + con->http_status = 201;
43709 + con->file_finished = 1;
43715 + return HANDLER_FINISHED;
43717 + con->http_status = 400;
43718 + return HANDLER_FINISHED;
43722 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "If"))) {
43723 + buffer *locktoken = ds->value;
43724 + sqlite3_stmt *stmt = p->conf.stmt_refresh_lock;
43726 + /* remove the < > around the token */
43727 + if (locktoken->used < 6) {
43728 + con->http_status = 400;
43730 + return HANDLER_FINISHED;
43733 + buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 2, locktoken->used - 5);
43735 + sqlite3_reset(stmt);
43737 + sqlite3_bind_text(stmt, 1,
43738 + CONST_BUF_LEN(p->tmp_buf),
43739 + SQLITE_TRANSIENT);
43741 + if (SQLITE_DONE != sqlite3_step(stmt)) {
43742 + log_error_write(srv, __FILE__, __LINE__, "ss",
43743 + "refresh lock:", sqlite3_errmsg(p->conf.sql));
43746 + webdav_lockdiscovery(srv, con, p->tmp_buf, "exclusive", "write", 0);
43748 + con->http_status = 200;
43749 + con->file_finished = 1;
43750 + return HANDLER_FINISHED;
43752 + /* we need a lock-token to refresh */
43753 + con->http_status = 400;
43755 + return HANDLER_FINISHED;
43760 + con->http_status = 501;
43761 + return HANDLER_FINISHED;
43763 + case HTTP_METHOD_UNLOCK:
43765 + if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Lock-Token"))) {
43766 + buffer *locktoken = ds->value;
43767 + sqlite3_stmt *stmt = p->conf.stmt_remove_lock;
43769 + /* remove the < > around the token */
43770 + if (locktoken->used < 4) {
43771 + con->http_status = 400;
43773 + return HANDLER_FINISHED;
43779 + * if the resourse is locked:
43780 + * - by us: unlock
43781 + * - by someone else: 401
43782 + * if the resource is not locked:
43786 + buffer_copy_string_len(p->tmp_buf, locktoken->ptr + 1, locktoken->used - 3);
43788 + sqlite3_reset(stmt);
43790 + sqlite3_bind_text(stmt, 1,
43791 + CONST_BUF_LEN(p->tmp_buf),
43792 + SQLITE_TRANSIENT);
43794 + sqlite3_bind_text(stmt, 2,
43795 + CONST_BUF_LEN(con->uri.path),
43796 + SQLITE_TRANSIENT);
43798 + if (SQLITE_DONE != sqlite3_step(stmt)) {
43799 + log_error_write(srv, __FILE__, __LINE__, "ss",
43800 + "remove lock:", sqlite3_errmsg(p->conf.sql));
43803 + if (0 == sqlite3_changes(p->conf.sql)) {
43804 + con->http_status = 401;
43806 + con->http_status = 204;
43808 + return HANDLER_FINISHED;
43810 + /* we need a lock-token to unlock */
43811 + con->http_status = 400;
43813 + return HANDLER_FINISHED;
43817 + con->http_status = 501;
43818 + return HANDLER_FINISHED;
43826 return HANDLER_GO_ON;
43828 @@ -1845,14 +2457,14 @@
43829 int mod_webdav_plugin_init(plugin *p) {
43830 p->version = LIGHTTPD_VERSION_ID;
43831 p->name = buffer_init_string("webdav");
43834 p->init = mod_webdav_init;
43835 p->handle_uri_clean = mod_webdav_uri_handler;
43836 p->handle_physical = mod_webdav_subrequest_handler;
43837 p->set_defaults = mod_webdav_set_defaults;
43838 p->cleanup = mod_webdav_free;
43846 --- ../lighttpd-1.4.11/src/network.c 2006-03-04 16:45:46.000000000 +0200
43847 +++ lighttpd-1.4.12/src/network.c 2006-07-18 13:03:40.000000000 +0300
43849 #include <sys/types.h>
43850 #include <sys/stat.h>
43851 -#include <sys/time.h>
43855 -#include <unistd.h>
43856 #include <string.h>
43857 #include <stdlib.h>
43858 #include <assert.h>
43860 +#include <stdio.h>
43862 #include "network.h"
43863 #include "fdevent.h"
43865 @@ -19,11 +19,12 @@
43866 #include "network_backends.h"
43867 #include "sys-mmap.h"
43868 #include "sys-socket.h"
43869 +#include "sys-files.h"
43872 -# include <openssl/ssl.h>
43873 -# include <openssl/err.h>
43874 -# include <openssl/rand.h>
43875 +# include <openssl/ssl.h>
43876 +# include <openssl/err.h>
43877 +# include <openssl/rand.h>
43880 handler_t network_server_handle_fdevent(void *s, void *context, int revents) {
43881 @@ -31,25 +32,25 @@
43882 server_socket *srv_socket = (server_socket *)context;
43890 if (revents != FDEVENT_IN) {
43891 - log_error_write(srv, __FILE__, __LINE__, "sdd",
43892 + log_error_write(srv, __FILE__, __LINE__, "sdd",
43893 "strange event for server socket",
43895 + srv_socket->sock->fd,
43897 return HANDLER_ERROR;
43900 /* accept()s at most 100 connections directly
43902 - * we jump out after 100 to give the waiting connections a chance */
43903 + * we jump out after 100 to give the waiting connections a chance */
43904 for (loops = 0; loops < 100 && NULL != (con = connection_accept(srv, srv_socket)); loops++) {
43908 connection_state_machine(srv, con);
43911 switch(r = plugins_call_handle_joblist(srv, con)) {
43912 case HANDLER_FINISHED:
43913 case HANDLER_GO_ON:
43914 @@ -72,18 +73,18 @@
43916 int is_unix_domain_socket = 0;
43920 #ifdef SO_ACCEPTFILTER
43921 struct accept_filter_arg afa;
43926 WORD wVersionRequested;
43931 wVersionRequested = MAKEWORD( 2, 2 );
43934 err = WSAStartup( wVersionRequested, &wsaData );
43936 /* Tell the user that we could not find a usable */
43937 @@ -91,37 +92,37 @@
43943 srv_socket = calloc(1, sizeof(*srv_socket));
43944 - srv_socket->fd = -1;
43946 + srv_socket->sock = iosocket_init();
43948 srv_socket->srv_token = buffer_init();
43949 buffer_copy_string_buffer(srv_socket->srv_token, host_token);
43953 buffer_copy_string_buffer(b, host_token);
43960 if (NULL == (sp = strrchr(b->ptr, ':'))) {
43961 log_error_write(srv, __FILE__, __LINE__, "sb", "value of $SERVER[\"socket\"] has to be \"ip:port\".", b);
43971 /* check for [ and ] */
43972 if (b->ptr[0] == '[' && *(sp-1) == ']') {
43984 port = strtol(sp, NULL, 10);
43986 if (host[0] == '/') {
43987 @@ -129,18 +130,18 @@
43988 is_unix_domain_socket = 1;
43989 } else if (port == 0 || port > 65535) {
43990 log_error_write(srv, __FILE__, __LINE__, "sd", "port out of range:", port);
43997 if (*host == '\0') host = NULL;
43999 if (is_unix_domain_socket) {
44000 #ifdef HAVE_SYS_UN_H
44002 srv_socket->addr.plain.sa_family = AF_UNIX;
44004 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44006 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, 0))) {
44007 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44010 @@ -154,32 +155,32 @@
44013 srv_socket->addr.plain.sa_family = AF_INET6;
44015 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44017 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44018 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44021 srv_socket->use_ipv6 = 1;
44025 - if (srv_socket->fd == -1) {
44027 + if (srv_socket->sock->fd == -1) {
44028 srv_socket->addr.plain.sa_family = AF_INET;
44029 - if (-1 == (srv_socket->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44030 + if (-1 == (srv_socket->sock->fd = socket(srv_socket->addr.plain.sa_family, SOCK_STREAM, IPPROTO_TCP))) {
44031 log_error_write(srv, __FILE__, __LINE__, "ss", "socket failed:", strerror(errno));
44038 - srv->cur_fds = srv_socket->fd;
44040 + srv->cur_fds = srv_socket->sock->fd;
44043 - if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44044 + if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
44045 log_error_write(srv, __FILE__, __LINE__, "ss", "socketsockopt failed:", strerror(errno));
44050 switch(srv_socket->addr.plain.sa_family) {
44053 @@ -190,23 +191,23 @@
44055 struct addrinfo hints, *res;
44059 memset(&hints, 0, sizeof(hints));
44062 hints.ai_family = AF_INET6;
44063 hints.ai_socktype = SOCK_STREAM;
44064 hints.ai_protocol = IPPROTO_TCP;
44067 if (0 != (r = getaddrinfo(host, NULL, &hints, &res))) {
44068 - log_error_write(srv, __FILE__, __LINE__,
44069 - "sssss", "getaddrinfo failed: ",
44070 + log_error_write(srv, __FILE__, __LINE__,
44071 + "sssss", "getaddrinfo failed: ",
44072 gai_strerror(r), "'", host, "'");
44079 memcpy(&(srv_socket->addr), res->ai_addr, res->ai_addrlen);
44084 srv_socket->addr.ipv6.sin6_port = htons(port);
44085 @@ -221,33 +222,34 @@
44087 struct hostent *he;
44088 if (NULL == (he = gethostbyname(host))) {
44089 - log_error_write(srv, __FILE__, __LINE__,
44090 - "sds", "gethostbyname failed: ",
44091 + log_error_write(srv, __FILE__, __LINE__,
44092 + "sds", "gethostbyname failed: ",
44098 if (he->h_addrtype != AF_INET) {
44099 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-type != AF_INET: ", he->h_addrtype);
44104 if (he->h_length != sizeof(struct in_addr)) {
44105 log_error_write(srv, __FILE__, __LINE__, "sd", "addr-length != sizeof(in_addr): ", he->h_length);
44110 memcpy(&(srv_socket->addr.ipv4.sin_addr.s_addr), he->h_addr_list[0], he->h_length);
44112 srv_socket->addr.ipv4.sin_port = htons(port);
44115 addr_len = sizeof(struct sockaddr_in);
44121 srv_socket->addr.un.sun_family = AF_UNIX;
44122 strcpy(srv_socket->addr.un.sun_path, host);
44126 addr_len = SUN_LEN(&srv_socket->addr.un);
44128 @@ -256,11 +258,11 @@
44131 /* check if the socket exists and try to connect to it. */
44132 - if (-1 != (fd = connect(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44133 + if (-1 != (fd = connect(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len))) {
44136 - log_error_write(srv, __FILE__, __LINE__, "ss",
44137 - "server socket is still in use:",
44138 + log_error_write(srv, __FILE__, __LINE__, "ss",
44139 + "server socket is still in use:",
44143 @@ -275,88 +277,89 @@
44147 - log_error_write(srv, __FILE__, __LINE__, "sds",
44148 - "testing socket failed:",
44149 + log_error_write(srv, __FILE__, __LINE__, "sds",
44150 + "testing socket failed:",
44151 host, strerror(errno));
44165 - if (0 != bind(srv_socket->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44167 + if (0 != bind(srv_socket->sock->fd, (struct sockaddr *) &(srv_socket->addr), addr_len)) {
44168 switch(srv_socket->addr.plain.sa_family) {
44170 - log_error_write(srv, __FILE__, __LINE__, "sds",
44171 - "can't bind to socket:",
44172 + log_error_write(srv, __FILE__, __LINE__, "sds",
44173 + "can't bind to socket:",
44174 host, strerror(errno));
44177 - log_error_write(srv, __FILE__, __LINE__, "ssds",
44178 - "can't bind to port:",
44179 + log_error_write(srv, __FILE__, __LINE__, "ssds",
44180 + "can't bind to port:",
44181 host, port, strerror(errno));
44187 - if (-1 == listen(srv_socket->fd, 128 * 8)) {
44189 + if (-1 == listen(srv_socket->sock->fd, 128 * 8)) {
44190 log_error_write(srv, __FILE__, __LINE__, "ss", "listen failed: ", strerror(errno));
44197 if (srv->ssl_is_init == 0) {
44198 SSL_load_error_strings();
44199 SSL_library_init();
44200 srv->ssl_is_init = 1;
44203 if (0 == RAND_status()) {
44204 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44205 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44206 "not enough entropy in the pool");
44212 if (NULL == (s->ssl_ctx = SSL_CTX_new(SSLv23_server_method()))) {
44213 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44214 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44215 ERR_error_string(ERR_get_error(), NULL));
44220 if (buffer_is_empty(s->ssl_pemfile)) {
44221 log_error_write(srv, __FILE__, __LINE__, "s", "ssl.pemfile has to be set");
44226 if (!buffer_is_empty(s->ssl_ca_file)) {
44227 if (1 != SSL_CTX_load_verify_locations(s->ssl_ctx, s->ssl_ca_file->ptr, NULL)) {
44228 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44229 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44230 ERR_error_string(ERR_get_error(), NULL), s->ssl_ca_file);
44236 if (SSL_CTX_use_certificate_file(s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44237 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44238 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44239 ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44244 if (SSL_CTX_use_PrivateKey_file (s->ssl_ctx, s->ssl_pemfile->ptr, SSL_FILETYPE_PEM) < 0) {
44245 - log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44246 + log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
44247 ERR_error_string(ERR_get_error(), NULL), s->ssl_pemfile);
44252 if (SSL_CTX_check_private_key(s->ssl_ctx) != 1) {
44253 - log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44254 + log_error_write(srv, __FILE__, __LINE__, "sssb", "SSL:",
44255 "Private key does not match the certificate public key, reason:",
44256 ERR_error_string(ERR_get_error(), NULL),
44258 @@ -364,15 +367,15 @@
44260 srv_socket->ssl_ctx = s->ssl_ctx;
44264 buffer_free(srv_socket->srv_token);
44270 - log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44272 + log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
44273 "ssl requested but openssl support is not compiled in");
44279 @@ -383,17 +386,16 @@
44281 memset(&afa, 0, sizeof(afa));
44282 strcpy(afa.af_name, "httpready");
44283 - if (setsockopt(srv_socket->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44284 + if (setsockopt(srv_socket->sock->fd, SOL_SOCKET, SO_ACCEPTFILTER, &afa, sizeof(afa)) < 0) {
44285 if (errno != ENOENT) {
44286 log_error_write(srv, __FILE__, __LINE__, "ss", "can't set accept-filter 'httpready': ", strerror(errno));
44293 srv_socket->is_ssl = s->is_ssl;
44294 - srv_socket->fde_ndx = -1;
44297 if (srv->srv_sockets.size == 0) {
44298 srv->srv_sockets.size = 4;
44299 srv->srv_sockets.used = 0;
44300 @@ -402,11 +404,10 @@
44301 srv->srv_sockets.size += 4;
44302 srv->srv_sockets.ptr = realloc(srv->srv_sockets.ptr, srv->srv_sockets.size * sizeof(server_socket));
44306 srv->srv_sockets.ptr[srv->srv_sockets.used++] = srv_socket;
44314 @@ -414,45 +415,60 @@
44316 for (i = 0; i < srv->srv_sockets.used; i++) {
44317 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44319 - if (srv_socket->fd != -1) {
44321 + if (srv_socket->sock->fd != -1) {
44322 /* check if server fd are already registered */
44323 - if (srv_socket->fde_ndx != -1) {
44324 - fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
44325 - fdevent_unregister(srv->ev, srv_socket->fd);
44326 + if (srv_socket->sock->fde_ndx != -1) {
44327 + fdevent_event_del(srv->ev, srv_socket->sock);
44328 + fdevent_unregister(srv->ev, srv_socket->sock);
44331 - close(srv_socket->fd);
44333 + closesocket(srv_socket->sock->fd);
44336 + if (srv_socket->is_ssl) {
44337 +#ifdef USE_OPENSSL
44338 + SSL_CTX_free(srv_socket->ssl_ctx);
44343 + iosocket_free(srv_socket->sock);
44345 buffer_free(srv_socket->srv_token);
44352 +#ifdef USE_OPENSSL
44353 + ERR_free_strings();
44355 free(srv->srv_sockets.ptr);
44362 NETWORK_BACKEND_UNSET,
44364 NETWORK_BACKEND_WRITE,
44365 NETWORK_BACKEND_WRITEV,
44366 NETWORK_BACKEND_LINUX_SENDFILE,
44367 NETWORK_BACKEND_FREEBSD_SENDFILE,
44368 - NETWORK_BACKEND_SOLARIS_SENDFILEV
44369 + NETWORK_BACKEND_SOLARIS_SENDFILEV,
44371 + NETWORK_BACKEND_WIN32_SEND,
44372 + NETWORK_BACKEND_WIN32_TRANSMITFILE,
44373 } network_backend_t;
44375 int network_init(server *srv) {
44378 network_backend_t backend;
44381 - network_backend_t nb;
44382 - const char *name;
44383 - } network_backends[] = {
44386 + network_backend_t nb;
44387 + const char *name;
44388 + } network_backends[] = {
44389 /* lowest id wins */
44390 #if defined USE_LINUX_SENDFILE
44391 { NETWORK_BACKEND_LINUX_SENDFILE, "linux-sendfile" },
44392 @@ -466,21 +482,30 @@
44393 #if defined USE_WRITEV
44394 { NETWORK_BACKEND_WRITEV, "writev" },
44396 +#if defined USE_WRITE
44397 { NETWORK_BACKEND_WRITE, "write" },
44399 +#if defined USE_WIN32_TRANSMITFILE
44400 + { NETWORK_BACKEND_WIN32_TRANSMITFILE, "win32-transmitfile" },
44402 +#if defined USE_WIN32_SEND
44403 + { NETWORK_BACKEND_WIN32_SEND, "win32-send" },
44406 { NETWORK_BACKEND_UNSET, NULL }
44413 buffer_copy_string_buffer(b, srv->srvconf.bindhost);
44414 buffer_append_string(b, ":");
44415 buffer_append_long(b, srv->srvconf.port);
44418 if (0 != network_server_init(srv, b, srv->config_storage[0])) {
44425 srv->network_ssl_backend_write = network_write_chunkqueue_openssl;
44427 @@ -500,54 +525,80 @@
44428 if (NULL == network_backends[i].name) {
44429 /* we don't know it */
44431 - log_error_write(srv, __FILE__, __LINE__, "sb",
44432 - "server.network-backend has a unknown value:",
44433 + log_error_write(srv, __FILE__, __LINE__, "sb",
44434 + "server.network-backend has a unknown value:",
44435 srv->srvconf.network_backend);
44441 +#define SET_NETWORK_BACKEND(read, write) \
44442 + srv->network_backend_write = network_write_chunkqueue_##write;\
44443 + srv->network_backend_read = network_read_chunkqueue_##read
44445 +#define SET_NETWORK_BACKEND_SSL(read, write) \
44446 + srv->network_ssl_backend_write = network_write_chunkqueue_##write;\
44447 + srv->network_ssl_backend_read = network_read_chunkqueue_##read
44451 +#ifdef USE_WIN32_SEND
44452 + case NETWORK_BACKEND_WIN32_SEND:
44453 + SET_NETWORK_BACKEND(win32recv, win32send);
44455 +#ifdef USE_WIN32_TRANSMITFILE
44456 + case NETWORK_BACKEND_WIN32_TRANSMITFILE:
44457 + SET_NETWORK_BACKEND(win32recv, win32transmitfile);
44463 case NETWORK_BACKEND_WRITE:
44464 - srv->network_backend_write = network_write_chunkqueue_write;
44465 + SET_NETWORK_BACKEND(read, write);
44469 case NETWORK_BACKEND_WRITEV:
44470 - srv->network_backend_write = network_write_chunkqueue_writev;
44471 + SET_NETWORK_BACKEND(read, writev);
44474 #ifdef USE_LINUX_SENDFILE
44475 case NETWORK_BACKEND_LINUX_SENDFILE:
44476 - srv->network_backend_write = network_write_chunkqueue_linuxsendfile;
44477 + SET_NETWORK_BACKEND(read, linuxsendfile);
44480 #ifdef USE_FREEBSD_SENDFILE
44481 case NETWORK_BACKEND_FREEBSD_SENDFILE:
44482 - srv->network_backend_write = network_write_chunkqueue_freebsdsendfile;
44483 + SET_NETWORK_BACKEND(read, freebsdsendfile);
44486 #ifdef USE_SOLARIS_SENDFILEV
44487 case NETWORK_BACKEND_SOLARIS_SENDFILEV:
44488 - srv->network_backend_write = network_write_chunkqueue_solarissendfilev;
44489 + SET_NETWORK_BACKEND(read, solarissendfilev);
44496 +#ifdef USE_OPENSSL
44497 + SET_NETWORK_BACKEND_SSL(openssl, openssl);
44500 /* check for $SERVER["socket"] */
44501 for (i = 1; i < srv->config_context->used; i++) {
44502 data_config *dc = (data_config *)srv->config_context->data[i];
44503 specific_config *s = srv->config_storage[i];
44507 /* not our stage */
44508 if (COMP_SERVER_SOCKET != dc->comp) continue;
44511 if (dc->cond != CONFIG_COND_EQ) {
44512 log_error_write(srv, __FILE__, __LINE__, "s", "only == is allowed for $SERVER[\"socket\"].");
44518 @@ -558,36 +609,47 @@
44524 if (j == srv->srv_sockets.used) {
44525 if (0 != network_server_init(srv, dc->string, s)) return -1;
44533 int network_register_fdevents(server *srv) {
44536 if (-1 == fdevent_reset(srv->ev)) {
44540 /* register fdevents after reset */
44541 for (i = 0; i < srv->srv_sockets.used; i++) {
44542 server_socket *srv_socket = srv->srv_sockets.ptr[i];
44544 - fdevent_register(srv->ev, srv_socket->fd, network_server_handle_fdevent, srv_socket);
44545 - fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
44546 + fdevent_register(srv->ev, srv_socket->sock, network_server_handle_fdevent, srv_socket);
44547 + fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
44552 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44554 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44555 + server_socket *srv_socket = con->srv_socket;
44557 + if (srv_socket->is_ssl) {
44558 +#ifdef USE_OPENSSL
44559 + return srv->network_ssl_backend_read(srv, con, con->sock, cq);
44561 + return NETWORK_STATUS_FATAL_ERROR;
44564 + return srv->network_backend_read(srv, con, con->sock, cq);
44568 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *cq) {
44569 + network_status_t ret = NETWORK_STATUS_UNSET;
44575 server_socket *srv_socket = con->srv_socket;
44576 @@ -600,37 +662,42 @@
44577 joblist_append(srv, con);
44583 written = cq->bytes_out;
44587 /* Linux: put a cork into the socket as we want to combine the write() calls
44588 * but only if we really have multiple chunks
44590 if (cq->first && cq->first->next) {
44592 - setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44593 + setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44598 if (srv_socket->is_ssl) {
44600 - ret = srv->network_ssl_backend_write(srv, con, con->ssl, cq);
44601 + ret = srv->network_ssl_backend_write(srv, con, con->sock, cq);
44604 - ret = srv->network_backend_write(srv, con, con->fd, cq);
44605 + ret = srv->network_backend_write(srv, con, con->sock, cq);
44611 + case NETWORK_STATUS_WAIT_FOR_EVENT:
44612 + case NETWORK_STATUS_SUCCESS:
44613 chunkqueue_remove_finished_chunks(cq);
44614 - ret = chunkqueue_is_empty(cq) ? 0 : 1;
44625 - setsockopt(con->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44626 + setsockopt(con->sock->fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
44630 @@ -639,13 +706,13 @@
44631 con->bytes_written_cur_second += written;
44633 *(con->conf.global_bytes_per_second_cnt_ptr) += written;
44636 if (con->conf.kbytes_per_second &&
44637 (con->bytes_written_cur_second > con->conf.kbytes_per_second * 1024)) {
44638 /* we reached the traffic limit */
44640 con->traffic_limit_reached = 1;
44641 joblist_append(srv, con);
44646 --- ../lighttpd-1.4.11/src/network.h 2005-08-11 01:26:42.000000000 +0300
44647 +++ lighttpd-1.4.12/src/network.h 2006-07-18 13:03:40.000000000 +0300
44650 #include "server.h"
44652 -int network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
44653 +network_status_t network_write_chunkqueue(server *srv, connection *con, chunkqueue *c);
44654 +network_status_t network_read_chunkqueue(server *srv, connection *con, chunkqueue *c);
44656 int network_init(server *srv);
44657 int network_close(server *srv);
44659 int network_register_fdevents(server *srv);
44660 +handler_t network_server_handle_fdevent(void *s, void *context, int revents);
44663 --- ../lighttpd-1.4.11/src/network_backends.h 2005-10-24 15:13:51.000000000 +0300
44664 +++ lighttpd-1.4.12/src/network_backends.h 2006-07-18 13:03:40.000000000 +0300
44665 @@ -43,16 +43,47 @@
44666 # define USE_AIX_SENDFILE
44670 +* unix can use read/write or recv/send on sockets
44671 +* win32 only recv/send
44674 +# define USE_WIN32_SEND
44675 +/* wait for async-io support
44676 +# define USE_WIN32_TRANSMITFILE
44679 +# define USE_WRITE
44683 +#include "network.h"
44685 +#define NETWORK_BACKEND_WRITE_CHUNK(x) \
44686 + network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq, chunk *c)
44688 +#define NETWORK_BACKEND_WRITE(x) \
44689 + network_status_t network_write_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
44690 +#define NETWORK_BACKEND_READ(x) \
44691 + network_status_t network_read_chunkqueue_##x(server *srv, connection *con, iosocket *sock, chunkqueue *cq)
44693 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem);
44695 +NETWORK_BACKEND_WRITE(write);
44696 +NETWORK_BACKEND_WRITE(writev);
44697 +NETWORK_BACKEND_WRITE(linuxsendfile);
44698 +NETWORK_BACKEND_WRITE(freebsdsendfile);
44699 +NETWORK_BACKEND_WRITE(solarissendfilev);
44701 +NETWORK_BACKEND_WRITE(win32transmitfile);
44702 +NETWORK_BACKEND_WRITE(win32send);
44704 +NETWORK_BACKEND_READ(read);
44705 +NETWORK_BACKEND_READ(win32recv);
44707 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq);
44708 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq);
44709 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
44710 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq);
44711 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq);
44713 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq);
44714 +NETWORK_BACKEND_WRITE(openssl);
44715 +NETWORK_BACKEND_READ(openssl);
44719 --- ../lighttpd-1.4.11/src/network_freebsd_sendfile.c 2005-10-22 12:28:18.000000000 +0300
44720 +++ lighttpd-1.4.12/src/network_freebsd_sendfile.c 2006-07-16 00:26:04.000000000 +0300
44721 @@ -26,142 +26,61 @@
44724 # ifdef __FreeBSD__
44725 -/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
44726 +/* FreeBSD 4.7, 4.9 defined it in sys/uio.h only if _KERNEL is specified */
44727 # define UIO_MAXIOV 1024
44731 -int network_write_chunkqueue_freebsdsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
44732 +NETWORK_BACKEND_WRITE(freebsdsendfile) {
44734 size_t chunks_written = 0;
44737 for(c = cq->first; c; c = c->next, chunks_written++) {
44738 int chunk_finished = 0;
44740 + network_status_t ret;
44743 - case MEM_CHUNK: {
44748 - size_t num_chunks, i;
44749 - struct iovec chunks[UIO_MAXIOV];
44751 - size_t num_bytes = 0;
44753 - /* we can't send more then SSIZE_MAX bytes in one chunk */
44755 - /* build writev list
44757 - * 1. limit: num_chunks < UIO_MAXIOV
44758 - * 2. limit: num_bytes < SSIZE_MAX
44760 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
44762 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
44763 - if (tc->mem->used == 0) {
44764 - chunks[i].iov_base = tc->mem->ptr;
44765 - chunks[i].iov_len = 0;
44767 - offset = tc->mem->ptr + tc->offset;
44768 - toSend = tc->mem->used - 1 - tc->offset;
44770 - chunks[i].iov_base = offset;
44772 - /* protect the return value of writev() */
44773 - if (toSend > SSIZE_MAX ||
44774 - num_bytes + toSend > SSIZE_MAX) {
44775 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
44777 - num_chunks = i + 1;
44780 - chunks[i].iov_len = toSend;
44783 - num_bytes += toSend;
44787 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
44797 - log_error_write(srv, __FILE__, __LINE__, "ssd",
44798 - "writev failed:", strerror(errno), fd);
44803 + ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
44808 - /* check which chunks have been written */
44809 - cq->bytes_out += r;
44811 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
44812 - if (r >= (ssize_t)chunks[i].iov_len) {
44814 - r -= chunks[i].iov_len;
44815 - tc->offset += chunks[i].iov_len;
44817 - if (chunk_finished) {
44818 - /* skip the chunks from further touches */
44819 - chunks_written++;
44822 - /* chunks_written + c = c->next is done in the for()*/
44823 - chunk_finished++;
44826 - /* partially written */
44829 - chunk_finished = 0;
44833 + if (ret != NETWORK_STATUS_SUCCESS) {
44838 + chunk_finished = 1;
44845 stat_cache_entry *sce = NULL;
44849 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
44850 log_error_write(srv, __FILE__, __LINE__, "sb",
44851 strerror(errno), c->file.name);
44853 + return NETWORK_STATUS_FATAL_ERROR;
44857 offset = c->file.start + c->offset;
44858 /* limit the toSend to 2^31-1 bytes in a chunk */
44859 - toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
44860 + toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
44861 ((1 << 30) - 1) : c->file.length - c->offset;
44864 if (offset > sce->st.st_size) {
44865 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
44869 + return NETWORK_STATUS_FATAL_ERROR;
44873 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
44874 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
44878 + return NETWORK_STATUS_FATAL_ERROR;
44885 /* FreeBSD sendfile() */
44886 if (-1 == sendfile(ifd, fd, offset, toSend, NULL, &r, 0)) {
44888 @@ -169,39 +88,39 @@
44893 + return NETWORK_STATUS_CONNECTION_CLOSE;
44895 log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
44898 + return NETWORK_STATUS_FATAL_ERROR;
44905 cq->bytes_out += r;
44908 if (c->offset == c->file.length) {
44909 chunk_finished = 1;
44918 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
44925 if (!chunk_finished) {
44926 /* not finished yet */
44933 - return chunks_written;
44934 + return NETWORK_STATUS_SUCCESS;
44938 --- ../lighttpd-1.4.11/src/network_linux_sendfile.c 2006-02-15 20:02:36.000000000 +0200
44939 +++ lighttpd-1.4.12/src/network_linux_sendfile.c 2006-07-18 13:03:40.000000000 +0300
44940 @@ -26,122 +26,54 @@
44941 /* on linux 2.4.29 + debian/ubuntu we have crashes if this is enabled */
44942 #undef HAVE_POSIX_FADVISE
44944 -int network_write_chunkqueue_linuxsendfile(server *srv, connection *con, int fd, chunkqueue *cq) {
44946 +NETWORK_BACKEND_WRITE(linuxsendfile) {
44948 size_t chunks_written = 0;
44951 for(c = cq->first; c; c = c->next, chunks_written++) {
44952 int chunk_finished = 0;
44954 + network_status_t ret;
44957 - case MEM_CHUNK: {
44962 - size_t num_chunks, i;
44963 - struct iovec chunks[UIO_MAXIOV];
44965 - size_t num_bytes = 0;
44967 - /* we can't send more then SSIZE_MAX bytes in one chunk */
44969 - /* build writev list
44971 - * 1. limit: num_chunks < UIO_MAXIOV
44972 - * 2. limit: num_bytes < SSIZE_MAX
44974 - for (num_chunks = 0, tc = c;
44975 - tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV;
44976 - tc = tc->next, num_chunks++);
44978 - for (tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
44979 - if (tc->mem->used == 0) {
44980 - chunks[i].iov_base = tc->mem->ptr;
44981 - chunks[i].iov_len = 0;
44983 - offset = tc->mem->ptr + tc->offset;
44984 - toSend = tc->mem->used - 1 - tc->offset;
44986 - chunks[i].iov_base = offset;
44988 - /* protect the return value of writev() */
44989 - if (toSend > SSIZE_MAX ||
44990 - num_bytes + toSend > SSIZE_MAX) {
44991 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
44993 - num_chunks = i + 1;
44996 - chunks[i].iov_len = toSend;
44999 - num_bytes += toSend;
45003 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
45013 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45014 - "writev failed:", strerror(errno), fd);
45020 - /* check which chunks have been written */
45021 - cq->bytes_out += r;
45023 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
45025 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45026 - if (r >= (ssize_t)chunks[i].iov_len) {
45028 - r -= chunks[i].iov_len;
45029 - tc->offset += chunks[i].iov_len;
45031 + /* check which chunks are finished now */
45032 + for (tc = c; tc; tc = tc->next) {
45033 + /* finished the chunk */
45034 + if (tc->offset == tc->mem->used - 1) {
45035 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
45036 if (chunk_finished) {
45037 - /* skip the chunks from further touches */
45038 - chunks_written++;
45041 - /* chunks_written + c = c->next is done in the for()*/
45042 - chunk_finished++;
45043 + chunk_finished = 1;
45046 - /* partially written */
45049 - chunk_finished = 0;
45056 + if (ret != NETWORK_STATUS_SUCCESS) {
45066 stat_cache_entry *sce = NULL;
45069 offset = c->file.start + c->offset;
45070 /* limit the toSend to 2^31-1 bytes in a chunk */
45071 - toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45072 + toSend = c->file.length - c->offset > ((1 << 30) - 1) ?
45073 ((1 << 30) - 1) : c->file.length - c->offset;
45075 - /* open file if not already opened */
45077 + /* open file if not already opened */
45078 if (-1 == c->file.fd) {
45079 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
45080 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45086 @@ -151,14 +83,14 @@
45087 /* tell the kernel that we want to stream the file */
45088 if (-1 == posix_fadvise(c->file.fd, 0, 0, POSIX_FADV_SEQUENTIAL)) {
45089 if (ENOSYS != errno) {
45090 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45091 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45092 "posix_fadvise failed:", strerror(errno), c->file.fd);
45098 - if (-1 == (r = sendfile(fd, c->file.fd, &offset, toSend))) {
45099 + if (-1 == (r = sendfile(sock->fd, c->file.fd, &offset, toSend))) {
45103 @@ -166,11 +98,11 @@
45108 + return NETWORK_STATUS_CONNECTION_CLOSE;
45110 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45111 - "sendfile failed:", strerror(errno), fd);
45113 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45114 + "sendfile failed:", strerror(errno), sock->fd);
45115 + return NETWORK_STATUS_FATAL_ERROR;
45119 @@ -179,39 +111,39 @@
45121 * - the file shrinked -> error
45122 * - the remote side closed inbetween -> remote-close */
45125 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45126 /* file is gone ? */
45128 + return NETWORK_STATUS_FATAL_ERROR;
45131 if (offset > sce->st.st_size) {
45132 /* file shrinked, close the connection */
45134 + return NETWORK_STATUS_FATAL_ERROR;
45138 + return NETWORK_STATUS_CONNECTION_CLOSE;
45141 #ifdef HAVE_POSIX_FADVISE
45144 -#define M * 1024 K
45145 +#define M * 1024 K
45146 #define READ_AHEAD 4 M
45147 /* check if we need a new chunk */
45148 if ((c->offset & ~(READ_AHEAD - 1)) != ((c->offset + r) & ~(READ_AHEAD - 1))) {
45149 /* tell the kernel that we want to stream the file */
45150 if (-1 == posix_fadvise(c->file.fd, (c->offset + r) & ~(READ_AHEAD - 1), READ_AHEAD, POSIX_FADV_NOREUSE)) {
45151 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45152 + log_error_write(srv, __FILE__, __LINE__, "ssd",
45153 "posix_fadvise failed:", strerror(errno), c->file.fd);
45161 cq->bytes_out += r;
45164 if (c->offset == c->file.length) {
45165 chunk_finished = 1;
45167 @@ -222,24 +154,24 @@
45178 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45182 + return NETWORK_STATUS_FATAL_ERROR;
45186 if (!chunk_finished) {
45187 /* not finished yet */
45191 + return NETWORK_STATUS_WAIT_FOR_EVENT;
45195 - return chunks_written;
45196 + return NETWORK_STATUS_SUCCESS;
45200 --- ../lighttpd-1.4.11/src/network_openssl.c 2005-11-17 14:53:29.000000000 +0200
45201 +++ lighttpd-1.4.12/src/network_openssl.c 2006-07-18 13:03:40.000000000 +0300
45202 @@ -23,17 +23,87 @@
45204 #include "stat_cache.h"
45206 -# include <openssl/ssl.h>
45207 -# include <openssl/err.h>
45208 +# include <openssl/ssl.h>
45209 +# include <openssl/err.h>
45211 -int network_write_chunkqueue_openssl(server *srv, connection *con, SSL *ssl, chunkqueue *cq) {
45212 +NETWORK_BACKEND_READ(openssl) {
45216 + b = chunkqueue_get_append_buffer(cq);
45217 + buffer_prepare_copy(b, 8192);
45218 + len = SSL_read(sock->ssl, b->ptr, b->size - 1);
45220 + log_error_write(srv, __FILE__, __LINE__, "so", "SSL:", len);
45225 + switch ((r = SSL_get_error(sock->ssl, len))) {
45226 + case SSL_ERROR_WANT_READ:
45227 + return NETWORK_STATUS_WAIT_FOR_EVENT;
45228 + case SSL_ERROR_SYSCALL:
45230 + * man SSL_get_error()
45232 + * SSL_ERROR_SYSCALL
45233 + * Some I/O error occurred. The OpenSSL error queue may contain more
45234 + * information on the error. If the error queue is empty (i.e.
45235 + * ERR_get_error() returns 0), ret can be used to find out more about
45236 + * the error: If ret == 0, an EOF was observed that violates the
45237 + * protocol. If ret == -1, the underlying BIO reported an I/O error
45238 + * (for socket I/O on Unix systems, consult errno for details).
45241 + while((ssl_err = ERR_get_error())) {
45242 + /* get all errors from the error-queue */
45243 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45244 + r, ERR_error_string(ssl_err, NULL));
45249 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45251 + strerror(errno));
45256 + case SSL_ERROR_ZERO_RETURN:
45257 + /* clean shutdown on the remote side */
45260 + /* FIXME: later */
45263 + /* fall thourgh */
45265 + while((ssl_err = ERR_get_error())) {
45266 + /* get all errors from the error-queue */
45267 + log_error_write(srv, __FILE__, __LINE__, "sds", "SSL:",
45268 + r, ERR_error_string(ssl_err, NULL));
45276 + b->ptr[b->used - 1] = '\0';
45278 + return NETWORK_STATUS_SUCCESS;
45282 +NETWORK_BACKEND_WRITE(openssl) {
45285 size_t chunks_written = 0;
45287 /* this is a 64k sendbuffer
45289 - * it has to stay at the same location all the time to satisfy the needs
45290 + * it has to stay at the same location all the time to satisfy the needs
45291 * of SSL_write to pass the SAME parameter in case of a _WANT_WRITE
45293 * the buffer is allocated once, is NOT realloced and is NOT freed at shutdown
45294 @@ -43,59 +113,61 @@
45295 * In reality we would like to use mmap() but we don't have a guarantee that
45296 * we get the same mmap() address for each call. On openbsd the mmap() address
45298 - * That means either we keep the mmap() open or we do a read() into a
45299 - * constant buffer
45300 + * That means either we keep the mmap() open or we do a read() into a
45301 + * constant buffer
45303 #define LOCAL_SEND_BUFSIZE (64 * 1024)
45304 static char *local_send_buffer = NULL;
45306 /* the remote side closed the connection before without shutdown request
45310 * if keep-alive is disabled */
45312 if (con->keep_alive == 0) {
45313 - SSL_set_shutdown(ssl, SSL_RECEIVED_SHUTDOWN);
45314 + SSL_set_shutdown(sock->ssl, SSL_RECEIVED_SHUTDOWN);
45317 for(c = cq->first; c; c = c->next) {
45318 int chunk_finished = 0;
45329 if (c->mem->used == 0) {
45330 chunk_finished = 1;
45335 offset = c->mem->ptr + c->offset;
45336 toSend = c->mem->used - 1 - c->offset;
45340 * SSL_write man-page
45344 * When an SSL_write() operation has to be repeated because of
45345 * SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, it must be
45346 * repeated with the same arguments.
45349 + * SSL_write(..., 0) return 0 which is handle as an error (Success)
45350 + * checking toSend and not calling SSL_write() is simpler
45353 - if ((r = SSL_write(ssl, offset, toSend)) <= 0) {
45355 + if (toSend != 0 && (r = SSL_write(sock->ssl, offset, toSend)) <= 0) {
45358 - switch ((ssl_r = SSL_get_error(ssl, r))) {
45359 + switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45360 case SSL_ERROR_WANT_WRITE:
45362 case SSL_ERROR_SYSCALL:
45363 /* perhaps we have error waiting in our error-queue */
45364 if (0 != (err = ERR_get_error())) {
45366 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45367 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45369 ERR_error_string(err, NULL));
45370 } while((err = ERR_get_error()));
45371 @@ -105,43 +177,43 @@
45375 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45376 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45382 /* neither error-queue nor errno ? */
45383 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45384 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45391 case SSL_ERROR_ZERO_RETURN:
45392 /* clean shutdown on the remote side */
45395 if (r == 0) return -2;
45400 while((err = ERR_get_error())) {
45401 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45402 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45404 ERR_error_string(err, NULL));
45412 cq->bytes_out += r;
45416 if (c->offset == (off_t)c->mem->used - 1) {
45417 chunk_finished = 1;
45424 @@ -150,7 +222,7 @@
45425 stat_cache_entry *sce = NULL;
45427 int write_wait = 0;
45430 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45431 log_error_write(srv, __FILE__, __LINE__, "sb",
45432 strerror(errno), c->file.name);
45433 @@ -164,13 +236,13 @@
45436 off_t offset = c->file.start + c->offset;
45437 - off_t toSend = c->file.length - c->offset;
45438 + off_t toSend = c->file.length - c->offset;
45440 if (toSend > LOCAL_SEND_BUFSIZE) toSend = LOCAL_SEND_BUFSIZE;
45443 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45444 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed:", strerror(errno));
45450 @@ -183,13 +255,13 @@
45453 s = local_send_buffer;
45458 - if ((r = SSL_write(ssl, s, toSend)) <= 0) {
45460 + if ((r = SSL_write(sock->ssl, s, toSend)) <= 0) {
45463 - switch ((ssl_r = SSL_get_error(ssl, r))) {
45464 + switch ((ssl_r = SSL_get_error(sock->ssl, r))) {
45465 case SSL_ERROR_WANT_WRITE:
45468 @@ -197,7 +269,7 @@
45469 /* perhaps we have error waiting in our error-queue */
45470 if (0 != (err = ERR_get_error())) {
45472 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45473 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45475 ERR_error_string(err, NULL));
45476 } while((err = ERR_get_error()));
45477 @@ -207,62 +279,62 @@
45481 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45482 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL:",
45488 /* neither error-queue nor errno ? */
45489 - log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45490 + log_error_write(srv, __FILE__, __LINE__, "sddds", "SSL (error):",
45497 case SSL_ERROR_ZERO_RETURN:
45498 /* clean shutdown on the remote side */
45501 if (r == 0) return -2;
45506 while((err = ERR_get_error())) {
45507 - log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45508 + log_error_write(srv, __FILE__, __LINE__, "sdds", "SSL:",
45510 ERR_error_string(err, NULL));
45518 cq->bytes_out += r;
45522 if (c->offset == c->file.length) {
45523 chunk_finished = 1;
45525 } while(!chunk_finished && !write_wait);
45531 log_error_write(srv, __FILE__, __LINE__, "s", "type not known");
45538 if (!chunk_finished) {
45539 /* not finished yet */
45549 - return chunks_written;
45550 + return NETWORK_STATUS_SUCCESS;
45554 --- ../lighttpd-1.4.11/src/network_solaris_sendfilev.c 2005-10-22 12:28:27.000000000 +0300
45555 +++ lighttpd-1.4.12/src/network_solaris_sendfilev.c 2006-07-16 00:26:04.000000000 +0300
45556 @@ -29,114 +29,34 @@
45560 - * a very simple sendfilev() interface for solaris which can be optimised a lot more
45561 + * a very simple sendfilev() interface for solaris which can be optimised a lot more
45562 * as solaris sendfilev() supports 'sending everythin in one syscall()'
45564 - * If you want such an interface and need the performance, just give me an account on
45567 + * If you want such an interface and need the performance, just give me an account on
45569 * - jan@kneschke.de
45573 -int network_write_chunkqueue_solarissendfilev(server *srv, connection *con, int fd, chunkqueue *cq) {
45574 +NETWORK_BACKEND_WRITE(solarissendfilev) {
45576 size_t chunks_written = 0;
45579 for(c = cq->first; c; c = c->next, chunks_written++) {
45580 int chunk_finished = 0;
45582 + network_status_t ret;
45585 - case MEM_CHUNK: {
45590 - size_t num_chunks, i;
45591 - struct iovec chunks[UIO_MAXIOV];
45594 - size_t num_bytes = 0;
45596 - /* we can't send more then SSIZE_MAX bytes in one chunk */
45598 - /* build writev list
45600 - * 1. limit: num_chunks < UIO_MAXIOV
45601 - * 2. limit: num_bytes < SSIZE_MAX
45603 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
45605 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
45606 - if (tc->mem->used == 0) {
45607 - chunks[i].iov_base = tc->mem->ptr;
45608 - chunks[i].iov_len = 0;
45610 - offset = tc->mem->ptr + tc->offset;
45611 - toSend = tc->mem->used - 1 - tc->offset;
45613 - chunks[i].iov_base = offset;
45615 - /* protect the return value of writev() */
45616 - if (toSend > SSIZE_MAX ||
45617 - num_bytes + toSend > SSIZE_MAX) {
45618 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
45620 - num_chunks = i + 1;
45623 - chunks[i].iov_len = toSend;
45626 - num_bytes += toSend;
45630 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
45640 - log_error_write(srv, __FILE__, __LINE__, "ssd",
45641 - "writev failed:", strerror(errno), fd);
45647 - /* check which chunks have been written */
45648 - cq->bytes_out += r;
45650 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
45651 - if (r >= (ssize_t)chunks[i].iov_len) {
45653 - r -= chunks[i].iov_len;
45654 - tc->offset += chunks[i].iov_len;
45656 - if (chunk_finished) {
45657 - /* skip the chunks from further touches */
45658 - chunks_written++;
45661 - /* chunks_written + c = c->next is done in the for()*/
45662 - chunk_finished++;
45665 - /* partially written */
45668 - chunk_finished = 0;
45673 + ret = network_write_chunkqueue_writev_mem(srv, con, fd, cq, &c);
45675 + if (ret != NETWORK_STATUS_SUCCESS) {
45680 + chunk_finished = 1;
45687 @@ -144,25 +64,25 @@
45688 sendfilevec_t fvec;
45689 stat_cache_entry *sce = NULL;
45693 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45694 log_error_write(srv, __FILE__, __LINE__, "sb",
45695 strerror(errno), c->file.name);
45700 offset = c->file.start + c->offset;
45701 toSend = c->file.length - c->offset;
45704 if (offset > sce->st.st_size) {
45705 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45711 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45712 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45718 @@ -170,44 +90,43 @@
45720 fvec.sfv_off = offset;
45721 fvec.sfv_len = toSend;
45724 /* Solaris sendfilev() */
45725 if (-1 == (r = sendfilev(fd, &fvec, 1, &written))) {
45726 if (errno != EAGAIN) {
45727 log_error_write(srv, __FILE__, __LINE__, "ssd", "sendfile: ", strerror(errno), errno);
45732 + return NETWORK_STATUS_FATAL_ERROR;
45741 c->offset += written;
45742 cq->bytes_out += written;
45745 if (c->offset == c->file.length) {
45746 chunk_finished = 1;
45754 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
45758 + return NETWORK_STATUS_FATAL_ERROR;
45762 if (!chunk_finished) {
45763 /* not finished yet */
45770 - return chunks_written;
45771 + return NETWORK_STATUS_SUCCESS;
45775 --- ../lighttpd-1.4.11/src/network_write.c 2005-10-22 12:27:56.000000000 +0300
45776 +++ lighttpd-1.4.12/src/network_write.c 2006-07-18 13:03:40.000000000 +0300
45778 #include <sys/types.h>
45779 #include <sys/stat.h>
45780 -#include <sys/time.h>
45784 -#include <unistd.h>
45785 #include <string.h>
45786 #include <stdlib.h>
45787 +#include <assert.h>
45789 #include "network.h"
45790 #include "fdevent.h"
45792 #include "stat_cache.h"
45794 #include "sys-socket.h"
45795 +#include "sys-files.h"
45797 #include "network_backends.h"
45801 #ifdef HAVE_SYS_FILIO_H
45802 # include <sys/filio.h>
45804 @@ -24,47 +27,92 @@
45805 #include <sys/resource.h>
45808 -int network_write_chunkqueue_write(server *srv, connection *con, int fd, chunkqueue *cq) {
45811 +* fill the chunkqueue will all the data that we can get
45813 +* this might be optimized into a readv() which uses the chunks
45816 +NETWORK_BACKEND_READ(read) {
45822 + * a EAGAIN is a successful read if we already read something to the chunkqueue
45824 + int read_something = 0;
45826 + /* use a chunk-size of 8k */
45830 + b = chunkqueue_get_append_buffer(cq);
45832 + buffer_prepare_copy(b, toread);
45834 + if (-1 == (r = read(sock->fd, b->ptr, toread))) {
45837 + /* remove the last chunk from the chunkqueue */
45838 + chunkqueue_remove_empty_last_chunk(cq);
45839 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_WAIT_FOR_EVENT;
45841 + ERROR("oops, read from fd=%d failed: %s (%d)", sock->fd, strerror(errno), errno );
45843 + return NETWORK_STATUS_FATAL_ERROR;
45848 + chunkqueue_remove_empty_last_chunk(cq);
45849 + return read_something ? NETWORK_STATUS_SUCCESS : NETWORK_STATUS_CONNECTION_CLOSE;
45852 + read_something = 1;
45855 + b->ptr[b->used++] = '\0';
45856 + } while (r == toread);
45858 + return NETWORK_STATUS_SUCCESS;
45861 +NETWORK_BACKEND_WRITE(write) {
45863 size_t chunks_written = 0;
45866 for(c = cq->first; c; c = c->next) {
45867 int chunk_finished = 0;
45877 if (c->mem->used == 0) {
45878 chunk_finished = 1;
45883 offset = c->mem->ptr + c->offset;
45884 toSend = c->mem->used - 1 - c->offset;
45886 - if ((r = send(fd, offset, toSend, 0)) < 0) {
45887 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
45892 - if ((r = write(fd, offset, toSend)) < 0) {
45893 - log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), fd);
45897 + if ((r = write(sock->fd, offset, toSend)) < 0) {
45898 + log_error_write(srv, __FILE__, __LINE__, "ssd", "write failed: ", strerror(errno), sock->fd);
45900 + return NETWORK_STATUS_FATAL_ERROR;
45906 cq->bytes_out += r;
45909 if (c->offset == (off_t)c->mem->used - 1) {
45910 chunk_finished = 1;
45917 @@ -76,93 +124,89 @@
45919 stat_cache_entry *sce = NULL;
45923 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
45924 log_error_write(srv, __FILE__, __LINE__, "sb",
45925 strerror(errno), c->file.name);
45927 + return NETWORK_STATUS_FATAL_ERROR;
45931 offset = c->file.start + c->offset;
45932 toSend = c->file.length - c->offset;
45935 if (offset > sce->st.st_size) {
45936 log_error_write(srv, __FILE__, __LINE__, "sb", "file was shrinked:", c->file.name);
45940 + return NETWORK_STATUS_FATAL_ERROR;
45943 if (-1 == (ifd = open(c->file.name->ptr, O_RDONLY))) {
45944 log_error_write(srv, __FILE__, __LINE__, "ss", "open failed: ", strerror(errno));
45948 + return NETWORK_STATUS_FATAL_ERROR;
45952 #if defined USE_MMAP
45953 if (MAP_FAILED == (p = mmap(0, sce->st.st_size, PROT_READ, MAP_SHARED, ifd, 0))) {
45954 log_error_write(srv, __FILE__, __LINE__, "ss", "mmap failed: ", strerror(errno));
45960 + return NETWORK_STATUS_FATAL_ERROR;
45964 - if ((r = write(fd, p + offset, toSend)) <= 0) {
45965 + if ((r = write(sock->fd, p + offset, toSend)) <= 0) {
45966 log_error_write(srv, __FILE__, __LINE__, "ss", "write failed: ", strerror(errno));
45967 munmap(p, sce->st.st_size);
45969 + return NETWORK_STATUS_FATAL_ERROR;
45973 munmap(p, sce->st.st_size);
45975 buffer_prepare_copy(srv->tmp_buf, toSend);
45978 lseek(ifd, offset, SEEK_SET);
45979 if (-1 == (toSend = read(ifd, srv->tmp_buf->ptr, toSend))) {
45980 log_error_write(srv, __FILE__, __LINE__, "ss", "read: ", strerror(errno));
45985 + return NETWORK_STATUS_FATAL_ERROR;
45989 - if (-1 == (r = send(fd, srv->tmp_buf->ptr, toSend, 0))) {
45990 + if (-1 == (r = send(sock->fd, srv->tmp_buf->ptr, toSend, 0))) {
45991 log_error_write(srv, __FILE__, __LINE__, "ss", "write: ", strerror(errno));
45995 + return NETWORK_STATUS_FATAL_ERROR;
45999 cq->bytes_out += r;
46002 if (c->offset == c->file.length) {
46003 chunk_finished = 1;
46012 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46016 + return NETWORK_STATUS_FATAL_ERROR;
46020 if (!chunk_finished) {
46021 /* not finished yet */
46031 - return chunks_written;
46032 + return NETWORK_STATUS_SUCCESS;
46036 -network_write_init(void) {
46037 - p->write = network_write_write_chunkset;
46040 --- ../lighttpd-1.4.11/src/network_writev.c 2006-02-15 01:02:36.000000000 +0200
46041 +++ lighttpd-1.4.12/src/network_writev.c 2006-07-18 13:03:40.000000000 +0300
46042 @@ -28,10 +28,10 @@
46045 # if defined(__FreeBSD__) || defined(__APPLE__) || defined(__NetBSD__)
46046 -/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46047 +/* FreeBSD 4.7 defines it in sys/uio.h only if _KERNEL is specified */
46048 # define UIO_MAXIOV 1024
46049 # elif defined(__sgi)
46050 -/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46051 +/* IRIX 6.5 has sysconf(_SC_IOV_MAX) which might return 512 or bigger */
46052 # define UIO_MAXIOV 512
46053 # elif defined(__sun)
46054 /* Solaris (and SunOS?) defines IOV_MAX instead */
46055 @@ -51,105 +51,121 @@
46056 #define LOCAL_BUFFERING 1
46059 -int network_write_chunkqueue_writev(server *srv, connection *con, int fd, chunkqueue *cq) {
46061 +NETWORK_BACKEND_WRITE_CHUNK(writev_mem) {
46066 + size_t num_chunks, i;
46067 + struct iovec chunks[UIO_MAXIOV];
46068 + chunk *tc; /* transfer chunks */
46069 + size_t num_bytes = 0;
46071 + /* we can't send more then SSIZE_MAX bytes in one chunk */
46073 + /* build writev list
46075 + * 1. limit: num_chunks < UIO_MAXIOV
46076 + * 2. limit: num_bytes < SSIZE_MAX
46078 + for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46080 + for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46081 + if (tc->mem->used == 0) {
46082 + chunks[i].iov_base = tc->mem->ptr;
46083 + chunks[i].iov_len = 0;
46085 + offset = tc->mem->ptr + tc->offset;
46086 + toSend = tc->mem->used - 1 - tc->offset;
46088 + chunks[i].iov_base = offset;
46090 + /* protect the return value of writev() */
46091 + if (toSend > SSIZE_MAX ||
46092 + num_bytes + toSend > SSIZE_MAX) {
46093 + chunks[i].iov_len = SSIZE_MAX - num_bytes;
46095 + num_chunks = i + 1;
46098 + chunks[i].iov_len = toSend;
46101 + num_bytes += toSend;
46105 + if ((r = writev(sock->fd, chunks, num_chunks)) < 0) {
46108 + return NETWORK_STATUS_WAIT_FOR_EVENT;
46110 + return NETWORK_STATUS_INTERRUPTED;
46113 + return NETWORK_STATUS_CONNECTION_CLOSE;
46115 + log_error_write(srv, __FILE__, __LINE__, "ssd",
46116 + "writev failed:", strerror(errno), sock->fd);
46118 + return NETWORK_STATUS_FATAL_ERROR;
46122 + cq->bytes_out += r;
46124 + /* check which chunks have been written */
46126 + for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46127 + if (r >= (ssize_t)chunks[i].iov_len) {
46129 + r -= chunks[i].iov_len;
46130 + tc->offset += chunks[i].iov_len;
46132 + /* partially written */
46136 + return NETWORK_STATUS_WAIT_FOR_EVENT;
46140 + /* all chunks have been pushed out */
46141 + return NETWORK_STATUS_SUCCESS;
46144 +NETWORK_BACKEND_WRITE(writev) {
46146 size_t chunks_written = 0;
46149 for(c = cq->first; c; c = c->next) {
46150 int chunk_finished = 0;
46152 + network_status_t ret;
46155 - case MEM_CHUNK: {
46160 - size_t num_chunks, i;
46161 - struct iovec chunks[UIO_MAXIOV];
46163 - size_t num_bytes = 0;
46165 - /* we can't send more then SSIZE_MAX bytes in one chunk */
46167 - /* build writev list
46169 - * 1. limit: num_chunks < UIO_MAXIOV
46170 - * 2. limit: num_bytes < SSIZE_MAX
46172 - for(num_chunks = 0, tc = c; tc && tc->type == MEM_CHUNK && num_chunks < UIO_MAXIOV; num_chunks++, tc = tc->next);
46174 - for(tc = c, i = 0; i < num_chunks; tc = tc->next, i++) {
46175 - if (tc->mem->used == 0) {
46176 - chunks[i].iov_base = tc->mem->ptr;
46177 - chunks[i].iov_len = 0;
46179 - offset = tc->mem->ptr + tc->offset;
46180 - toSend = tc->mem->used - 1 - tc->offset;
46182 - chunks[i].iov_base = offset;
46184 - /* protect the return value of writev() */
46185 - if (toSend > SSIZE_MAX ||
46186 - num_bytes + toSend > SSIZE_MAX) {
46187 - chunks[i].iov_len = SSIZE_MAX - num_bytes;
46189 - num_chunks = i + 1;
46192 - chunks[i].iov_len = toSend;
46195 - num_bytes += toSend;
46199 - if ((r = writev(fd, chunks, num_chunks)) < 0) {
46209 - log_error_write(srv, __FILE__, __LINE__, "ssd",
46210 - "writev failed:", strerror(errno), fd);
46216 - cq->bytes_out += r;
46218 + ret = network_write_chunkqueue_writev_mem(srv, con, sock, cq, c);
46220 - /* check which chunks have been written */
46222 - for(i = 0, tc = c; i < num_chunks; i++, tc = tc->next) {
46223 - if (r >= (ssize_t)chunks[i].iov_len) {
46225 - r -= chunks[i].iov_len;
46226 - tc->offset += chunks[i].iov_len;
46228 + /* check which chunks are finished now */
46229 + for (tc = c; tc; tc = tc->next) {
46230 + /* finished the chunk */
46231 + if (tc->offset == tc->mem->used - 1) {
46232 + /* skip the first c->next as that will be done by the c = c->next in the other for()-loop */
46233 if (chunk_finished) {
46234 - /* skip the chunks from further touches */
46235 - chunks_written++;
46238 - /* chunks_written + c = c->next is done in the for()*/
46239 - chunk_finished++;
46240 + chunk_finished = 1;
46243 - /* partially written */
46246 - chunk_finished = 0;
46253 + if (ret != NETWORK_STATUS_SUCCESS) {
46262 @@ -159,26 +175,26 @@
46263 #define KByte * 1024
46264 #define MByte * 1024 KByte
46265 #define GByte * 1024 MByte
46266 - const off_t we_want_to_mmap = 512 KByte;
46267 + const off_t we_want_to_mmap = 512 KByte;
46268 char *start = NULL;
46270 if (HANDLER_ERROR == stat_cache_get_entry(srv, con, c->file.name, &sce)) {
46271 log_error_write(srv, __FILE__, __LINE__, "sb",
46272 strerror(errno), c->file.name);
46274 + return NETWORK_STATUS_FATAL_ERROR;
46277 abs_offset = c->file.start + c->offset;
46280 if (abs_offset > sce->st.st_size) {
46281 - log_error_write(srv, __FILE__, __LINE__, "sb",
46282 + log_error_write(srv, __FILE__, __LINE__, "sb",
46283 "file was shrinked:", c->file.name);
46287 + return NETWORK_STATUS_FATAL_ERROR;
46290 - /* mmap the buffer
46292 + /* mmap the buffer
46294 * - new mmap as the we are at the end of the last one */
46295 if (c->file.mmap.start == MAP_FAILED ||
46296 abs_offset == (off_t)(c->file.mmap.offset + c->file.mmap.length)) {
46297 @@ -188,7 +204,7 @@
46298 * adaptive mem-mapping
46300 * we mmap() the whole file. If someone has alot large files and 32bit
46301 - * machine the virtual address area will be unrun and we will have a failing
46302 + * machine the virtual address area will be unrun and we will have a failing
46305 * only mmap 16M in one chunk and move the window as soon as we have finished
46306 @@ -234,8 +250,8 @@
46307 if (-1 == c->file.fd) { /* open the file if not already open */
46308 if (-1 == (c->file.fd = open(c->file.name->ptr, O_RDONLY))) {
46309 log_error_write(srv, __FILE__, __LINE__, "sbs", "open failed for:", c->file.name, strerror(errno));
46313 + return NETWORK_STATUS_FATAL_ERROR;
46316 fcntl(c->file.fd, F_SETFD, FD_CLOEXEC);
46317 @@ -245,10 +261,10 @@
46318 if (MAP_FAILED == (c->file.mmap.start = mmap(0, to_mmap, PROT_READ, MAP_SHARED, c->file.fd, c->file.mmap.offset))) {
46319 /* close it here, otherwise we'd have to set FD_CLOEXEC */
46321 - log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46322 + log_error_write(srv, __FILE__, __LINE__, "ssbd", "mmap failed:",
46323 strerror(errno), c->file.name, c->file.fd);
46326 + return NETWORK_STATUS_FATAL_ERROR;
46329 c->file.mmap.length = to_mmap;
46330 @@ -258,7 +274,7 @@
46331 #ifdef HAVE_MADVISE
46332 /* don't advise files < 64Kb */
46333 if (c->file.mmap.length > (64 KByte)) {
46334 - /* darwin 7 is returning EINVAL all the time and I don't know how to
46335 + /* darwin 7 is returning EINVAL all the time and I don't know how to
46336 * detect this at runtime.i
46338 * ignore the return value for now */
46339 @@ -274,12 +290,12 @@
46340 toSend = (c->file.mmap.offset + c->file.mmap.length) - (abs_offset);
46343 - log_error_write(srv, __FILE__, __LINE__, "soooo",
46344 + log_error_write(srv, __FILE__, __LINE__, "soooo",
46345 "toSend is negative:",
46347 c->file.mmap.length,
46349 - c->file.mmap.offset);
46350 + c->file.mmap.offset);
46351 assert(toSend < 0);
46354 @@ -289,7 +305,7 @@
46355 start = c->file.mmap.start;
46358 - if ((r = write(fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46359 + if ((r = write(sock->fd, start + (abs_offset - c->file.mmap.offset), toSend)) < 0) {
46363 @@ -297,18 +313,18 @@
46368 + return NETWORK_STATUS_CONNECTION_CLOSE;
46370 - log_error_write(srv, __FILE__, __LINE__, "ssd",
46371 - "write failed:", strerror(errno), fd);
46374 + log_error_write(srv, __FILE__, __LINE__, "ssd",
46375 + "write failed:", strerror(errno), sock->fd);
46377 + return NETWORK_STATUS_FATAL_ERROR;
46383 cq->bytes_out += r;
46386 if (c->offset == c->file.length) {
46387 chunk_finished = 1;
46389 @@ -318,26 +334,26 @@
46390 c->file.mmap.start = MAP_FAILED;
46400 log_error_write(srv, __FILE__, __LINE__, "ds", c, "type not known");
46404 + return NETWORK_STATUS_FATAL_ERROR;
46408 if (!chunk_finished) {
46409 /* not finished yet */
46419 - return chunks_written;
46420 + return NETWORK_STATUS_SUCCESS;
46424 --- ../lighttpd-1.4.11/src/plugin.c 2006-02-08 14:00:54.000000000 +0200
46425 +++ lighttpd-1.4.12/src/plugin.c 2006-07-16 00:26:04.000000000 +0300
46426 @@ -13,27 +13,27 @@
46427 #include <valgrind/valgrind.h>
46437 * if you change this enum to add a new callback, be sure
46438 * - that PLUGIN_FUNC_SIZEOF is the last entry
46439 * - that you add PLUGIN_TO_SLOT twice:
46440 - * 1. as callback-dispatcher
46441 + * 1. as callback-dispatcher
46442 * 2. in plugins_call_init()
46454 - PLUGIN_FUNC_HANDLE_URI_CLEAN,
46455 - PLUGIN_FUNC_HANDLE_URI_RAW,
46456 + PLUGIN_FUNC_HANDLE_URI_CLEAN,
46457 + PLUGIN_FUNC_HANDLE_URI_RAW,
46458 PLUGIN_FUNC_HANDLE_REQUEST_DONE,
46459 PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
46460 PLUGIN_FUNC_HANDLE_TRIGGER,
46461 @@ -44,38 +44,42 @@
46462 PLUGIN_FUNC_HANDLE_DOCROOT,
46463 PLUGIN_FUNC_HANDLE_PHYSICAL,
46464 PLUGIN_FUNC_CONNECTION_RESET,
46465 - PLUGIN_FUNC_INIT,
46466 + PLUGIN_FUNC_INIT,
46467 PLUGIN_FUNC_CLEANUP,
46468 PLUGIN_FUNC_SET_DEFAULTS,
46474 static plugin *plugin_init(void) {
46478 p = calloc(1, sizeof(*p));
46481 + p->required_plugins = array_init();
46486 static void plugin_free(plugin *p) {
46487 int use_dlclose = 1;
46488 if (p->name) buffer_free(p->name);
46490 + array_free(p->required_plugins);
46491 #ifdef HAVE_VALGRIND_VALGRIND_H
46492 /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
46495 #ifndef LIGHTTPD_STATIC
46496 - if (use_dlclose && p->lib) {
46498 + if (use_dlclose && p->lib) {
46500 FreeLibrary(p->lib);
46511 @@ -89,17 +93,17 @@
46512 srv->plugins.size += 4;
46513 srv->plugins.ptr = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
46517 ps = srv->plugins.ptr;
46518 ps[srv->plugins.used++] = p;
46533 #ifdef LIGHTTPD_STATIC
46534 @@ -121,30 +125,35 @@
46536 int plugins_load(server *srv) {
46541 int (*init)(plugin *pl);
46549 for (i = 0; i < srv->srvconf.modules->used; i++) {
46550 data_string *d = (data_string *)srv->srvconf.modules->data[i];
46551 char *modules = d->value->ptr;
46554 buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
46556 buffer_append_string(srv->tmp_buf, "/");
46557 buffer_append_string(srv->tmp_buf, modules);
46558 -#if defined(__WIN32) || defined(__CYGWIN__)
46559 +#if defined(_WIN32) || defined(__CYGWIN__)
46560 buffer_append_string(srv->tmp_buf, ".dll");
46562 buffer_append_string(srv->tmp_buf, ".so");
46569 if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
46572 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
46573 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
46574 FORMAT_MESSAGE_FROM_SYSTEM,
46577 @@ -152,36 +161,36 @@
46578 (LPTSTR) &lpMsgBuf,
46581 - log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
46582 + log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
46583 lpMsgBuf, srv->tmp_buf);
46594 if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_LAZY))) {
46595 - log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
46596 + log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
46597 srv->tmp_buf, dlerror());
46608 buffer_reset(srv->tmp_buf);
46609 buffer_copy_string(srv->tmp_buf, modules);
46610 buffer_append_string(srv->tmp_buf, "_plugin_init");
46614 init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
46616 if (init == NULL) {
46619 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
46620 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
46621 FORMAT_MESSAGE_FROM_SYSTEM,
46624 @@ -190,7 +199,7 @@
46627 log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
46633 @@ -203,24 +212,43 @@
46635 if ((error = dlerror()) != NULL) {
46636 log_error_write(srv, __FILE__, __LINE__, "s", error);
46646 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin init failed" );
46653 log_error_write(srv, __FILE__, __LINE__, "ss", modules, "plugin loaded" );
46655 + /* check if the required plugin is loaded */
46656 + for (k = 0; k < p->required_plugins->used; k++) {
46657 + data_string *req = (data_string *)p->required_plugins->data[k];
46659 + for (j = 0; j < i; j++) {
46660 + data_string *mod = (data_string *)srv->srvconf.modules->data[j];
46662 + if (buffer_is_equal(req->value, mod->value)) break;
46667 + log_error_write(srv, __FILE__, __LINE__, "ssbs", modules, "failed to load. required plugin", req->value, "was not loaded" );
46674 plugins_register(srv, p);
46681 @@ -253,8 +281,8 @@
46685 - * plugins that use
46687 + * plugins that use
46690 * - connection *con
46691 * - void *p_d (plugin_data *)
46692 @@ -301,12 +329,12 @@
46696 - * plugins that use
46698 + * plugins that use
46701 * - void *p_d (plugin_data *)
46705 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
46706 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
46707 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
46708 @@ -314,18 +342,18 @@
46710 #undef PLUGIN_TO_SLOT
46721 handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
46726 ps = srv->plugins.ptr;
46729 for (i = 0; i < srv->plugins.used; i++) {
46731 if (p->handle_fdevent) {
46732 @@ -344,34 +372,34 @@
46738 return HANDLER_GO_ON;
46744 * - call init function of all plugins to init the plugin-internals
46745 * - added each plugin that supports has callback to the corresponding slot
46748 * - is only called once.
46751 handler_t plugins_call_init(server *srv) {
46756 ps = srv->plugins.ptr;
46762 srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
46765 for (i = 0; i < srv->plugins.used; i++) {
46767 /* check which calls are supported */
46773 #define PLUGIN_TO_SLOT(x, y) \
46775 plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
46776 @@ -384,11 +412,11 @@
46783 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
46784 - PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
46788 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
46789 + PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
46790 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
46791 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
46792 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
46793 @@ -402,19 +430,19 @@
46794 PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
46795 PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
46796 #undef PLUGIN_TO_SLOT
46800 if (NULL == (p->data = p->init())) {
46801 - log_error_write(srv, __FILE__, __LINE__, "sb",
46802 + log_error_write(srv, __FILE__, __LINE__, "sb",
46803 "plugin-init failed for module", p->name);
46804 return HANDLER_ERROR;
46808 /* used for con->mode, DIRECT == 0, plugins above that */
46809 ((plugin_data *)(p->data))->id = i + 1;
46812 if (p->version != LIGHTTPD_VERSION_ID) {
46813 - log_error_write(srv, __FILE__, __LINE__, "sb",
46814 + log_error_write(srv, __FILE__, __LINE__, "sb",
46815 "plugin-version doesn't match lighttpd-version for", p->name);
46816 return HANDLER_ERROR;
46818 @@ -422,29 +450,46 @@
46824 return HANDLER_GO_ON;
46828 + * get the config-storage of the named plugin
46830 +void *plugin_get_config(server *srv, const char *name) {
46833 + for (i = 0; i < srv->plugins.used; i++) {
46834 + plugin *p = ((plugin **)srv->plugins.ptr)[i];
46836 + if (buffer_is_equal_string(p->name, name, strlen(name))) {
46844 void plugins_free(server *srv) {
46846 plugins_call_cleanup(srv);
46849 for (i = 0; i < srv->plugins.used; i++) {
46850 plugin *p = ((plugin **)srv->plugins.ptr)[i];
46857 for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
46858 plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
46861 if (slot) free(slot);
46865 free(srv->plugin_slots);
46866 srv->plugin_slots = NULL;
46869 free(srv->plugins.ptr);
46870 srv->plugins.ptr = NULL;
46871 srv->plugins.used = 0;
46872 --- ../lighttpd-1.4.11/src/plugin.h 2005-08-15 12:28:56.000000000 +0300
46873 +++ lighttpd-1.4.12/src/plugin.h 2006-07-16 00:26:04.000000000 +0300
46876 #define INIT_FUNC(x) \
46879 + * The PATCH_OPTION() macro is used in the patch_connection() functions
46880 + * of the modules to update the config object for the current request.
46882 +#define PATCH_OPTION(x) \
46885 #define FREE_FUNC SERVER_FUNC
46886 #define TRIGGER_FUNC SERVER_FUNC
46887 @@ -25,19 +31,19 @@
46888 #define URIHANDLER_FUNC CONNECTION_FUNC
46890 #define PLUGIN_DATA size_t id
46897 buffer *name; /* name of the plugin */
46901 handler_t (* set_defaults) (server *srv, void *p_d);
46902 handler_t (* cleanup) (server *srv, void *p_d);
46903 /* is called ... */
46904 handler_t (* handle_trigger) (server *srv, void *p_d); /* once a second */
46905 handler_t (* handle_sighup) (server *srv, void *p_d); /* at a signup */
46908 handler_t (* handle_uri_raw) (server *srv, connection *con, void *p_d); /* after uri_raw is set */
46909 handler_t (* handle_uri_clean) (server *srv, connection *con, void *p_d); /* after uri is set */
46910 handler_t (* handle_docroot) (server *srv, connection *con, void *p_d); /* getting the document-root */
46911 @@ -45,20 +51,22 @@
46912 handler_t (* handle_request_done) (server *srv, connection *con, void *p_d); /* at the end of a request */
46913 handler_t (* handle_connection_close)(server *srv, connection *con, void *p_d); /* at the end of a connection */
46914 handler_t (* handle_joblist) (server *srv, connection *con, void *p_d); /* after all events are handled */
46918 - handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
46920 - /* when a handler for the request
46924 + handler_t (* handle_subrequest_start)(server *srv, connection *con, void *p_d);
46926 + /* when a handler for the request
46929 handler_t (* handle_subrequest) (server *srv, connection *con, void *p_d); /* */
46930 handler_t (* connection_reset) (server *srv, connection *con, void *p_d); /* */
46934 /* dlopen handle */
46937 + array *required_plugins;
46940 int plugins_load(server *srv);
46942 int config_patch_connection(server *srv, connection *con, comp_key_t comp);
46943 int config_check_cond(server *srv, connection *con, data_config *dc);
46944 int config_append_cond_match_buffer(connection *con, data_config *dc, buffer *buf, int n);
46945 +int config_exec_pcre_keyvalue_buffer(connection *con, pcre_keyvalue_buffer *kvb, data_config *context, buffer *match_buf, buffer *result);
46947 +void *plugin_get_config(server *srv, const char *name);
46950 --- ../lighttpd-1.4.11/src/proc_open.c 2005-08-11 01:26:39.000000000 +0300
46951 +++ lighttpd-1.4.12/src/proc_open.c 2006-07-16 00:26:04.000000000 +0300
46952 @@ -13,13 +13,13 @@
46958 /* {{{ win32 stuff */
46959 # define SHELLENV "ComSpec"
46960 # define SECURITY_DC , SECURITY_ATTRIBUTES *security
46961 # define SECURITY_CC , security
46962 # define pipe(pair) (CreatePipe(&pair[0], &pair[1], security, 2048L) ? 0 : -1)
46963 -static inline HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
46964 +static HANDLE dup_handle(HANDLE src, BOOL inherit, BOOL closeorig)
46966 HANDLE copy, self = GetCurrentProcess();
46968 @@ -148,11 +148,14 @@
46971 SECURITY_ATTRIBUTES security;
46972 - const char *shell;
46973 + const char *shell = NULL;
46974 + const char *windir = NULL;
46977 - if (NULL == (shell = getenv(SHELLENV))) {
46978 - fprintf(stderr, "env %s is required", SHELLENV);
46979 + if (NULL == (shell = getenv(SHELLENV)) &&
46980 + NULL == (windir = getenv("SystemRoot")) &&
46981 + NULL == (windir = getenv("windir"))) {
46982 + fprintf(stderr, "One of %s,%%SystemRoot,%%windir is required", SHELLENV);
46986 @@ -177,17 +180,23 @@
46987 memset(&pi, 0, sizeof(pi));
46989 cmdline = buffer_init();
46990 - buffer_append_string(cmdline, shell);
46992 + buffer_append_string(cmdline, shell);
46994 + buffer_append_string(cmdline, windir);
46995 + buffer_append_string(cmdline, "\\system32\\cmd.exe");
46997 buffer_append_string_len(cmdline, CONST_STR_LEN(" /c "));
46998 buffer_append_string(cmdline, command);
46999 procok = CreateProcess(NULL, cmdline->ptr, &security, &security, TRUE,
47000 NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
47001 - buffer_free(cmdline);
47003 if (FALSE == procok) {
47004 - fprintf(stderr, "failed to CreateProcess");
47005 + fprintf(stderr, "failed to CreateProcess: %s", cmdline->ptr);
47006 + buffer_free(cmdline);
47009 + buffer_free(cmdline);
47011 proc->child = pi.hProcess;
47012 CloseHandle(pi.hThread);
47013 @@ -226,8 +235,7 @@
47016 if (NULL == (shell = getenv(SHELLENV))) {
47017 - fprintf(stderr, "env %s is required", SHELLENV);
47019 + shell = "/bin/sh";
47022 if (proc_open_pipes(proc) != 0) {
47023 @@ -262,11 +270,11 @@
47027 -#endif /* WIN32 */
47028 +#endif /* _WIN32 */
47030 /* {{{ proc_read_fd_to_buffer */
47031 static void proc_read_fd_to_buffer(int fd, buffer *b) {
47033 + int s; /* win32 has not ssize_t */
47036 buffer_prepare_append(b, 512);
47037 --- ../lighttpd-1.4.11/src/proc_open.h 2005-08-11 01:26:39.000000000 +0300
47038 +++ lighttpd-1.4.12/src/proc_open.h 2006-07-16 00:26:04.000000000 +0300
47041 #include "buffer.h"
47045 #include <windows.h>
47046 typedef HANDLE descriptor_t;
47047 typedef HANDLE proc_pid_t;
47048 --- ../lighttpd-1.4.11/src/request.c 2006-03-05 11:58:09.000000000 +0200
47049 +++ lighttpd-1.4.12/src/request.c 2006-07-18 13:03:40.000000000 +0300
47050 @@ -10,15 +10,17 @@
47051 #include "keyvalue.h"
47054 +#include "sys-strings.h"
47056 static int request_check_hostname(server *srv, connection *con, buffer *host) {
47057 enum { DOMAINLABEL, TOPLABEL } stage = TOPLABEL;
47062 - int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47063 + int is_ip = -1; /* -1 don't know yet, 0 no, 1 yes */
47070 @@ -32,17 +34,17 @@
47071 * IPv6address = "[" ... "]"
47077 if (!host || host->used == 0) return 0;
47080 host_len = host->used - 1;
47084 if (host->ptr[0] == '[') {
47085 char *c = host->ptr + 1;
47089 /* check portnumber */
47090 for (; *c && *c != ']'; c++) {
47092 @@ -53,12 +55,12 @@
47105 if (*(c+1) == ':') {
47106 for (c += 2; *c; c++) {
47107 @@ -69,39 +71,39 @@
47113 if (NULL != (colon = memchr(host->ptr, ':', host_len))) {
47114 char *c = colon + 1;
47117 /* check portnumber */
47119 if (!light_isdigit(*c)) return -1;
47123 /* remove the port from the host-len */
47124 host_len = colon - host->ptr;
47128 /* Host is empty */
47129 if (host_len == 0) return -1;
47132 /* scan from the right and skip the \0 */
47133 for (i = host_len - 1; i + 1 > 0; i--) {
47134 const char c = host->ptr[i];
47140 /* only switch stage, if this is not the last character */
47141 if (i != host_len - 1) {
47142 if (label_len == 0) {
47147 /* check the first character at right of the dot */
47149 if (!light_isalpha(host->ptr[i+1])) {
47153 } else if (!light_isdigit(host->ptr[i+1])) {
47155 @@ -111,9 +113,9 @@
47161 stage = DOMAINLABEL;
47166 } else if (i == 0) {
47167 @@ -135,7 +137,7 @@
47176 @@ -143,7 +145,7 @@
47177 if (label_len == 0) {
47184 } else if (!light_isdigit(c)) {
47185 @@ -156,12 +158,12 @@
47186 if (label_len == 0) {
47191 /* c is either - or alphanum here */
47192 if ('-' == host->ptr[i+1]) {
47199 } else if (i == 0) {
47200 @@ -176,20 +178,20 @@
47211 /* a IP has to consist of 4 parts */
47212 if (is_ip == 1 && level != 3) {
47217 if (label_len == 0) {
47225 @@ -201,53 +203,53 @@
47235 * val1, val2, val3, val4
47238 * into a array (more or less a explode() incl. striping of whitespaces
47242 if (b->used == 0) return 0;
47248 for (i =0; i < b->used - 1; ) {
47249 char *start = NULL, *end = NULL;
47258 for (; (*s == ' ' || *s == '\t') && i < b->used - 1; i++, s++);
47265 case 1: /* value */
47269 for (; *s != ',' && i < b->used - 1; i++, s++);
47273 for (; (*end == ' ' || *end == '\t') && end > start; end--);
47276 if (NULL == (ds = (data_string *)array_get_unused_element(vals, TYPE_STRING))) {
47277 ds = data_string_init();
47280 buffer_copy_string_len(ds->value, start, end-start+1);
47281 array_insert_unique(vals, (data_unset *)ds);
47289 /* end of string */
47295 @@ -263,7 +265,7 @@
47296 if (c <= 32) return 0;
47297 if (c == 127) return 0;
47298 if (c == 255) return 0;
47304 @@ -271,28 +273,28 @@
47305 char *uri = NULL, *proto = NULL, *method = NULL, con_length_set;
47306 int is_key = 1, key_len = 0, is_ws_after_key = 0, in_folding;
47307 char *value = NULL, *key = NULL;
47310 enum { HTTP_CONNECTION_UNSET, HTTP_CONNECTION_KEEPALIVE, HTTP_CONNECTION_CLOSE } keep_alive_set = HTTP_CONNECTION_UNSET;
47316 int request_line_stage = 0;
47323 data_string *ds = NULL;
47326 - * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47327 - * Option : "^([-a-zA-Z]+): (.+)$"
47330 + * Request: "^(GET|POST|HEAD) ([^ ]+(\\?[^ ]+|)) (HTTP/1\\.[01])$"
47331 + * Option : "^([-a-zA-Z]+): (.+)$"
47335 if (con->conf.log_request_header) {
47336 - log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47338 - "request-len:", con->request.request->used,
47339 + log_error_write(srv, __FILE__, __LINE__, "sdsdSb",
47340 + "fd:", con->sock->fd,
47341 + "request-len:", con->request.request->used,
47342 "\n", con->request.request);
47345 @@ -300,13 +302,13 @@
47346 con->request.request->ptr[0] == '\r' &&
47347 con->request.request->ptr[1] == '\n') {
47348 /* we are in keep-alive and might get \r\n after a previous POST request.*/
47351 buffer_copy_string_len(con->parse_request, con->request.request->ptr + 2, con->request.request->used - 1 - 2);
47353 /* fill the local request buffer */
47354 buffer_copy_string_buffer(con->parse_request, con->request.request);
47358 keep_alive_set = 0;
47359 con_length_set = 0;
47361 @@ -318,25 +320,25 @@
47363 for (i = 0, first = 0; i < con->parse_request->used && line == 0; i++) {
47364 char *cur = con->parse_request->ptr + i;
47370 if (con->parse_request->ptr[i+1] == '\n') {
47377 con->parse_request->ptr[i] = '\0';
47378 con->parse_request->ptr[i+1] = '\0';
47381 buffer_copy_string_len(con->request.request_line, con->parse_request->ptr, i);
47384 if (request_line_stage != 2) {
47385 con->http_status = 400;
47386 con->response.keep_alive = 0;
47387 con->keep_alive = 0;
47390 if (srv->srvconf.log_request_header_on_error) {
47391 log_error_write(srv, __FILE__, __LINE__, "s", "incomplete request line -> 400");
47392 log_error_write(srv, __FILE__, __LINE__, "Sb",
47393 @@ -345,36 +347,36 @@
47399 proto = con->parse_request->ptr + first;
47403 *(proto - 1) = '\0';
47406 /* we got the first one :) */
47407 if (-1 == (r = get_http_method_key(method))) {
47408 con->http_status = 501;
47409 con->response.keep_alive = 0;
47410 con->keep_alive = 0;
47413 if (srv->srvconf.log_request_header_on_error) {
47414 log_error_write(srv, __FILE__, __LINE__, "s", "unknown http-method -> 501");
47415 log_error_write(srv, __FILE__, __LINE__, "Sb",
47416 "request-header:\n",
47417 con->request.request);
47425 con->request.http_method = r;
47432 * HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
47436 if (0 == strncmp(proto, "HTTP/", sizeof("HTTP/") - 1)) {
47437 char * major = proto + sizeof("HTTP/") - 1;
47438 char * minor = strchr(major, '.');
47439 @@ -413,10 +415,10 @@
47442 if (major_num == 1 && minor_num == 1) {
47443 - con->request.http_version = con->conf.allow_http11 ? HTTP_VERSION_1_1 : HTTP_VERSION_1_0;
47444 + con->request.http_version = HTTP_VERSION_1_1;
47445 } else if (major_num == 1 && minor_num == 0) {
47446 con->request.http_version = HTTP_VERSION_1_0;
47449 con->http_status = 505;
47451 if (srv->srvconf.log_request_header_on_error) {
47452 @@ -439,30 +441,30 @@
47458 if (0 == strncmp(uri, "http://", 7) &&
47459 NULL != (nuri = strchr(uri + 7, '/'))) {
47460 /* ignore the host-part */
47463 buffer_copy_string_len(con->request.uri, nuri, proto - nuri - 1);
47465 /* everything looks good so far */
47466 buffer_copy_string_len(con->request.uri, uri, proto - uri - 1);
47470 /* check uri for invalid characters */
47471 for (j = 0; j < con->request.uri->used - 1; j++) {
47472 if (!request_uri_is_valid_char(con->request.uri->ptr[j])) {
47473 unsigned char buf[2];
47474 con->http_status = 400;
47475 con->keep_alive = 0;
47478 if (srv->srvconf.log_request_header_on_error) {
47479 buf[0] = con->request.uri->ptr[j];
47483 if (con->request.uri->ptr[j] > 32 &&
47484 - con->request.uri->ptr[j] != 127) {
47485 + con->request.uri->ptr[j] != 127) {
47486 /* the character is printable -> print it */
47487 log_error_write(srv, __FILE__, __LINE__, "ss",
47488 "invalid character in URI -> 400",
47489 @@ -473,20 +475,20 @@
47490 "invalid character in URI -> 400",
47491 con->request.uri->ptr[j]);
47495 log_error_write(srv, __FILE__, __LINE__, "Sb",
47496 "request-header:\n",
47497 con->request.request);
47506 buffer_copy_string_buffer(con->request.orig_uri, con->request.uri);
47509 con->http_status = 0;
47515 @@ -494,14 +496,14 @@
47518 switch(request_line_stage) {
47522 - method = con->parse_request->ptr + first;
47523 + method = con->parse_request->ptr + first;
47528 - uri = con->parse_request->ptr + first;
47529 + uri = con->parse_request->ptr + first;
47533 @@ -509,7 +511,7 @@
47534 con->http_status = 400;
47535 con->response.keep_alive = 0;
47536 con->keep_alive = 0;
47539 if (srv->srvconf.log_request_header_on_error) {
47540 log_error_write(srv, __FILE__, __LINE__, "s", "overlong request line -> 400");
47541 log_error_write(srv, __FILE__, __LINE__, "Sb",
47542 @@ -518,12 +520,12 @@
47548 request_line_stage++;
47556 if (con->request.uri->used == 1) {
47557 @@ -540,30 +542,30 @@
47563 for (; i < con->parse_request->used && !done; i++) {
47564 char *cur = con->parse_request->ptr + i;
47573 * 1*<any CHAR except CTLs or separators>
47574 * CTLs == 0-31 + 127
47586 if (is_ws_after_key == 0) {
47587 key_len = i - first;
47589 is_ws_after_key = 0;
47595 @@ -584,8 +586,8 @@
47596 con->http_status = 400;
47597 con->keep_alive = 0;
47598 con->response.keep_alive = 0;
47600 - log_error_write(srv, __FILE__, __LINE__, "sbsds",
47602 + log_error_write(srv, __FILE__, __LINE__, "sbsds",
47603 "invalid character in key", con->request.request, cur, *cur, "-> 400");
47606 @@ -594,13 +596,13 @@
47618 key_len = i - first;
47621 /* skip every thing up to the : */
47622 for (j = 1; !got_colon; j++) {
47623 switch(con->parse_request->ptr[j + i]) {
47624 @@ -610,40 +612,40 @@
47639 if (srv->srvconf.log_request_header_on_error) {
47640 log_error_write(srv, __FILE__, __LINE__, "s", "WS character in key -> 400");
47641 log_error_write(srv, __FILE__, __LINE__, "Sb",
47642 "request-header:\n",
47643 con->request.request);
47647 con->http_status = 400;
47648 con->response.keep_alive = 0;
47649 con->keep_alive = 0;
47659 if (con->parse_request->ptr[i+1] == '\n' && i == first) {
47660 /* End of Header */
47661 con->parse_request->ptr[i] = '\0';
47662 con->parse_request->ptr[i+1] = '\0';
47673 if (srv->srvconf.log_request_header_on_error) {
47674 @@ -652,7 +654,7 @@
47675 "request-header:\n",
47676 con->request.request);
47680 con->http_status = 400;
47681 con->keep_alive = 0;
47682 con->response.keep_alive = 0;
47683 @@ -693,16 +695,16 @@
47684 con->http_status = 400;
47685 con->keep_alive = 0;
47686 con->response.keep_alive = 0;
47689 if (srv->srvconf.log_request_header_on_error) {
47690 - log_error_write(srv, __FILE__, __LINE__, "sbsds",
47691 + log_error_write(srv, __FILE__, __LINE__, "sbsds",
47692 "CTL character in key", con->request.request, cur, *cur, "-> 400");
47694 log_error_write(srv, __FILE__, __LINE__, "Sb",
47695 "request-header:\n",
47696 con->request.request);
47703 @@ -710,25 +712,25 @@
47709 if (con->parse_request->ptr[i+1] == '\n') {
47710 /* End of Headerline */
47711 con->parse_request->ptr[i] = '\0';
47712 con->parse_request->ptr[i+1] = '\0';
47720 if (srv->srvconf.log_request_header_on_error) {
47721 log_error_write(srv, __FILE__, __LINE__, "s", "WS at the start of first line -> 400");
47724 log_error_write(srv, __FILE__, __LINE__, "Sb",
47725 "request-header:\n",
47726 con->request.request);
47731 con->http_status = 400;
47732 con->keep_alive = 0;
47733 con->response.keep_alive = 0;
47734 @@ -738,9 +740,9 @@
47737 key = con->parse_request->ptr + first;
47740 s_len = cur - value;
47745 if (NULL == (ds = (data_string *)array_get_unused_element(con->request.headers, TYPE_STRING))) {
47746 @@ -748,86 +750,87 @@
47748 buffer_copy_string_len(ds->key, key, key_len);
47749 buffer_copy_string_len(ds->value, value, s_len);
47751 - /* retreive values
47755 + /* retreive values
47758 * the list of options is sorted to simplify the search
47762 if (0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Connection")))) {
47770 vals = srv->split_vals;
47775 http_request_split_value(vals, ds->value);
47778 for (vi = 0; vi < vals->used; vi++) {
47779 data_string *dsv = (data_string *)vals->data[vi];
47782 if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("keep-alive"))) {
47783 keep_alive_set = HTTP_CONNECTION_KEEPALIVE;
47787 } else if (0 == buffer_caseless_compare(CONST_BUF_LEN(dsv->value), CONST_STR_LEN("close"))) {
47788 keep_alive_set = HTTP_CONNECTION_CLOSE;
47796 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Content-Length")))) {
47798 unsigned long int r;
47802 if (con_length_set) {
47803 con->http_status = 400;
47804 con->keep_alive = 0;
47807 if (srv->srvconf.log_request_header_on_error) {
47808 - log_error_write(srv, __FILE__, __LINE__, "s",
47809 + log_error_write(srv, __FILE__, __LINE__, "s",
47810 "duplicate Content-Length-header -> 400");
47811 log_error_write(srv, __FILE__, __LINE__, "Sb",
47812 "request-header:\n",
47813 con->request.request);
47815 + ds->free((data_unset *) ds);
47820 if (ds->value->used == 0) SEGFAULT();
47823 for (j = 0; j < ds->value->used - 1; j++) {
47824 char c = ds->value->ptr[j];
47825 if (!isdigit((unsigned char)c)) {
47826 - log_error_write(srv, __FILE__, __LINE__, "sbs",
47827 + log_error_write(srv, __FILE__, __LINE__, "sbs",
47828 "content-length broken:", ds->value, "-> 400");
47831 con->http_status = 400;
47832 con->keep_alive = 0;
47835 array_insert_unique(con->request.headers, (data_unset *)ds);
47841 r = strtoul(ds->value->ptr, &err, 10);
47844 if (*err == '\0') {
47845 con_length_set = 1;
47846 con->request.content_length = r;
47848 - log_error_write(srv, __FILE__, __LINE__, "sbs",
47849 + log_error_write(srv, __FILE__, __LINE__, "sbs",
47850 "content-length broken:", ds->value, "-> 400");
47853 con->http_status = 400;
47854 con->keep_alive = 0;
47857 array_insert_unique(con->request.headers, (data_unset *)ds);
47860 @@ -838,23 +841,24 @@
47862 con->http_status = 400;
47863 con->keep_alive = 0;
47866 if (srv->srvconf.log_request_header_on_error) {
47867 - log_error_write(srv, __FILE__, __LINE__, "s",
47868 + log_error_write(srv, __FILE__, __LINE__, "s",
47869 "duplicate Content-Type-header -> 400");
47870 log_error_write(srv, __FILE__, __LINE__, "Sb",
47871 "request-header:\n",
47872 con->request.request);
47874 + ds->free((data_unset *) ds);
47877 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Expect")))) {
47878 - /* HTTP 2616 8.2.3
47879 + /* HTTP 2616 8.2.3
47880 * Expect: 100-continue
47883 * -> (10.1.1) 100 (read content, process request, send final status-code)
47884 * -> (10.4.18) 417 (close)
47887 * (not handled at all yet, we always send 417 here)
47889 * What has to be added ?
47890 @@ -863,10 +867,10 @@
47896 con->http_status = 417;
47897 con->keep_alive = 0;
47900 array_insert_unique(con->request.headers, (data_unset *)ds);
47902 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Host")))) {
47903 @@ -875,14 +879,15 @@
47905 con->http_status = 400;
47906 con->keep_alive = 0;
47909 if (srv->srvconf.log_request_header_on_error) {
47910 - log_error_write(srv, __FILE__, __LINE__, "s",
47911 + log_error_write(srv, __FILE__, __LINE__, "s",
47912 "duplicate Host-header -> 400");
47913 log_error_write(srv, __FILE__, __LINE__, "Sb",
47914 "request-header:\n",
47915 con->request.request);
47917 + ds->free((data_unset *) ds);
47920 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-Modified-Since")))) {
47921 @@ -897,14 +902,15 @@
47923 con->http_status = 400;
47924 con->keep_alive = 0;
47927 if (srv->srvconf.log_request_header_on_error) {
47928 - log_error_write(srv, __FILE__, __LINE__, "s",
47929 + log_error_write(srv, __FILE__, __LINE__, "s",
47930 "duplicate If-Modified-Since header -> 400");
47931 log_error_write(srv, __FILE__, __LINE__, "Sb",
47932 "request-header:\n",
47933 con->request.request);
47935 + ds->free((data_unset *) ds);
47938 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("If-None-Match")))) {
47939 @@ -914,47 +920,49 @@
47941 con->http_status = 400;
47942 con->keep_alive = 0;
47945 if (srv->srvconf.log_request_header_on_error) {
47946 - log_error_write(srv, __FILE__, __LINE__, "s",
47947 + log_error_write(srv, __FILE__, __LINE__, "s",
47948 "duplicate If-None-Match-header -> 400");
47949 log_error_write(srv, __FILE__, __LINE__, "Sb",
47950 "request-header:\n",
47951 con->request.request);
47953 + ds->free((data_unset *) ds);
47956 } else if (cmp > 0 && 0 == (cmp = buffer_caseless_compare(CONST_BUF_LEN(ds->key), CONST_STR_LEN("Range")))) {
47957 if (!con->request.http_range) {
47961 if (0 == strncasecmp(ds->value->ptr, "bytes=", 6) &&
47962 NULL != strchr(ds->value->ptr+6, '-')) {
47965 /* if dup, only the first one will survive */
47966 con->request.http_range = ds->value->ptr + 6;
47969 con->http_status = 400;
47970 con->keep_alive = 0;
47973 if (srv->srvconf.log_request_header_on_error) {
47974 - log_error_write(srv, __FILE__, __LINE__, "s",
47975 + log_error_write(srv, __FILE__, __LINE__, "s",
47976 "duplicate Range-header -> 400");
47977 log_error_write(srv, __FILE__, __LINE__, "Sb",
47978 "request-header:\n",
47979 con->request.request);
47981 + ds->free((data_unset *) ds);
47987 array_insert_unique(con->request.headers, (data_unset *)ds);
47989 /* empty header-fields are not allowed by HTTP-RFC, we just ignore them */
47997 @@ -963,10 +971,10 @@
48000 if (srv->srvconf.log_request_header_on_error) {
48001 - log_error_write(srv, __FILE__, __LINE__, "sbs",
48002 + log_error_write(srv, __FILE__, __LINE__, "sbs",
48003 "CR without LF", con->request.request, "-> 400");
48007 con->http_status = 400;
48008 con->keep_alive = 0;
48009 con->response.keep_alive = 0;
48010 @@ -982,28 +990,28 @@
48016 con->header_len = i;
48019 /* do some post-processing */
48021 if (con->request.http_version == HTTP_VERSION_1_1) {
48022 if (keep_alive_set != HTTP_CONNECTION_CLOSE) {
48023 /* no Connection-Header sent */
48026 /* HTTP/1.1 -> keep-alive default TRUE */
48027 con->keep_alive = 1;
48029 con->keep_alive = 0;
48033 /* RFC 2616, 14.23 */
48034 if (con->request.http_host == NULL ||
48035 buffer_is_empty(con->request.http_host)) {
48036 con->http_status = 400;
48037 con->response.keep_alive = 0;
48038 con->keep_alive = 0;
48041 if (srv->srvconf.log_request_header_on_error) {
48042 log_error_write(srv, __FILE__, __LINE__, "s", "HTTP/1.1 but Host missing -> 400");
48043 log_error_write(srv, __FILE__, __LINE__, "Sb",
48044 @@ -1015,18 +1023,18 @@
48046 if (keep_alive_set == HTTP_CONNECTION_KEEPALIVE) {
48047 /* no Connection-Header sent */
48050 /* HTTP/1.0 -> keep-alive default FALSE */
48051 con->keep_alive = 1;
48053 con->keep_alive = 0;
48058 /* check hostname field if it is set */
48059 if (NULL != con->request.http_host &&
48060 0 != request_check_hostname(srv, con, con->request.http_host)) {
48063 if (srv->srvconf.log_request_header_on_error) {
48064 log_error_write(srv, __FILE__, __LINE__, "s",
48065 "Invalid Hostname -> 400");
48066 @@ -1038,7 +1046,7 @@
48067 con->http_status = 400;
48068 con->response.keep_alive = 0;
48069 con->keep_alive = 0;
48075 @@ -1048,7 +1056,7 @@
48076 /* content-length is forbidden for those */
48077 if (con_length_set && con->request.content_length != 0) {
48078 /* content-length is missing */
48079 - log_error_write(srv, __FILE__, __LINE__, "s",
48080 + log_error_write(srv, __FILE__, __LINE__, "s",
48081 "GET/HEAD with content-length -> 400");
48083 con->keep_alive = 0;
48084 @@ -1060,7 +1068,7 @@
48085 /* content-length is required for them */
48086 if (!con_length_set) {
48087 /* content-length is missing */
48088 - log_error_write(srv, __FILE__, __LINE__, "s",
48089 + log_error_write(srv, __FILE__, __LINE__, "s",
48090 "POST-request, but content-length missing -> 411");
48092 con->keep_alive = 0;
48093 @@ -1073,16 +1081,16 @@
48094 /* the may have a content-length */
48101 /* check if we have read post data */
48102 if (con_length_set) {
48103 /* don't handle more the SSIZE_MAX bytes in content-length */
48104 if (con->request.content_length > SSIZE_MAX) {
48105 - con->http_status = 413;
48106 + con->http_status = 413;
48107 con->keep_alive = 0;
48109 - log_error_write(srv, __FILE__, __LINE__, "sds",
48110 + log_error_write(srv, __FILE__, __LINE__, "sds",
48111 "request-size too long:", con->request.content_length, "-> 413");
48114 @@ -1090,25 +1098,25 @@
48115 /* divide by 1024 as srvconf.max_request_size is in kBytes */
48116 if (srv->srvconf.max_request_size != 0 &&
48117 (con->request.content_length >> 10) > srv->srvconf.max_request_size) {
48118 - /* the request body itself is larger then
48119 + /* the request body itself is larger then
48120 * our our max_request_size
48124 con->http_status = 413;
48125 con->keep_alive = 0;
48127 - log_error_write(srv, __FILE__, __LINE__, "sds",
48129 + log_error_write(srv, __FILE__, __LINE__, "sds",
48130 "request-size too long:", con->request.content_length, "-> 413");
48137 /* we have content */
48138 if (con->request.content_length != 0) {
48147 @@ -1116,9 +1124,9 @@
48150 if (con->request.request->used < 5) return 0;
48153 if (0 == memcmp(con->request.request->ptr + con->request.request->used - 5, "\r\n\r\n", 4)) return 1;
48154 if (NULL != strstr(con->request.request->ptr, "\r\n\r\n")) return 1;
48159 --- ../lighttpd-1.4.11/src/response.c 2006-03-04 16:41:39.000000000 +0200
48160 +++ lighttpd-1.4.12/src/response.c 2006-07-16 00:26:04.000000000 +0300
48162 #include <stdlib.h>
48163 #include <string.h>
48165 -#include <unistd.h>
48167 #include <assert.h>
48169 @@ -24,15 +23,17 @@
48170 #include "plugin.h"
48172 #include "sys-socket.h"
48173 +#include "sys-files.h"
48174 +#include "sys-strings.h"
48176 int http_response_write_header(server *srv, connection *con) {
48180 int have_server = 0;
48183 b = chunkqueue_get_prepend_buffer(con->write_queue);
48186 if (con->request.http_version == HTTP_VERSION_1_1) {
48187 BUFFER_COPY_STRING_CONST(b, "HTTP/1.1 ");
48189 @@ -41,25 +42,26 @@
48190 buffer_append_long(b, con->http_status);
48191 BUFFER_APPEND_STRING_CONST(b, " ");
48192 buffer_append_string(b, get_http_status_name(con->http_status));
48195 if (con->request.http_version != HTTP_VERSION_1_1 || con->keep_alive == 0) {
48196 BUFFER_APPEND_STRING_CONST(b, "\r\nConnection: ");
48197 buffer_append_string(b, con->keep_alive ? "keep-alive" : "close");
48201 if (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) {
48202 BUFFER_APPEND_STRING_CONST(b, "\r\nTransfer-Encoding: chunked");
48208 /* add all headers */
48209 for (i = 0; i < con->response.headers->used; i++) {
48213 ds = (data_string *)con->response.headers->data[i];
48216 if (ds->value->used && ds->key->used &&
48217 - 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1)) {
48218 + 0 != strncmp(ds->key->ptr, "X-LIGHTTPD-", sizeof("X-LIGHTTPD-") - 1) &&
48219 + 0 != strcasecmp(ds->key->ptr, "X-Sendfile")) {
48220 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Date"))) have_date = 1;
48221 if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Server"))) have_server = 1;
48223 @@ -68,28 +70,28 @@
48224 BUFFER_APPEND_STRING_CONST(b, ": ");
48225 buffer_append_string_buffer(b, ds->value);
48227 - log_error_write(srv, __FILE__, __LINE__, "bb",
48228 + log_error_write(srv, __FILE__, __LINE__, "bb",
48229 ds->key, ds->value);
48236 /* HTTP/1.1 requires a Date: header */
48237 BUFFER_APPEND_STRING_CONST(b, "\r\nDate: ");
48240 /* cache the generated timestamp */
48241 if (srv->cur_ts != srv->last_generated_date_ts) {
48242 buffer_prepare_copy(srv->ts_date_str, 255);
48244 - strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48246 + strftime(srv->ts_date_str->ptr, srv->ts_date_str->size - 1,
48247 "%a, %d %b %Y %H:%M:%S GMT", gmtime(&(srv->cur_ts)));
48250 srv->ts_date_str->used = strlen(srv->ts_date_str->ptr) + 1;
48253 srv->last_generated_date_ts = srv->cur_ts;
48257 buffer_append_string_buffer(b, srv->ts_date_str);
48260 @@ -101,16 +103,16 @@
48261 buffer_append_string_buffer(b, con->conf.server_tag);
48266 BUFFER_APPEND_STRING_CONST(b, "\r\n\r\n");
48271 con->bytes_header = b->used - 1;
48274 if (con->conf.log_response_header) {
48275 log_error_write(srv, __FILE__, __LINE__, "sSb", "Response-Header:", "\n", b);
48282 @@ -118,71 +120,71 @@
48284 handler_t http_response_prepare(server *srv, connection *con) {
48287 - /* looks like someone has already done a decision */
48288 - if (con->mode == DIRECT &&
48290 + /* looks like someone has already made a decision */
48291 + if (con->mode == DIRECT &&
48292 (con->http_status != 0 && con->http_status != 200)) {
48293 /* remove a packets in the queue */
48294 if (con->file_finished == 0) {
48295 chunkqueue_reset(con->write_queue);
48299 return HANDLER_FINISHED;
48303 /* no decision yet, build conf->filename */
48304 if (con->mode == DIRECT && con->physical.path->used == 0) {
48307 - /* we only come here when we have the parse the full request again
48309 - * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48310 + /* we only come here when we have to parse the full request again
48312 + * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
48313 * problem here as mod_setenv might get called multiple times
48315 * fastcgi-auth might lead to a COMEBACK too
48316 * fastcgi again dead server too
48318 * mod_compress might add headers twice too
48324 if (con->conf.log_condition_handling) {
48325 log_error_write(srv, __FILE__, __LINE__, "s", "run condition");
48327 config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
48336 * - uri.path (secure)
48345 * Name according to RFC 2396
48354 * (scheme)://(authority)(path)?(query)
48362 buffer_copy_string(con->uri.scheme, con->conf.is_ssl ? "https" : "http");
48363 buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
48364 buffer_to_lower(con->uri.authority);
48367 config_patch_connection(srv, con, COMP_HTTP_HOST); /* Host: */
48368 config_patch_connection(srv, con, COMP_HTTP_REMOTEIP); /* Client-IP */
48369 config_patch_connection(srv, con, COMP_HTTP_REFERER); /* Referer: */
48370 config_patch_connection(srv, con, COMP_HTTP_USERAGENT); /* User-Agent: */
48371 config_patch_connection(srv, con, COMP_HTTP_COOKIE); /* Cookie: */
48374 /** extract query string from request.uri */
48375 if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
48376 buffer_copy_string (con->uri.query, qstr + 1);
48377 @@ -200,22 +202,22 @@
48378 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-path : ", con->uri.path_raw);
48379 log_error_write(srv, __FILE__, __LINE__, "sb", "URI-query : ", con->uri.query);
48383 /* disable keep-alive if requested */
48386 if (con->request_count > con->conf.max_keep_alive_requests) {
48387 con->keep_alive = 0;
48400 * - based on the raw URL
48406 switch(r = plugins_call_handle_uri_raw(srv, con)) {
48407 case HANDLER_GO_ON:
48409 @@ -229,14 +231,14 @@
48413 - /* build filename
48414 + /* build filename
48416 * - decode url-encodings (e.g. %20 -> ' ')
48417 * - remove path-modifiers (e.g. /../)
48425 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
48426 con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
48427 /* OPTIONS * ... */
48428 @@ -253,15 +255,20 @@
48438 * - based on the clean URL
48444 config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
48447 + /* do we have to downgrade to 1.0 ? */
48448 + if (!con->conf.allow_http11) {
48449 + con->request.http_version = HTTP_VERSION_1_0;
48452 switch(r = plugins_call_handle_uri_clean(srv, con)) {
48453 case HANDLER_GO_ON:
48455 @@ -274,11 +281,11 @@
48456 log_error_write(srv, __FILE__, __LINE__, "");
48461 if (con->request.http_method == HTTP_METHOD_OPTIONS &&
48462 con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
48463 - /* option requests are handled directly without checking of the path */
48465 + /* option requests are handled directly without checking the path */
48467 response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));
48469 con->http_status = 200;
48470 @@ -288,46 +295,47 @@
48480 * logical filename (URI) becomes a physical filename here
48497 * ... ISREG() -> ok, go on
48498 * ... ISDIR() -> index-file -> redirect
48513 * SEARCH DOCUMENT ROOT
48517 /* set a default */
48520 buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
48521 buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
48523 -#if defined(__WIN32) || defined(__CYGWIN__)
48524 - /* strip dots from the end and spaces
48526 + filename_unix2local(con->physical.rel_path);
48527 +#if defined(_WIN32) || defined(__CYGWIN__)
48528 + /* strip dots and spaces from the end
48530 * windows/dos handle those filenames as the same file
48532 * foo == foo. == foo..... == "foo... " == "foo.. ./"
48534 - * This will affect in some cases PATHINFO
48535 + * This will affect PATHINFO in some cases
48537 * on native windows we could prepend the filename with \\?\ to circumvent
48538 * this behaviour. I have no idea how to push this through cygwin
48539 @@ -377,36 +385,41 @@
48540 log_error_write(srv, __FILE__, __LINE__, "");
48544 - /* MacOS X and Windows can't distiguish between upper and lower-case
48546 - * convert to lower-case
48548 + /* The default Mac OS X and Windows filesystems can't distiguish between
48549 + * upper- and lowercase, so convert to lowercase
48551 if (con->conf.force_lowercase_filenames) {
48552 buffer_to_lower(con->physical.rel_path);
48555 - /* the docroot plugins might set the servername, if they don't we take http-host */
48556 + /* the docroot plugins might set the servername; if they don't we take http-host */
48557 if (buffer_is_empty(con->server_name)) {
48558 buffer_copy_string_buffer(con->server_name, con->uri.authority);
48562 - * create physical filename
48565 + * create physical filename
48566 * -> physical.path = docroot + rel_path
48572 buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
48573 - BUFFER_APPEND_SLASH(con->physical.path);
48574 + PATHNAME_APPEND_SLASH(con->physical.path);
48575 buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
48576 if (con->physical.rel_path->used &&
48577 - con->physical.rel_path->ptr[0] == '/') {
48578 + con->physical.rel_path->ptr[0] == DIR_SEPERATOR) {
48579 buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
48581 buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
48584 + /* win32: directories can't have a trailing slash */
48585 + if (con->physical.path->ptr[con->physical.path->used - 2] == DIR_SEPERATOR) {
48586 + con->physical.path->ptr[con->physical.path->used - 2] = '\0';
48587 + con->physical.path->used--;
48590 if (con->conf.log_request_handling) {
48591 log_error_write(srv, __FILE__, __LINE__, "s", "-- after doc_root");
48592 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
48593 @@ -426,7 +439,7 @@
48594 log_error_write(srv, __FILE__, __LINE__, "");
48599 if (con->conf.log_request_handling) {
48600 log_error_write(srv, __FILE__, __LINE__, "s", "-- logical -> physical");
48601 log_error_write(srv, __FILE__, __LINE__, "sb", "Doc-Root :", con->physical.doc_root);
48602 @@ -434,38 +447,38 @@
48603 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48608 - * Noone catched away the file from normal path of execution yet (like mod_access)
48612 + * No one took the file away from the normal path of execution yet (like mod_access)
48614 * Go on and check of the file exists at all
48618 if (con->mode == DIRECT) {
48619 char *slash = NULL;
48620 char *pathinfo = NULL;
48622 stat_cache_entry *sce = NULL;
48625 if (con->conf.log_request_handling) {
48626 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling physical path");
48627 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48631 if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {
48635 if (con->conf.log_request_handling) {
48636 log_error_write(srv, __FILE__, __LINE__, "s", "-- file found");
48637 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48641 if (S_ISDIR(sce->st.st_mode)) {
48642 - if (con->physical.path->ptr[con->physical.path->used - 2] != '/') {
48643 + if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
48644 /* redirect to .../ */
48647 http_response_redirect_to_directory(srv, con);
48650 return HANDLER_FINISHED;
48652 } else if (!S_ISREG(sce->st.st_mode)) {
48653 @@ -477,12 +490,12 @@
48656 con->http_status = 403;
48659 if (con->conf.log_request_handling) {
48660 log_error_write(srv, __FILE__, __LINE__, "s", "-- access denied");
48661 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48665 buffer_reset(con->physical.path);
48666 return HANDLER_FINISHED;
48668 @@ -499,77 +512,77 @@
48669 /* PATH_INFO ! :) */
48672 - /* we have no idea what happend. let's tell the user so. */
48673 + /* we have no idea what happened, so tell the user. */
48674 con->http_status = 500;
48675 buffer_reset(con->physical.path);
48678 log_error_write(srv, __FILE__, __LINE__, "ssbsb",
48679 "file not found ... or so: ", strerror(errno),
48681 "->", con->physical.path);
48684 return HANDLER_FINISHED;
48688 /* not found, perhaps PATHINFO */
48691 buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
48699 buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
48701 buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
48705 if (0 == stat(con->physical.path->ptr, &(st)) &&
48706 S_ISREG(st.st_mode)) {
48712 if (pathinfo != NULL) {
48715 slash = strrchr(srv->tmp_buf->ptr, '/');
48718 if (pathinfo != NULL) {
48724 if (slash) pathinfo = slash;
48725 } while ((found == 0) && (slash != NULL) && (slash - srv->tmp_buf->ptr > con->physical.basedir->used - 2));
48729 - /* no it really doesn't exists */
48730 + /* no, it really doesn't exists */
48731 con->http_status = 404;
48734 if (con->conf.log_file_not_found) {
48735 log_error_write(srv, __FILE__, __LINE__, "sbsb",
48736 "file not found:", con->uri.path,
48737 "->", con->physical.path);
48741 buffer_reset(con->physical.path);
48744 return HANDLER_FINISHED;
48748 /* we have a PATHINFO */
48750 buffer_copy_string(con->request.pathinfo, pathinfo);
48758 con->uri.path->used -= strlen(pathinfo);
48759 con->uri.path->ptr[con->uri.path->used - 1] = '\0';
48763 if (con->conf.log_request_handling) {
48764 log_error_write(srv, __FILE__, __LINE__, "s", "-- after pathinfo check");
48765 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48766 @@ -577,12 +590,12 @@
48767 log_error_write(srv, __FILE__, __LINE__, "sb", "Pathinfo :", con->request.pathinfo);
48772 if (con->conf.log_request_handling) {
48773 log_error_write(srv, __FILE__, __LINE__, "s", "-- handling subrequest");
48774 log_error_write(srv, __FILE__, __LINE__, "sb", "Path :", con->physical.path);
48778 /* call the handlers */
48779 switch(r = plugins_call_handle_subrequest_start(srv, con)) {
48780 case HANDLER_GO_ON:
48781 @@ -593,32 +606,32 @@
48782 if (con->conf.log_request_handling) {
48783 log_error_write(srv, __FILE__, __LINE__, "s", "-- subrequest finished");
48786 - /* something strange happend */
48788 + /* something strange happened */
48792 - /* if we are still here, no one wanted the file, status 403 is ok I think */
48795 + /* if we are still here, no one wanted the file; status 403 is ok I think */
48797 if (con->mode == DIRECT) {
48798 con->http_status = 403;
48801 return HANDLER_FINISHED;
48808 switch(r = plugins_call_handle_subrequest(srv, con)) {
48809 case HANDLER_GO_ON:
48810 - /* request was not handled, looks like we are done */
48811 + /* request was not handled; looks like we are done */
48812 return HANDLER_FINISHED;
48813 case HANDLER_FINISHED:
48814 /* request is finished */
48816 - /* something strange happend */
48817 + /* something strange happened */
48823 return HANDLER_COMEBACK;
48825 --- ../lighttpd-1.4.11/src/server.c 2006-03-04 19:12:17.000000000 +0200
48826 +++ lighttpd-1.4.12/src/server.c 2006-07-18 13:03:40.000000000 +0300
48828 #include <sys/types.h>
48829 -#include <sys/time.h>
48830 #include <sys/stat.h>
48832 #include <string.h>
48835 -#include <unistd.h>
48836 #include <stdlib.h>
48838 #include <signal.h>
48840 #include "plugin.h"
48841 #include "joblist.h"
48842 #include "network_backends.h"
48845 +/* use local getopt implementation */
48846 +# undef HAVE_GETOPT_H
48848 #ifdef HAVE_GETOPT_H
48849 #include <getopt.h>
48851 +#include "getopt.h"
48854 #ifdef HAVE_VALGRIND_VALGRIND_H
48856 /* #define USE_ALARM */
48860 +#undef HAVE_SIGNAL
48863 +#include "sys-files.h"
48864 +#include "sys-process.h"
48865 +#include "sys-socket.h"
48867 static volatile sig_atomic_t srv_shutdown = 0;
48868 static volatile sig_atomic_t graceful_shutdown = 0;
48869 +static volatile sig_atomic_t graceful_restart = 0;
48870 static volatile sig_atomic_t handle_sig_alarm = 1;
48871 static volatile sig_atomic_t handle_sig_hup = 0;
48876 case SIGTERM: srv_shutdown = 1; break;
48879 if (graceful_shutdown) srv_shutdown = 1;
48880 - else graceful_shutdown = 1;
48881 + else graceful_shutdown = 1;
48884 case SIGALRM: handle_sig_alarm = 1; break;
48886 static void signal_handler(int sig) {
48888 case SIGTERM: srv_shutdown = 1; break;
48891 if (graceful_shutdown) srv_shutdown = 1;
48892 - else graceful_shutdown = 1;
48893 + else graceful_shutdown = 1;
48896 case SIGALRM: handle_sig_alarm = 1; break;
48897 @@ -110,35 +122,35 @@
48898 signal(SIGTSTP, SIG_IGN);
48900 if (0 != fork()) exit(0);
48903 if (-1 == setsid()) exit(0);
48905 signal(SIGHUP, SIG_IGN);
48907 if (0 != fork()) exit(0);
48910 if (0 != chdir("/")) exit(0);
48914 static server *server_init(void) {
48918 server *srv = calloc(1, sizeof(*srv));
48920 + srv->max_fds = 1024;
48922 srv->x = buffer_init();
48925 CLEAN(response_header);
48926 CLEAN(parse_full_path);
48927 CLEAN(ts_debug_str);
48928 CLEAN(ts_date_str);
48929 - CLEAN(errorlog_buf);
48930 CLEAN(response_range);
48932 srv->empty_string = buffer_init_string("");
48933 CLEAN(cond_check_buf);
48936 CLEAN(srvconf.errorlog_file);
48937 CLEAN(srvconf.groupname);
48938 CLEAN(srvconf.username);
48939 @@ -146,68 +158,63 @@
48940 CLEAN(srvconf.bindhost);
48941 CLEAN(srvconf.event_handler);
48942 CLEAN(srvconf.pid_file);
48945 CLEAN(tmp_chunk_len);
48950 srv->x = array_init();
48953 CLEAN(config_context);
48954 CLEAN(config_touched);
48959 for (i = 0; i < FILE_CACHE_MAX; i++) {
48960 srv->mtime_cache[i].str = buffer_init();
48964 srv->cur_ts = time(NULL);
48965 srv->startup_ts = srv->cur_ts;
48968 srv->conns = calloc(1, sizeof(*srv->conns));
48969 assert(srv->conns);
48972 srv->joblist = calloc(1, sizeof(*srv->joblist));
48973 assert(srv->joblist);
48976 srv->fdwaitqueue = calloc(1, sizeof(*srv->fdwaitqueue));
48977 assert(srv->fdwaitqueue);
48980 srv->srvconf.modules = array_init();
48981 srv->srvconf.modules_dir = buffer_init_string(LIBRARY_DIR);
48982 srv->srvconf.network_backend = buffer_init();
48983 srv->srvconf.upload_tempdirs = array_init();
48986 - srv->errorlog_fd = -1;
48987 - srv->errorlog_mode = ERRORLOG_STDERR;
48989 srv->split_vals = array_init();
48995 static void server_free(server *srv) {
48999 for (i = 0; i < FILE_CACHE_MAX; i++) {
49000 buffer_free(srv->mtime_cache[i].str);
49005 buffer_free(srv->x);
49008 CLEAN(response_header);
49009 CLEAN(parse_full_path);
49010 CLEAN(ts_debug_str);
49011 CLEAN(ts_date_str);
49012 - CLEAN(errorlog_buf);
49013 CLEAN(response_range);
49015 CLEAN(empty_string);
49016 CLEAN(cond_check_buf);
49019 CLEAN(srvconf.errorlog_file);
49020 CLEAN(srvconf.groupname);
49021 CLEAN(srvconf.username);
49022 @@ -217,7 +224,7 @@
49023 CLEAN(srvconf.pid_file);
49024 CLEAN(srvconf.modules_dir);
49025 CLEAN(srvconf.network_backend);
49028 CLEAN(tmp_chunk_len);
49031 @@ -225,15 +232,15 @@
49032 fdevent_unregister(srv->ev, srv->fd);
49034 fdevent_free(srv->ev);
49040 if (srv->config_storage) {
49041 for (i = 0; i < srv->config_context->used; i++) {
49042 specific_config *s = srv->config_storage[i];
49047 buffer_free(s->document_root);
49048 buffer_free(s->server_name);
49049 buffer_free(s->server_tag);
49050 @@ -242,32 +249,32 @@
49051 buffer_free(s->error_handler);
49052 buffer_free(s->errorfile_prefix);
49053 array_free(s->mimetypes);
49058 free(srv->config_storage);
49059 srv->config_storage = NULL;
49064 array_free(srv->x);
49067 CLEAN(config_context);
49068 CLEAN(config_touched);
49070 CLEAN(srvconf.upload_tempdirs);
49074 joblist_free(srv, srv->joblist);
49075 fdwaitqueue_free(srv, srv->fdwaitqueue);
49078 if (srv->stat_cache) {
49079 stat_cache_free(srv->stat_cache);
49082 array_free(srv->srvconf.modules);
49083 array_free(srv->split_vals);
49089 @@ -281,14 +288,12 @@
49090 " - a light and fast webserver\n" \
49091 "Build-Date: " __DATE__ " " __TIME__ "\n";
49095 write(STDOUT_FILENO, b, strlen(b));
49098 static void show_features (void) {
49100 - printf("\nEvent Handlers:\n\n%s",
49102 + const char *s = ""
49104 "\t+ select (generic)\n"
49106 @@ -355,11 +360,6 @@
49108 "\t- crypt support\n"
49111 - "\t+ PAM support\n"
49113 - "\t- PAM support\n"
49116 "\t+ SSL Support\n"
49118 @@ -371,9 +371,9 @@
49119 "\t- PCRE support\n"
49122 - "\t+ mySQL support\n"
49123 + "\t+ MySQL support\n"
49125 - "\t- mySQL support\n"
49126 + "\t- MySQL support\n"
49128 #if defined(HAVE_LDAP_H) && defined(HAVE_LBER_H) && defined(HAVE_LIBLDAP) && defined(HAVE_LIBLBER)
49129 "\t+ LDAP support\n"
49130 @@ -410,8 +410,11 @@
49132 "\t- GDBM support\n"
49140 + printf("\nEvent Handlers:\n\n%s", s);
49143 static void show_help (void) {
49144 @@ -433,277 +436,644 @@
49145 " -h show this help\n" \
49151 write(STDOUT_FILENO, b, strlen(b));
49154 -int main (int argc, char **argv) {
49155 - server *srv = NULL;
49156 - int print_config = 0;
49157 - int test_config = 0;
49160 - int num_childs = 0;
49161 - int pid_fd = -1, fd;
49163 -#ifdef HAVE_SIGACTION
49164 - struct sigaction act;
49166 -#ifdef HAVE_GETRLIMIT
49167 - struct rlimit rlim;
49171 - struct itimerval interval;
49173 - interval.it_interval.tv_sec = 1;
49174 - interval.it_interval.tv_usec = 0;
49175 - interval.it_value.tv_sec = 1;
49176 - interval.it_value.tv_usec = 0;
49180 - /* for nice %b handling in strfime() */
49181 - setlocale(LC_TIME, "C");
49183 - if (NULL == (srv = server_init())) {
49184 - fprintf(stderr, "did this really happen?\n");
49188 - /* init structs done */
49190 - srv->srvconf.port = 0;
49191 -#ifdef HAVE_GETUID
49192 - i_am_root = (getuid() == 0);
49196 - srv->srvconf.dont_daemonize = 0;
49198 - while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49201 - if (config_read(srv, optarg)) {
49202 - server_free(srv);
49207 - buffer_copy_string(srv->srvconf.modules_dir, optarg);
49209 - case 'p': print_config = 1; break;
49210 - case 't': test_config = 1; break;
49211 - case 'D': srv->srvconf.dont_daemonize = 1; break;
49212 - case 'v': show_version(); return 0;
49213 - case 'V': show_features(); return 0;
49214 - case 'h': show_help(); return 0;
49217 - server_free(srv);
49222 - if (!srv->config_storage) {
49223 - log_error_write(srv, __FILE__, __LINE__, "s",
49224 - "No configuration available. Try using -f option.");
49226 - server_free(srv);
49230 - if (print_config) {
49231 - data_unset *dc = srv->config_context->data[0];
49233 - dc->print(dc, 0);
49234 - fprintf(stderr, "\n");
49236 - /* shouldn't happend */
49237 - fprintf(stderr, "global config not found\n");
49240 +int lighty_mainloop(server *srv) {
49241 + fdevent_revents *revents = fdevent_revents_init();
49243 - if (test_config) {
49244 - printf("Syntax OK\n");
49247 + while (!srv_shutdown) {
49252 - if (test_config || print_config) {
49253 - server_free(srv);
49257 - /* close stdin and stdout, as they are not needed */
49258 - /* move stdin to /dev/null */
49259 - if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49260 - close(STDIN_FILENO);
49261 - dup2(fd, STDIN_FILENO);
49265 - /* move stdout to /dev/null */
49266 - if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49267 - close(STDOUT_FILENO);
49268 - dup2(fd, STDOUT_FILENO);
49272 - if (0 != config_set_defaults(srv)) {
49273 - log_error_write(srv, __FILE__, __LINE__, "s",
49274 - "setting default values failed");
49275 - server_free(srv);
49279 - /* UID handling */
49280 -#ifdef HAVE_GETUID
49281 - if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49282 - /* we are setuid-root */
49284 - log_error_write(srv, __FILE__, __LINE__, "s",
49285 - "Are you nuts ? Don't apply a SUID bit to this binary");
49287 - server_free(srv);
49292 - /* check document-root */
49293 - if (srv->config_storage[0]->document_root->used <= 1) {
49294 - log_error_write(srv, __FILE__, __LINE__, "s",
49295 - "document-root is not set\n");
49297 - server_free(srv);
49302 - if (plugins_load(srv)) {
49303 - log_error_write(srv, __FILE__, __LINE__, "s",
49304 - "loading plugins finally failed");
49306 - plugins_free(srv);
49307 - server_free(srv);
49312 - /* open pid file BEFORE chroot */
49313 - if (srv->srvconf.pid_file->used) {
49314 - 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))) {
49316 - if (errno != EEXIST) {
49317 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49318 - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49322 - if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49323 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49324 - "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49327 - if (!S_ISREG(st.st_mode)) {
49328 - log_error_write(srv, __FILE__, __LINE__, "sb",
49329 - "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49333 - if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49334 - log_error_write(srv, __FILE__, __LINE__, "sbs",
49335 - "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49337 + if (handle_sig_hup) {
49340 + /* reset notification */
49341 + handle_sig_hup = 0;
49346 + /* send the old process into a graceful-shutdown and start a
49347 + * new process right away
49350 + * - if webserver is running on port < 1024 (e.g. 80, 433)
49351 + * we don't have the permissions to bind to that port anymore
49355 + if (0 == (pid = fork())) {
49356 + execve(argv[0], argv, envp);
49359 + } else if (pid == -1) {
49364 + graceful_shutdown = 1; /* shutdown without killing running connections */
49365 + graceful_restart = 1; /* don't delete pid file */
49370 + /* cycle logfiles */
49372 - if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49373 - /* select limits itself
49375 - * as it is a hard limit and will lead to a segfault we add some safety
49377 - srv->max_fds = FD_SETSIZE - 200;
49379 - srv->max_fds = 4096;
49381 + switch(r = plugins_call_handle_sighup(srv)) {
49382 + case HANDLER_GO_ON:
49385 + log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
49390 - struct group *grp = NULL;
49391 - struct passwd *pwd = NULL;
49392 - int use_rlimit = 1;
49393 + if (-1 == log_error_cycle()) {
49394 + log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
49396 -#ifdef HAVE_VALGRIND_VALGRIND_H
49397 - if (RUNNING_ON_VALGRIND) use_rlimit = 0;
49400 -#ifdef HAVE_GETRLIMIT
49401 - if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
49402 - log_error_write(srv, __FILE__, __LINE__,
49403 - "ss", "couldn't get 'max filedescriptors'",
49404 - strerror(errno));
49408 - if (use_rlimit && srv->srvconf.max_fds) {
49409 - /* set rlimits */
49411 - rlim.rlim_cur = srv->srvconf.max_fds;
49412 - rlim.rlim_max = srv->srvconf.max_fds;
49414 - if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
49415 - log_error_write(srv, __FILE__, __LINE__,
49416 - "ss", "couldn't set 'max filedescriptors'",
49417 - strerror(errno));
49423 - /* #372: solaris need some fds extra for devpoll */
49424 - if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
49425 + if (handle_sig_alarm) {
49426 + /* a new second */
49428 - if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49429 - srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
49431 - srv->max_fds = rlim.rlim_cur;
49434 + /* reset notification */
49435 + handle_sig_alarm = 0;
49438 - /* set core file rlimit, if enable_cores is set */
49439 - if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
49440 - rlim.rlim_cur = rlim.rlim_max;
49441 + /* get current time */
49442 + min_ts = time(NULL);
49444 + if (min_ts != srv->cur_ts) {
49446 + connections *conns = srv->conns;
49449 + switch(r = plugins_call_handle_trigger(srv)) {
49450 + case HANDLER_GO_ON:
49452 + case HANDLER_ERROR:
49453 + log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
49456 + log_error_write(srv, __FILE__, __LINE__, "d", r);
49460 + /* trigger waitpid */
49461 + srv->cur_ts = min_ts;
49463 + /* cleanup stat-cache */
49464 + stat_cache_trigger_cleanup(srv);
49466 + * check all connections for timeouts
49469 + for (ndx = 0; ndx < conns->used; ndx++) {
49474 + con = conns->ptr[ndx];
49476 + if (con->state == CON_STATE_READ ||
49477 + con->state == CON_STATE_READ_POST) {
49478 + if (con->request_count == 1) {
49479 + if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
49482 + log_error_write(srv, __FILE__, __LINE__, "sd",
49483 + "connection closed - read-timeout:", con->fd);
49485 + connection_set_state(srv, con, CON_STATE_ERROR);
49489 + if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
49492 + log_error_write(srv, __FILE__, __LINE__, "sd",
49493 + "connection closed - read-timeout:", con->fd);
49495 + connection_set_state(srv, con, CON_STATE_ERROR);
49501 + if ((con->state == CON_STATE_WRITE) &&
49502 + (con->write_request_ts != 0)) {
49504 + if (srv->cur_ts - con->write_request_ts > 60) {
49505 + log_error_write(srv, __FILE__, __LINE__, "sdd",
49506 + "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
49510 + if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
49513 + log_error_write(srv, __FILE__, __LINE__, "sbsosds",
49514 + "NOTE: a request for",
49515 + con->request.uri,
49516 + "timed out after writing",
49517 + con->bytes_written,
49518 + "bytes. We waited",
49519 + (int)con->conf.max_write_idle,
49520 + "seconds. If this a problem increase server.max-write-idle");
49522 + connection_set_state(srv, con, CON_STATE_ERROR);
49526 + /* we don't like div by zero */
49527 + if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
49529 + if (con->traffic_limit_reached &&
49530 + (con->conf.kbytes_per_second == 0 ||
49531 + ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
49532 + /* enable connection again */
49533 + con->traffic_limit_reached = 0;
49539 + connection_state_machine(srv, con);
49541 + con->bytes_written_cur_second = 0;
49542 + *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
49546 + fprintf(stderr, "connection-state: ");
49550 + fprintf(stderr, "c[%d,%d]: %s ",
49553 + connection_get_state(con->state));
49557 + if (cs == 1) fprintf(stderr, "\n");
49561 + if (srv->sockets_disabled) {
49562 + /* our server sockets are disabled, why ? */
49564 + if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
49565 + (srv->conns->used < srv->max_conns * 0.9) &&
49566 + (0 == graceful_shutdown)) {
49569 + for (i = 0; i < srv->srv_sockets.used; i++) {
49570 + server_socket *srv_socket = srv->srv_sockets.ptr[i];
49571 + fdevent_event_add(srv->ev, srv_socket->sock, FDEVENT_IN);
49574 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
49576 + srv->sockets_disabled = 0;
49579 + if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
49580 + (srv->conns->used > srv->max_conns) || /* out of connections */
49581 + (graceful_shutdown)) { /* graceful_shutdown */
49584 + /* disable server-fds */
49586 + for (i = 0; i < srv->srv_sockets.used; i++) {
49587 + server_socket *srv_socket = srv->srv_sockets.ptr[i];
49588 + fdevent_event_del(srv->ev, srv_socket->sock);
49590 + if (graceful_shutdown) {
49591 + /* we don't want this socket anymore,
49593 + * closing it right away will make it possible for
49594 + * the next lighttpd to take over (graceful restart)
49597 + fdevent_unregister(srv->ev, srv_socket->sock);
49598 + closesocket(srv_socket->sock->fd);
49599 + srv_socket->sock->fd = -1;
49601 + /* network_close() will cleanup after us */
49605 + if (graceful_shutdown) {
49606 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
49607 + } else if (srv->conns->used > srv->max_conns) {
49608 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
49610 + log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
49613 + srv->sockets_disabled = 1;
49617 + if (graceful_shutdown && srv->conns->used == 0) {
49618 + /* we are in graceful shutdown phase and all connections are closed
49619 + * we are ready to terminate without harming anyone */
49620 + srv_shutdown = 1;
49623 + /* we still have some fds to share */
49624 + if (srv->want_fds) {
49625 + /* check the fdwaitqueue for waiting fds */
49626 + int free_fds = srv->max_fds - srv->cur_fds - 16;
49629 + for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
49630 + connection_state_machine(srv, con);
49636 + if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
49637 + /* n is the number of events */
49639 + fdevent_get_revents(srv->ev, n, revents);
49641 + /* handle client connections first
49643 + * this is a bit of a hack, but we have to make sure than we handle
49644 + * close-events before the connection is reused for a keep-alive
49647 + * this is mostly an issue for mod_proxy_core, but you never know
49651 + for (i = 0; i < revents->used; i++) {
49652 + fdevent_revent *revent = revents->ptr[i];
49655 + /* skip server-fds */
49656 + if (revent->handler == network_server_handle_fdevent) continue;
49658 + switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
49659 + case HANDLER_FINISHED:
49660 + case HANDLER_GO_ON:
49661 + case HANDLER_WAIT_FOR_EVENT:
49662 + case HANDLER_WAIT_FOR_FD:
49664 + case HANDLER_ERROR:
49665 + /* should never happen */
49669 + log_error_write(srv, __FILE__, __LINE__, "d", r);
49674 + for (i = 0; i < revents->used; i++) {
49675 + fdevent_revent *revent = revents->ptr[i];
49678 + /* server fds only */
49679 + if (revent->handler != network_server_handle_fdevent) continue;
49681 + switch (r = (*(revent->handler))(srv, revent->context, revent->revents)) {
49682 + case HANDLER_FINISHED:
49683 + case HANDLER_GO_ON:
49684 + case HANDLER_WAIT_FOR_EVENT:
49685 + case HANDLER_WAIT_FOR_FD:
49687 + case HANDLER_ERROR:
49688 + /* should never happen */
49692 + log_error_write(srv, __FILE__, __LINE__, "d", r);
49697 + } else if (n < 0 && errno != EINTR) {
49698 + log_error_write(srv, __FILE__, __LINE__, "ss",
49699 + "fdevent_poll failed:",
49700 + strerror(errno));
49703 + for (ndx = 0; ndx < srv->joblist->used; ndx++) {
49704 + connection *con = srv->joblist->ptr[ndx];
49707 + connection_state_machine(srv, con);
49709 + switch(r = plugins_call_handle_joblist(srv, con)) {
49710 + case HANDLER_FINISHED:
49711 + case HANDLER_GO_ON:
49714 + log_error_write(srv, __FILE__, __LINE__, "d", r);
49718 + con->in_joblist = 0;
49721 + srv->joblist->used = 0;
49724 + fdevent_revents_free(revents);
49730 +int main (int argc, char **argv, char **envp) {
49731 + server *srv = NULL;
49732 + int print_config = 0;
49733 + int test_config = 0;
49736 + int num_childs = 0;
49737 + int pid_fd = -1, fd;
49740 + char *optarg = NULL;
49743 +#ifdef HAVE_SIGACTION
49744 + struct sigaction act;
49746 +#ifdef HAVE_GETRLIMIT
49747 + struct rlimit rlim;
49751 + struct itimerval interval;
49753 + interval.it_interval.tv_sec = 1;
49754 + interval.it_interval.tv_usec = 0;
49755 + interval.it_value.tv_sec = 1;
49756 + interval.it_value.tv_usec = 0;
49761 + /* for nice %b handling in strfime() */
49762 + setlocale(LC_TIME, "C");
49764 + if (NULL == (srv = server_init())) {
49765 + fprintf(stderr, "did this really happen?\n");
49769 + /* init structs done */
49771 + srv->srvconf.port = 0;
49772 +#ifdef HAVE_GETUID
49773 + i_am_root = (getuid() == 0);
49777 + srv->srvconf.dont_daemonize = 0;
49779 + while(-1 != (o = getopt(argc, argv, "f:m:hvVDpt"))) {
49783 + /* evil HACK for windows, optarg is not set */
49784 + optarg = argv[optind-1];
49786 + if (config_read(srv, optarg)) {
49787 + server_free(srv);
49793 + buffer_copy_string(srv->srvconf.modules_dir, optarg);
49795 + case 'p': print_config = 1; break;
49796 + case 't': test_config = 1; break;
49797 + case 'D': srv->srvconf.dont_daemonize = 1; break;
49798 + case 'v': show_version(); return 0;
49799 + case 'V': show_features(); return 0;
49800 + case 'h': show_help(); return 0;
49803 + server_free(srv);
49808 + if (!srv->config_storage) {
49809 + log_error_write(srv, __FILE__, __LINE__, "s",
49810 + "No configuration available. Try using -f option.");
49812 + server_free(srv);
49816 + if (print_config) {
49817 + data_unset *dc = srv->config_context->data[0];
49819 + dc->print(dc, 0);
49820 + fprintf(stderr, "\n");
49822 + /* shouldn't happend */
49823 + fprintf(stderr, "global config not found\n");
49827 + if (test_config) {
49828 + printf("Syntax OK\n");
49831 + if (test_config || print_config) {
49832 + server_free(srv);
49836 + /* close stdin and stdout, as they are not needed */
49837 + /* move stdin to /dev/null */
49838 + if (-1 != (fd = open("/dev/null", O_RDONLY))) {
49839 + close(STDIN_FILENO);
49840 + dup2(fd, STDIN_FILENO);
49844 + /* move stdout to /dev/null */
49845 + if (-1 != (fd = open("/dev/null", O_WRONLY))) {
49846 + close(STDOUT_FILENO);
49847 + dup2(fd, STDOUT_FILENO);
49851 + if (0 != config_set_defaults(srv)) {
49852 + log_error_write(srv, __FILE__, __LINE__, "s",
49853 + "setting default values failed");
49854 + server_free(srv);
49858 + /* UID handling */
49859 +#ifdef HAVE_GETUID
49860 + if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
49861 + /* we are setuid-root */
49863 + log_error_write(srv, __FILE__, __LINE__, "s",
49864 + "Are you nuts ? Don't apply a SUID bit to this binary");
49866 + server_free(srv);
49871 + /* check document-root */
49872 + if (srv->config_storage[0]->document_root->used <= 1) {
49873 + log_error_write(srv, __FILE__, __LINE__, "s",
49874 + "document-root is not set\n");
49876 + server_free(srv);
49881 + if (plugins_load(srv)) {
49882 + log_error_write(srv, __FILE__, __LINE__, "s",
49883 + "loading plugins finally failed");
49885 + plugins_free(srv);
49886 + server_free(srv);
49892 + /* open pid file BEFORE chroot */
49893 + if (srv->srvconf.pid_file->used) {
49894 + 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))) {
49896 + if (errno != EEXIST) {
49897 + log_error_write(srv, __FILE__, __LINE__, "sbs",
49898 + "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49902 + if (0 != stat(srv->srvconf.pid_file->ptr, &st)) {
49903 + log_error_write(srv, __FILE__, __LINE__, "sbs",
49904 + "stating existing pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49907 + if (!S_ISREG(st.st_mode)) {
49908 + log_error_write(srv, __FILE__, __LINE__, "sb",
49909 + "pid-file exists and isn't regular file:", srv->srvconf.pid_file);
49913 + if (-1 == (pid_fd = open(srv->srvconf.pid_file->ptr, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
49914 + log_error_write(srv, __FILE__, __LINE__, "sbs",
49915 + "opening pid-file failed:", srv->srvconf.pid_file, strerror(errno));
49921 + if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49922 + /* select limits itself
49924 + * as it is a hard limit and will lead to a segfault we add some safety
49926 + fprintf(stderr, "%s.%d: max parallel connections: %d\r\n", __FILE__, __LINE__, FD_SETSIZE);
49927 + srv->max_fds = FD_SETSIZE - 4;
49929 + srv->max_fds = 4096;
49933 + struct group *grp = NULL;
49934 + struct passwd *pwd = NULL;
49935 + int use_rlimit = 1;
49937 +#ifdef HAVE_VALGRIND_VALGRIND_H
49938 + if (RUNNING_ON_VALGRIND) use_rlimit = 0;
49941 +#ifdef HAVE_GETRLIMIT
49942 + if (0 != getrlimit(RLIMIT_NOFILE, &rlim)) {
49943 + log_error_write(srv, __FILE__, __LINE__,
49944 + "ss", "couldn't get 'max filedescriptors'",
49945 + strerror(errno));
49949 + if (use_rlimit && srv->srvconf.max_fds) {
49950 + /* set rlimits */
49952 + rlim.rlim_cur = srv->srvconf.max_fds;
49953 + rlim.rlim_max = srv->srvconf.max_fds;
49955 + if (0 != setrlimit(RLIMIT_NOFILE, &rlim)) {
49956 + log_error_write(srv, __FILE__, __LINE__,
49957 + "ss", "couldn't set 'max filedescriptors'",
49958 + strerror(errno));
49963 + /* #372: solaris need some fds extra for devpoll */
49964 + if (rlim.rlim_cur > 10) rlim.rlim_cur -= 10;
49966 + if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49967 + srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
49969 + srv->max_fds = rlim.rlim_cur;
49972 + /* set core file rlimit, if enable_cores is set */
49973 + if (use_rlimit && srv->srvconf.enable_cores && getrlimit(RLIMIT_CORE, &rlim) == 0) {
49974 + rlim.rlim_cur = rlim.rlim_max;
49975 setrlimit(RLIMIT_CORE, &rlim);
49978 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
49979 /* don't raise the limit above FD_SET_SIZE */
49980 if (srv->max_fds > FD_SETSIZE - 200) {
49981 - log_error_write(srv, __FILE__, __LINE__, "sd",
49982 + log_error_write(srv, __FILE__, __LINE__, "sd",
49983 "can't raise max filedescriptors above", FD_SETSIZE - 200,
49984 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
49992 /* set user and group */
49993 if (srv->srvconf.username->used) {
49994 if (NULL == (pwd = getpwnam(srv->srvconf.username->ptr))) {
49995 - log_error_write(srv, __FILE__, __LINE__, "sb",
49996 + log_error_write(srv, __FILE__, __LINE__, "sb",
49997 "can't find username", srv->srvconf.username);
50002 if (pwd->pw_uid == 0) {
50003 log_error_write(srv, __FILE__, __LINE__, "s",
50004 "I will not set uid to 0\n");
50010 if (srv->srvconf.groupname->used) {
50011 if (NULL == (grp = getgrnam(srv->srvconf.groupname->ptr))) {
50012 - log_error_write(srv, __FILE__, __LINE__, "sb",
50013 + log_error_write(srv, __FILE__, __LINE__, "sb",
50014 "can't find groupname", srv->srvconf.groupname);
50017 @@ -713,15 +1083,15 @@
50023 /* we need root-perms for port < 1024 */
50024 if (0 != network_init(srv)) {
50031 -#ifdef HAVE_CHROOT
50032 +#ifdef HAVE_CHROOT
50033 if (srv->srvconf.changeroot->used) {
50036 @@ -761,7 +1131,7 @@
50039 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50040 - srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 200 ? rlim.rlim_cur : FD_SETSIZE - 200;
50041 + srv->max_fds = rlim.rlim_cur < FD_SETSIZE - 4 ? rlim.rlim_cur : FD_SETSIZE - 4;
50043 srv->max_fds = rlim.rlim_cur;
50045 @@ -775,18 +1145,18 @@
50047 if (srv->event_handler == FDEVENT_HANDLER_SELECT) {
50048 /* don't raise the limit above FD_SET_SIZE */
50049 - if (srv->max_fds > FD_SETSIZE - 200) {
50050 - log_error_write(srv, __FILE__, __LINE__, "sd",
50051 - "can't raise max filedescriptors above", FD_SETSIZE - 200,
50052 + if (srv->max_fds > FD_SETSIZE - 4) {
50053 + log_error_write(srv, __FILE__, __LINE__, "sd",
50054 + "can't raise max filedescriptors above", FD_SETSIZE - 4,
50055 "if event-handler is 'select'. Use 'poll' or something else or reduce server.max-fds.");
50061 if (0 != network_init(srv)) {
50069 @@ -802,25 +1172,27 @@
50070 /* or use the default */
50071 srv->max_conns = srv->max_fds;
50075 if (HANDLER_GO_ON != plugins_call_init(srv)) {
50076 log_error_write(srv, __FILE__, __LINE__, "s", "Initialization of plugins failed. Going down.");
50080 network_close(srv);
50089 /* network is up, let's deamonize ourself */
50090 if (srv->srvconf.dont_daemonize == 0) daemonize();
50094 srv->gid = getgid();
50095 srv->uid = getuid();
50099 /* write pid file */
50100 if (pid_fd != -1) {
50101 buffer_copy_long(srv->tmp_buf, getpid());
50102 @@ -829,17 +1201,17 @@
50108 if (HANDLER_GO_ON != plugins_call_set_defaults(srv)) {
50109 log_error_write(srv, __FILE__, __LINE__, "s", "Configuration of plugins failed. Going down.");
50113 network_close(srv);
50121 /* dump unused config-keys */
50122 for (i = 0; i < srv->config_context->used; i++) {
50123 array *config = ((data_config *)srv->config_context->data[i])->value;
50124 @@ -847,43 +1219,42 @@
50126 for (j = 0; config && j < config->used; j++) {
50127 data_unset *du = config->data[j];
50130 /* all var.* is known as user defined variable */
50131 if (strncmp(du->key->ptr, "var.", sizeof("var.") - 1) == 0) {
50135 if (NULL == array_get_element(srv->config_touched, du->key->ptr)) {
50136 - log_error_write(srv, __FILE__, __LINE__, "sbs",
50137 + log_error_write(srv, __FILE__, __LINE__, "sbs",
50138 "WARNING: unknown config-key:",
50146 if (srv->config_deprecated) {
50147 - log_error_write(srv, __FILE__, __LINE__, "s",
50148 + log_error_write(srv, __FILE__, __LINE__, "s",
50149 "Configuration contains deprecated keys. Going down.");
50153 network_close(srv);
50160 - if (-1 == log_error_open(srv)) {
50161 - log_error_write(srv, __FILE__, __LINE__, "s",
50163 + if (-1 == log_error_open(srv->srvconf.errorlog_file, srv->srvconf.errorlog_use_syslog)) {
50164 + log_error_write(srv, __FILE__, __LINE__, "s",
50165 "opening errorlog failed, dying");
50169 network_close(srv);
50176 #ifdef HAVE_SIGACTION
50177 memset(&act, 0, sizeof(act));
50178 act.sa_handler = SIG_IGN;
50179 @@ -903,7 +1274,7 @@
50180 sigaction(SIGHUP, &act, NULL);
50181 sigaction(SIGALRM, &act, NULL);
50182 sigaction(SIGCHLD, &act, NULL);
50185 #elif defined(HAVE_SIGNAL)
50186 /* ignore the SIGPIPE from sendfile() */
50187 signal(SIGPIPE, SIG_IGN);
50188 @@ -914,20 +1285,20 @@
50189 signal(SIGCHLD, signal_handler);
50190 signal(SIGINT, signal_handler);
50195 signal(SIGALRM, signal_handler);
50198 /* setup periodic timer (1 second) */
50199 if (setitimer(ITIMER_REAL, &interval, NULL)) {
50200 log_error_write(srv, __FILE__, __LINE__, "s", "setting timer failed");
50205 getitimer(ITIMER_REAL, &interval);
50210 /* start watcher and workers */
50211 num_childs = srv->srvconf.max_worker;
50212 if (num_childs > 0) {
50213 @@ -957,13 +1328,13 @@
50217 - if (NULL == (srv->ev = fdevent_init(srv->max_fds + 1, srv->event_handler))) {
50218 + if (NULL == (srv->ev = fdevent_init(/*srv->max_fds + 1*/ 4096, srv->event_handler))) {
50219 log_error_write(srv, __FILE__, __LINE__,
50220 "s", "fdevent_init failed");
50224 - * kqueue() is called here, select resets its internals,
50226 + * kqueue() is called here, select resets its internals,
50227 * all server sockets get their handlers
50230 @@ -971,7 +1342,7 @@
50232 network_close(srv);
50239 @@ -986,17 +1357,17 @@
50241 if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) {
50242 if (0 != FAMOpen2(srv->stat_cache->fam, "lighttpd")) {
50243 - log_error_write(srv, __FILE__, __LINE__, "s",
50244 + log_error_write(srv, __FILE__, __LINE__, "s",
50245 "could not open a fam connection, dieing.");
50248 #ifdef HAVE_FAMNOEXISTS
50249 FAMNoExists(srv->stat_cache->fam);
50251 + srv->stat_cache->sock->fd = FAMCONNECTION_GETFD(srv->stat_cache->fam);
50253 - srv->stat_cache->fam_fcce_ndx = -1;
50254 - fdevent_register(srv->ev, FAMCONNECTION_GETFD(srv->stat_cache->fam), stat_cache_handle_fdevent, NULL);
50255 - fdevent_event_add(srv->ev, &(srv->stat_cache->fam_fcce_ndx), FAMCONNECTION_GETFD(srv->stat_cache->fam), FDEVENT_IN);
50256 + fdevent_register(srv->ev, srv->stat_cache->sock, stat_cache_handle_fdevent, NULL);
50257 + fdevent_event_add(srv->ev, srv->stat_cache->sock, FDEVENT_IN);
50261 @@ -1007,330 +1378,34 @@
50263 for (i = 0; i < srv->srv_sockets.used; i++) {
50264 server_socket *srv_socket = srv->srv_sockets.ptr[i];
50265 - if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->fd)) {
50266 + if (-1 == fdevent_fcntl_set(srv->ev, srv_socket->sock)) {
50267 log_error_write(srv, __FILE__, __LINE__, "ss", "fcntl failed:", strerror(errno));
50273 - while (!srv_shutdown) {
50278 - if (handle_sig_hup) {
50281 - /* reset notification */
50282 - handle_sig_hup = 0;
50285 - /* cycle logfiles */
50287 - switch(r = plugins_call_handle_sighup(srv)) {
50288 - case HANDLER_GO_ON:
50291 - log_error_write(srv, __FILE__, __LINE__, "sd", "sighup-handler return with an error", r);
50295 - if (-1 == log_error_cycle(srv)) {
50296 - log_error_write(srv, __FILE__, __LINE__, "s", "cycling errorlog failed, dying");
50302 - if (handle_sig_alarm) {
50303 - /* a new second */
50306 - /* reset notification */
50307 - handle_sig_alarm = 0;
50310 - /* get current time */
50311 - min_ts = time(NULL);
50313 - if (min_ts != srv->cur_ts) {
50315 - connections *conns = srv->conns;
50318 - switch(r = plugins_call_handle_trigger(srv)) {
50319 - case HANDLER_GO_ON:
50321 - case HANDLER_ERROR:
50322 - log_error_write(srv, __FILE__, __LINE__, "s", "one of the triggers failed");
50325 - log_error_write(srv, __FILE__, __LINE__, "d", r);
50329 - /* trigger waitpid */
50330 - srv->cur_ts = min_ts;
50332 - /* cleanup stat-cache */
50333 - stat_cache_trigger_cleanup(srv);
50335 - * check all connections for timeouts
50338 - for (ndx = 0; ndx < conns->used; ndx++) {
50343 - con = conns->ptr[ndx];
50345 - if (con->state == CON_STATE_READ ||
50346 - con->state == CON_STATE_READ_POST) {
50347 - if (con->request_count == 1) {
50348 - if (srv->cur_ts - con->read_idle_ts > con->conf.max_read_idle) {
50351 - log_error_write(srv, __FILE__, __LINE__, "sd",
50352 - "connection closed - read-timeout:", con->fd);
50354 - connection_set_state(srv, con, CON_STATE_ERROR);
50358 - if (srv->cur_ts - con->read_idle_ts > con->conf.max_keep_alive_idle) {
50361 - log_error_write(srv, __FILE__, __LINE__, "sd",
50362 - "connection closed - read-timeout:", con->fd);
50364 - connection_set_state(srv, con, CON_STATE_ERROR);
50370 - if ((con->state == CON_STATE_WRITE) &&
50371 - (con->write_request_ts != 0)) {
50373 - if (srv->cur_ts - con->write_request_ts > 60) {
50374 - log_error_write(srv, __FILE__, __LINE__, "sdd",
50375 - "connection closed - pre-write-request-timeout:", con->fd, srv->cur_ts - con->write_request_ts);
50379 - if (srv->cur_ts - con->write_request_ts > con->conf.max_write_idle) {
50382 - log_error_write(srv, __FILE__, __LINE__, "sbsosds",
50383 - "NOTE: a request for",
50384 - con->request.uri,
50385 - "timed out after writing",
50386 - con->bytes_written,
50387 - "bytes. We waited",
50388 - (int)con->conf.max_write_idle,
50389 - "seconds. If this a problem increase server.max-write-idle");
50391 - connection_set_state(srv, con, CON_STATE_ERROR);
50395 - /* we don't like div by zero */
50396 - if (0 == (t_diff = srv->cur_ts - con->connection_start)) t_diff = 1;
50398 - if (con->traffic_limit_reached &&
50399 - (con->conf.kbytes_per_second == 0 ||
50400 - ((con->bytes_written / t_diff) < con->conf.kbytes_per_second * 1024))) {
50401 - /* enable connection again */
50402 - con->traffic_limit_reached = 0;
50408 - connection_state_machine(srv, con);
50410 - con->bytes_written_cur_second = 0;
50411 - *(con->conf.global_bytes_per_second_cnt_ptr) = 0;
50415 - fprintf(stderr, "connection-state: ");
50419 - fprintf(stderr, "c[%d,%d]: %s ",
50422 - connection_get_state(con->state));
50426 - if (cs == 1) fprintf(stderr, "\n");
50430 - if (srv->sockets_disabled) {
50431 - /* our server sockets are disabled, why ? */
50433 - if ((srv->cur_fds + srv->want_fds < srv->max_fds * 0.8) && /* we have enough unused fds */
50434 - (srv->conns->used < srv->max_conns * 0.9) &&
50435 - (0 == graceful_shutdown)) {
50436 - for (i = 0; i < srv->srv_sockets.used; i++) {
50437 - server_socket *srv_socket = srv->srv_sockets.ptr[i];
50438 - fdevent_event_add(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd, FDEVENT_IN);
50441 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets enabled again");
50443 - srv->sockets_disabled = 0;
50446 - if ((srv->cur_fds + srv->want_fds > srv->max_fds * 0.9) || /* out of fds */
50447 - (srv->conns->used > srv->max_conns) || /* out of connections */
50448 - (graceful_shutdown)) { /* graceful_shutdown */
50450 - /* disable server-fds */
50452 - for (i = 0; i < srv->srv_sockets.used; i++) {
50453 - server_socket *srv_socket = srv->srv_sockets.ptr[i];
50454 - fdevent_event_del(srv->ev, &(srv_socket->fde_ndx), srv_socket->fd);
50456 - if (graceful_shutdown) {
50457 - /* we don't want this socket anymore,
50459 - * closing it right away will make it possible for
50460 - * the next lighttpd to take over (graceful restart)
50463 - fdevent_unregister(srv->ev, srv_socket->fd);
50464 - close(srv_socket->fd);
50465 - srv_socket->fd = -1;
50467 - /* network_close() will cleanup after us */
50471 - if (graceful_shutdown) {
50472 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] graceful shutdown started");
50473 - } else if (srv->conns->used > srv->max_conns) {
50474 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, connection limit reached");
50476 - log_error_write(srv, __FILE__, __LINE__, "s", "[note] sockets disabled, out-of-fds");
50479 - srv->sockets_disabled = 1;
50483 - if (graceful_shutdown && srv->conns->used == 0) {
50484 - /* we are in graceful shutdown phase and all connections are closed
50485 - * we are ready to terminate without harming anyone */
50486 - srv_shutdown = 1;
50489 - /* we still have some fds to share */
50490 - if (srv->want_fds) {
50491 - /* check the fdwaitqueue for waiting fds */
50492 - int free_fds = srv->max_fds - srv->cur_fds - 16;
50495 - for (; free_fds > 0 && NULL != (con = fdwaitqueue_unshift(srv, srv->fdwaitqueue)); free_fds--) {
50496 - connection_state_machine(srv, con);
50501 + lighty_mainloop(srv);
50503 - if ((n = fdevent_poll(srv->ev, 1000)) > 0) {
50504 - /* n is the number of events */
50509 - log_error_write(srv, __FILE__, __LINE__, "sd",
50515 - fdevent_handler handler;
50519 - fd_ndx = fdevent_event_next_fdndx (srv->ev, fd_ndx);
50520 - revents = fdevent_event_get_revent (srv->ev, fd_ndx);
50521 - fd = fdevent_event_get_fd (srv->ev, fd_ndx);
50522 - handler = fdevent_get_handler(srv->ev, fd);
50523 - context = fdevent_get_context(srv->ev, fd);
50525 - /* connection_handle_fdevent needs a joblist_append */
50527 - log_error_write(srv, __FILE__, __LINE__, "sdd",
50528 - "event for", fd, revents);
50530 - switch (r = (*handler)(srv, context, revents)) {
50531 - case HANDLER_FINISHED:
50532 - case HANDLER_GO_ON:
50533 - case HANDLER_WAIT_FOR_EVENT:
50534 - case HANDLER_WAIT_FOR_FD:
50536 - case HANDLER_ERROR:
50537 - /* should never happen */
50541 - log_error_write(srv, __FILE__, __LINE__, "d", r);
50544 - } while (--n > 0);
50545 - } else if (n < 0 && errno != EINTR) {
50546 - log_error_write(srv, __FILE__, __LINE__, "ss",
50547 - "fdevent_poll failed:",
50548 - strerror(errno));
50551 - for (ndx = 0; ndx < srv->joblist->used; ndx++) {
50552 - connection *con = srv->joblist->ptr[ndx];
50555 - connection_state_machine(srv, con);
50557 - switch(r = plugins_call_handle_joblist(srv, con)) {
50558 - case HANDLER_FINISHED:
50559 - case HANDLER_GO_ON:
50562 - log_error_write(srv, __FILE__, __LINE__, "d", r);
50566 - con->in_joblist = 0;
50569 - srv->joblist->used = 0;
50572 - if (srv->srvconf.pid_file->used &&
50573 + if (0 == graceful_restart &&
50574 + srv->srvconf.pid_file->used &&
50575 srv->srvconf.changeroot->used == 0) {
50576 if (0 != unlink(srv->srvconf.pid_file->ptr)) {
50577 if (errno != EACCES && errno != EPERM) {
50578 - log_error_write(srv, __FILE__, __LINE__, "sbds",
50579 - "unlink failed for:",
50580 + log_error_write(srv, __FILE__, __LINE__, "sbds",
50581 + "unlink failed for:",
50582 srv->srvconf.pid_file,
50591 - log_error_close(srv);
50592 network_close(srv);
50593 connections_free(srv);
50601 --- ../lighttpd-1.4.11/src/settings.h 2005-08-11 01:26:41.000000000 +0300
50602 +++ lighttpd-1.4.12/src/settings.h 2006-07-16 00:26:04.000000000 +0300
50605 * max size of a buffer which will just be reset
50606 * to ->used = 0 instead of really freeing the buffer
50609 * 64kB (no real reason, just a guess)
50611 #define BUFFER_MAX_REUSE_SIZE (4 * 1024)
50614 * max size of the HTTP request header
50617 * 32k should be enough for everything (just a guess)
50621 #define MAX_HTTP_REQUEST_HEADER (32 * 1024)
50623 -typedef enum { HANDLER_UNSET,
50625 +typedef enum { HANDLER_UNSET,
50628 - HANDLER_COMEBACK,
50629 - HANDLER_WAIT_FOR_EVENT,
50630 + HANDLER_COMEBACK,
50631 + HANDLER_WAIT_FOR_EVENT,
50633 HANDLER_WAIT_FOR_FD
50635 --- ../lighttpd-1.4.11/src/spawn-fcgi.c 2006-03-07 14:18:10.000000000 +0200
50636 +++ lighttpd-1.4.12/src/spawn-fcgi.c 2006-07-16 00:26:04.000000000 +0300
50638 #include <sys/types.h>
50639 -#include <sys/time.h>
50640 #include <sys/stat.h>
50642 #include <stdlib.h>
50643 #include <string.h>
50646 -#include <unistd.h>
50650 #ifdef HAVE_CONFIG_H
50651 #include "config.h"
50661 #include "sys-socket.h"
50662 +#include "sys-files.h"
50664 #ifdef HAVE_SYS_WAIT_H
50665 #include <sys/wait.h>
50666 @@ -45,28 +43,28 @@
50668 int socket_type, status;
50669 struct timeval tv = { 0, 100 * 1000 };
50672 struct sockaddr_un fcgi_addr_un;
50673 struct sockaddr_in fcgi_addr_in;
50674 struct sockaddr *fcgi_addr;
50680 if (child_count < 2) {
50685 if (child_count > 256) {
50693 memset(&fcgi_addr, 0, sizeof(fcgi_addr));
50696 fcgi_addr_un.sun_family = AF_UNIX;
50697 strcpy(fcgi_addr_un.sun_path, unixsocket);
50701 servlen = SUN_LEN(&fcgi_addr_un);
50703 @@ -84,50 +82,50 @@
50705 fcgi_addr_in.sin_port = htons(port);
50706 servlen = sizeof(fcgi_addr_in);
50709 socket_type = AF_INET;
50710 fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
50714 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
50715 - fprintf(stderr, "%s.%d\n",
50716 + fprintf(stderr, "%s.%d\n",
50717 __FILE__, __LINE__);
50722 if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
50723 /* server is not up, spawn in */
50728 if (unixsocket) unlink(unixsocket);
50734 /* reopen socket */
50735 if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
50736 - fprintf(stderr, "%s.%d\n",
50737 + fprintf(stderr, "%s.%d\n",
50738 __FILE__, __LINE__);
50743 if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
50744 - fprintf(stderr, "%s.%d\n",
50745 + fprintf(stderr, "%s.%d\n",
50746 __FILE__, __LINE__);
50750 /* create socket */
50751 if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
50752 - fprintf(stderr, "%s.%d: bind failed: %s\n",
50753 + fprintf(stderr, "%s.%d: bind failed: %s\n",
50754 __FILE__, __LINE__,
50760 if (-1 == listen(fcgi_fd, 1024)) {
50761 - fprintf(stderr, "%s.%d: fd = -1\n",
50762 + fprintf(stderr, "%s.%d: fd = -1\n",
50763 __FILE__, __LINE__);
50766 @@ -137,42 +135,45 @@
50774 char cgi_childs[64];
50781 + /* loose control terminal */
50784 /* is save as we limit to 256 childs */
50785 sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
50788 if(fcgi_fd != FCGI_LISTENSOCK_FILENO) {
50789 close(FCGI_LISTENSOCK_FILENO);
50790 dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO);
50795 /* we don't need the client socket */
50796 for (i = 3; i < 256; i++) {
50801 /* create environment */
50804 putenv(cgi_childs);
50807 /* fork and replace shell */
50808 b = malloc(strlen("exec ") + strlen(appPath) + 1);
50809 strcpy(b, "exec ");
50810 strcat(b, appPath);
50814 execl("/bin/sh", "sh", "-c", b, NULL);
50823 @@ -180,47 +181,47 @@
50830 select(0, NULL, NULL, NULL, &tv);
50833 switch (waitpid(child, &status, WNOHANG)) {
50835 - fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
50836 + fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
50837 __FILE__, __LINE__,
50841 /* write pid file */
50842 if (pid_fd != -1) {
50843 /* assume a 32bit pid_t */
50847 snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
50850 write(pid_fd, pidbuf, strlen(pidbuf));
50860 if (WIFEXITED(status)) {
50861 - fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
50862 + fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
50863 __FILE__, __LINE__,
50864 WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
50865 } else if (WIFSIGNALED(status)) {
50866 - fprintf(stderr, "%s.%d: child signaled: %d\n",
50867 + fprintf(stderr, "%s.%d: child signaled: %d\n",
50868 __FILE__, __LINE__,
50871 - fprintf(stderr, "%s.%d: child died somehow: %d\n",
50872 + fprintf(stderr, "%s.%d: child died somehow: %d\n",
50873 __FILE__, __LINE__,
50882 @@ -228,16 +229,16 @@
50883 __FILE__, __LINE__);
50895 void show_version () {
50896 char *b = "spawn-fcgi" "-" PACKAGE_VERSION \
50897 -" - spawns fastcgi processes\n"
50898 +" - spawns fastcgi processes\n"
50900 write(1, b, strlen(b));
50902 @@ -265,7 +266,7 @@
50905 int main(int argc, char **argv) {
50906 - char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
50907 + char *fcgi_app = NULL, *changeroot = NULL, *username = NULL,
50908 *groupname = NULL, *unixsocket = NULL, *pid_file = NULL,
50910 unsigned short port = 0;
50911 @@ -273,9 +274,9 @@
50917 i_am_root = (getuid() == 0);
50920 while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
50922 case 'f': fcgi_app = optarg; break;
50923 @@ -290,137 +291,137 @@
50924 case 'P': pid_file = optarg; /* PID file */ break;
50925 case 'v': show_version(); return 0;
50926 case 'h': show_help(); return 0;
50935 if (fcgi_app == NULL || (port == 0 && unixsocket == NULL)) {
50941 if (unixsocket && port) {
50942 - fprintf(stderr, "%s.%d: %s\n",
50943 + fprintf(stderr, "%s.%d: %s\n",
50944 __FILE__, __LINE__,
50945 "either a unix domain socket or a tcp-port, but not both\n");
50952 if (unixsocket && strlen(unixsocket) > UNIX_PATH_MAX - 1) {
50953 - fprintf(stderr, "%s.%d: %s\n",
50954 + fprintf(stderr, "%s.%d: %s\n",
50955 __FILE__, __LINE__,
50956 "path of the unix socket is too long\n");
50963 if (!i_am_root && (geteuid() == 0 || getegid() == 0)) {
50964 /* we are setuid-root */
50966 - fprintf(stderr, "%s.%d: %s\n",
50968 + fprintf(stderr, "%s.%d: %s\n",
50969 __FILE__, __LINE__,
50970 "Are you nuts ? Don't apply a SUID bit to this binary\n");
50979 (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)))) {
50981 if (errno != EEXIST) {
50982 - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
50983 + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
50984 __FILE__, __LINE__,
50985 pid_file, strerror(errno));
50992 /* ok, file exists */
50995 if (0 != stat(pid_file, &st)) {
50996 - fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
50997 + fprintf(stderr, "%s.%d: stating pid-file '%s' failed: %s\n",
50998 __FILE__, __LINE__,
50999 pid_file, strerror(errno));
51006 /* is it a regular file ? */
51009 if (!S_ISREG(st.st_mode)) {
51010 - fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51011 + fprintf(stderr, "%s.%d: pid-file exists and isn't regular file: '%s'\n",
51012 __FILE__, __LINE__,
51020 if (-1 == (pid_fd = open(pid_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) {
51021 - fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51022 + fprintf(stderr, "%s.%d: opening pid-file '%s' failed: %s\n",
51023 __FILE__, __LINE__,
51024 pid_file, strerror(errno));
51033 struct group *grp = NULL;
51034 struct passwd *pwd = NULL;
51037 /* set user and group */
51041 if (NULL == (pwd = getpwnam(username))) {
51042 - fprintf(stderr, "%s.%d: %s, %s\n",
51043 + fprintf(stderr, "%s.%d: %s, %s\n",
51044 __FILE__, __LINE__,
51045 "can't find username", username);
51050 if (pwd->pw_uid == 0) {
51051 - fprintf(stderr, "%s.%d: %s\n",
51052 + fprintf(stderr, "%s.%d: %s\n",
51053 __FILE__, __LINE__,
51054 "I will not set uid to 0\n");
51061 if (NULL == (grp = getgrnam(groupname))) {
51062 - fprintf(stderr, "%s.%d: %s %s\n",
51063 + fprintf(stderr, "%s.%d: %s %s\n",
51064 __FILE__, __LINE__,
51065 - "can't find groupname",
51066 + "can't find groupname",
51070 if (grp->gr_gid == 0) {
51071 - fprintf(stderr, "%s.%d: %s\n",
51072 + fprintf(stderr, "%s.%d: %s\n",
51073 __FILE__, __LINE__,
51074 "I will not set gid to 0\n");
51081 if (-1 == chroot(changeroot)) {
51082 - fprintf(stderr, "%s.%d: %s %s\n",
51083 + fprintf(stderr, "%s.%d: %s %s\n",
51084 __FILE__, __LINE__,
51085 "chroot failed: ", strerror(errno));
51088 if (-1 == chdir("/")) {
51089 - fprintf(stderr, "%s.%d: %s %s\n",
51090 + fprintf(stderr, "%s.%d: %s %s\n",
51091 __FILE__, __LINE__,
51092 "chdir failed: ", strerror(errno));
51098 /* drop root privs */
51100 setgid(grp->gr_gid);
51101 @@ -428,7 +429,7 @@
51103 if (username) setuid(pwd->pw_uid);
51107 return fcgi_spawn_connection(fcgi_app, addr, port, unixsocket, child_count, pid_fd, nofork);
51110 --- ../lighttpd-1.4.11/src/splaytree.c 2005-09-12 21:51:28.000000000 +0300
51111 +++ lighttpd-1.4.12/src/splaytree.c 2006-07-16 00:26:03.000000000 +0300
51112 @@ -56,19 +56,19 @@
51114 #define node_size splaytree_size
51116 -/* Splay using the key i (which may or may not be in the tree.)
51117 - * The starting root is t, and the tree used is defined by rat
51118 +/* Splay using the key i (which may or may not be in the tree.)
51119 + * The starting root is t, and the tree used is defined by rat
51120 * size fields are maintained */
51121 splay_tree * splaytree_splay (splay_tree *t, int i) {
51122 splay_tree N, *l, *r, *y;
51123 int comp, root_size, l_size, r_size;
51126 if (t == NULL) return t;
51127 N.left = N.right = NULL;
51129 root_size = node_size(t);
51130 l_size = r_size = 0;
51134 comp = compare(i, t->key);
51136 @@ -120,7 +120,7 @@
51138 r_size -= 1+node_size(y->right);
51142 l->right = t->left; /* assemble */
51143 r->left = t->right;
51145 --- ../lighttpd-1.4.11/src/splaytree.h 2005-09-12 21:51:13.000000000 +0300
51146 +++ lighttpd-1.4.12/src/splaytree.h 2006-07-16 00:26:03.000000000 +0300
51148 /* This macro returns the size of a node. Unlike "x->size", */
51149 /* it works even if x=NULL. The test could be avoided by using */
51150 /* a special version of NULL which was a real node with size 0. */
51155 --- ../lighttpd-1.4.11/src/stat_cache.c 2005-11-22 15:23:51.000000000 +0200
51156 +++ lighttpd-1.4.12/src/stat_cache.c 2006-07-18 13:03:40.000000000 +0300
51158 #include <stdlib.h>
51159 #include <string.h>
51161 -#include <unistd.h>
51164 #include <assert.h>
51168 #include "sys-mmap.h"
51170 -/* NetBSD 1.3.x needs it */
51171 -#ifndef MAP_FAILED
51172 -# define MAP_FAILED -1
51175 -#ifndef O_LARGEFILE
51176 -# define O_LARGEFILE 0
51179 -#ifndef HAVE_LSTAT
51180 -#define lstat stat
51182 +#include "sys-files.h"
51183 +#include "sys-strings.h"
51186 /* enables debug code for testing if all nodes in the stat-cache as accessable */
51189 * if we get a change-event from FAM, we increment the version in the FAM->dir mapping
51191 - * if the stat()-cache is queried we check if the version id for the directory is the
51192 - * same and return immediatly.
51193 + * if the stat()-cache is queried we check if the version id for the directory is the
51194 + * same and return immediatly.
51198 @@ -62,17 +50,17 @@
51199 * - for each FAMRequest we have to find the version in the directory cache (index as userdata)
51201 * stat <<-> directory <-> FAMRequest
51203 - * if file is deleted, directory is dirty, file is rechecked ...
51205 + * if file is deleted, directory is dirty, file is rechecked ...
51206 * if directory is deleted, directory mapping is removed
51220 @@ -83,16 +71,16 @@
51222 * - the hash-key is used as sorting criteria for a tree
51223 * - a splay-tree is used as we can use the caching effect of it
51227 /* we want to cleanup the stat-cache every few seconds, let's say 10
51229 * - remove entries which are outdated since 30s
51230 * - remove entries which are fresh but havn't been used since 60s
51231 * - if we don't have a stat-cache entry for a directory, release it from the monitor
51235 -#ifdef DEBUG_STAT_CACHE
51236 +#ifdef DEBUG_STAT_CACHE
51240 @@ -105,15 +93,16 @@
51242 stat_cache *stat_cache_init(void) {
51243 stat_cache *fc = NULL;
51246 fc = calloc(1, sizeof(*fc));
51249 fc->dir_name = buffer_init();
51251 fc->fam = calloc(1, sizeof(*fc->fam));
51252 + fc->sock = iosocket_init();
51255 -#ifdef DEBUG_STAT_CACHE
51256 +#ifdef DEBUG_STAT_CACHE
51260 @@ -122,24 +111,24 @@
51262 static stat_cache_entry * stat_cache_entry_init(void) {
51263 stat_cache_entry *sce = NULL;
51266 sce = calloc(1, sizeof(*sce));
51269 sce->name = buffer_init();
51270 sce->etag = buffer_init();
51271 sce->content_type = buffer_init();
51277 static void stat_cache_entry_free(void *data) {
51278 stat_cache_entry *sce = data;
51282 buffer_free(sce->etag);
51283 buffer_free(sce->name);
51284 buffer_free(sce->content_type);
51290 @@ -148,22 +137,22 @@
51291 fam_dir_entry *fam_dir = NULL;
51293 fam_dir = calloc(1, sizeof(*fam_dir));
51296 fam_dir->name = buffer_init();
51302 static void fam_dir_entry_free(void *data) {
51303 fam_dir_entry *fam_dir = data;
51306 if (!fam_dir) return;
51309 FAMCancelMonitor(fam_dir->fc, fam_dir->req);
51312 buffer_free(fam_dir->name);
51313 free(fam_dir->req);
51319 @@ -174,7 +163,7 @@
51320 splay_tree *node = sc->files;
51322 osize = sc->files->size;
51325 stat_cache_entry_free(node->data);
51326 sc->files = splaytree_delete(sc->files, node->key);
51328 @@ -187,12 +176,12 @@
51331 splay_tree *node = sc->dirs;
51334 osize = sc->dirs->size;
51336 fam_dir_entry_free(node->data);
51337 sc->dirs = splaytree_delete(sc->dirs, node->key);
51341 assert(NULL == sc->dirs);
51343 @@ -202,6 +191,7 @@
51347 + iosocket_free(sc->sock);
51351 @@ -212,7 +202,7 @@
51352 static int stat_cache_attr_get(buffer *buf, char *name) {
51358 buffer_prepare_copy(buf, attrlen);
51360 @@ -251,15 +241,15 @@
51363 events = FAMPending(sc->fam);
51366 for (i = 0; i < events; i++) {
51368 fam_dir_entry *fam_dir;
51373 FAMNextEvent(sc->fam, &fe);
51379 @@ -280,7 +270,7 @@
51381 sc->dirs = splaytree_splay(sc->dirs, ndx);
51385 if (node && (node->key == ndx)) {
51386 int osize = splaytree_size(sc->dirs);
51388 @@ -298,17 +288,15 @@
51390 if (revent & FDEVENT_HUP) {
51391 /* fam closed the connection */
51392 - srv->stat_cache->fam_fcce_ndx = -1;
51394 - fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam));
51395 - fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam));
51396 + fdevent_event_del(srv->ev, sc->sock);
51397 + fdevent_unregister(srv->ev, sc->sock);
51406 return HANDLER_GO_ON;
51409 @@ -332,7 +320,7 @@
51415 * - HANDLER_FINISHED on cache-miss (don't forget to reopen the file)
51416 * - HANDLER_ERROR on stat() failed -> see errno for problem
51418 @@ -348,16 +336,16 @@
51422 -#ifdef DEBUG_STAT_CACHE
51423 +#ifdef DEBUG_STAT_CACHE
51428 splay_tree *file_node = NULL;
51435 * check if the directory for this file has changed
51438 @@ -366,23 +354,23 @@
51439 file_ndx = hashme(name);
51440 sc->files = splaytree_splay(sc->files, file_ndx);
51442 -#ifdef DEBUG_STAT_CACHE
51443 +#ifdef DEBUG_STAT_CACHE
51444 for (i = 0; i < ctrl.used; i++) {
51445 if (ctrl.ptr[i] == file_ndx) break;
51449 if (sc->files && (sc->files->key == file_ndx)) {
51450 -#ifdef DEBUG_STAT_CACHE
51451 +#ifdef DEBUG_STAT_CACHE
51452 /* it was in the cache */
51453 assert(i < ctrl.used);
51456 - /* we have seen this file already and
51458 + /* we have seen this file already and
51459 * don't stat() it again in the same second */
51461 file_node = sc->files;
51464 sce = file_node->data;
51466 /* check if the name is the same, we might have a collision */
51467 @@ -390,7 +378,7 @@
51468 if (buffer_is_equal(name, sce->name)) {
51469 if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) {
51470 if (sce->stat_ts == srv->cur_ts) {
51473 return HANDLER_GO_ON;
51476 @@ -400,15 +388,15 @@
51477 * file_node is used by the FAM check below to see if we know this file
51478 * and if we can save a stat().
51480 - * BUT, the sce is not reset here as the entry into the cache is ok, we
51481 + * BUT, the sce is not reset here as the entry into the cache is ok, we
51482 * it is just not pointing to our requested file.
51490 -#ifdef DEBUG_STAT_CACHE
51491 +#ifdef DEBUG_STAT_CACHE
51492 if (i != ctrl.used) {
51493 fprintf(stderr, "%s.%d: %08x was already inserted but not found in cache, %s\n", __FILE__, __LINE__, file_ndx, name->ptr);
51495 @@ -424,23 +412,23 @@
51498 dir_ndx = hashme(sc->dir_name);
51501 sc->dirs = splaytree_splay(sc->dirs, dir_ndx);
51504 if (sc->dirs && (sc->dirs->key == dir_ndx)) {
51505 dir_node = sc->dirs;
51509 if (dir_node && file_node) {
51510 /* we found a file */
51513 sce = file_node->data;
51514 fam_dir = dir_node->data;
51517 if (fam_dir->version == sce->dir_version) {
51518 /* the stat()-cache entry is still ok */
51523 return HANDLER_GO_ON;
51526 @@ -448,7 +436,7 @@
51532 * - open() + fstat() on a named-pipe results in a (intended) hang.
51533 * - stat() if regualar file + open() to see if we can read from it is better
51535 @@ -469,16 +457,16 @@
51542 osize = sc->files->size;
51545 sce = stat_cache_entry_init();
51546 buffer_copy_string_buffer(sce->name, name);
51548 - sc->files = splaytree_insert(sc->files, file_ndx, sce);
51549 -#ifdef DEBUG_STAT_CACHE
51551 + sc->files = splaytree_insert(sc->files, file_ndx, sce);
51552 +#ifdef DEBUG_STAT_CACHE
51553 if (ctrl.size == 0) {
51556 @@ -499,29 +487,29 @@
51558 sce->stat_ts = srv->cur_ts;
51560 - /* catch the obvious symlinks
51561 + /* catch the obvious symlinks
51563 * this is not a secure check as we still have a race-condition between
51564 - * the stat() and the open. We can only solve this by
51565 + * the stat() and the open. We can only solve this by
51566 * 1. open() the file
51567 * 2. fstat() the fd
51569 * and keeping the file open for the rest of the time. But this can
51570 * only be done at network level.
51574 if (S_ISLNK(st.st_mode) && !con->conf.follow_symlink) {
51575 return HANDLER_ERROR;
51578 - if (S_ISREG(st.st_mode)) {
51579 + if (S_ISREG(st.st_mode)) {
51580 /* determine mimetype */
51581 buffer_reset(sce->content_type);
51584 for (k = 0; k < con->conf.mimetypes->used; k++) {
51585 data_string *ds = (data_string *)con->conf.mimetypes->data[k];
51586 buffer *type = ds->key;
51589 if (type->used == 0) continue;
51591 /* check if the right side is the same */
51592 @@ -538,8 +526,10 @@
51593 stat_cache_attr_get(sce->content_type, name->ptr);
51596 + } else if (S_ISDIR(st.st_mode)) {
51597 + etag_create(sce->etag, &(sce->st));
51603 (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) {
51604 @@ -549,19 +539,19 @@
51605 fam_dir->fc = sc->fam;
51607 buffer_copy_string_buffer(fam_dir->name, sc->dir_name);
51610 fam_dir->version = 1;
51613 fam_dir->req = calloc(1, sizeof(FAMRequest));
51615 - if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
51617 + if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr,
51618 fam_dir->req, fam_dir)) {
51620 - log_error_write(srv, __FILE__, __LINE__, "sbs",
51621 - "monitoring dir failed:",
51624 + log_error_write(srv, __FILE__, __LINE__, "sbs",
51625 + "monitoring dir failed:",
51627 FamErrlist[FAMErrno]);
51630 fam_dir_entry_free(fam_dir);
51633 @@ -570,7 +560,7 @@
51634 osize = sc->dirs->size;
51637 - sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
51638 + sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir);
51640 assert(sc->dirs->data == fam_dir);
51641 assert(osize == (sc->dirs->size - 1));
51642 @@ -578,9 +568,9 @@
51644 fam_dir = dir_node->data;
51648 /* bind the fam_fc to the stat() cache entry */
51652 sce->dir_version = fam_dir->version;
51653 sce->dir_ndx = dir_ndx;
51654 @@ -594,11 +584,11 @@
51658 - * remove stat() from cache which havn't been stat()ed for
51659 + * remove stat() from cache which havn't been stat()ed for
51660 * more than 10 seconds
51663 - * walk though the stat-cache, collect the ids which are too old
51665 + * walk though the stat-cache, collect the ids which are too old
51666 * and remove them in a second loop
51669 @@ -639,9 +629,9 @@
51670 sc->files = splaytree_splay(sc->files, ndx);
51675 if (node && (node->key == ndx)) {
51676 -#ifdef DEBUG_STAT_CACHE
51677 +#ifdef DEBUG_STAT_CACHE
51679 int osize = splaytree_size(sc->files);
51680 stat_cache_entry *sce = node->data;
51681 @@ -649,7 +639,7 @@
51682 stat_cache_entry_free(node->data);
51683 sc->files = splaytree_delete(sc->files, ndx);
51685 -#ifdef DEBUG_STAT_CACHE
51686 +#ifdef DEBUG_STAT_CACHE
51687 for (j = 0; j < ctrl.used; j++) {
51688 if (ctrl.ptr[j] == ndx) {
51689 ctrl.ptr[j] = ctrl.ptr[--ctrl.used];
51690 --- ../lighttpd-1.4.11/src/stream.c 2005-09-23 21:50:15.000000000 +0300
51691 +++ lighttpd-1.4.12/src/stream.c 2006-07-16 00:26:04.000000000 +0300
51693 #include <sys/types.h>
51694 #include <sys/stat.h>
51696 -#include <unistd.h>
51699 #include "stream.h"
51703 #include "sys-mmap.h"
51704 +#include "sys-files.h"
51707 # define O_BINARY 0
51708 @@ -19,39 +19,39 @@
51712 -#elif defined __WIN32
51713 +#elif defined _WIN32
51721 if (-1 == stat(fn->ptr, &st)) {
51726 f->size = st.st_size;
51729 if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) {
51734 f->start = mmap(0, f->size, PROT_READ, MAP_SHARED, fd, 0);
51740 if (MAP_FAILED == f->start) {
51744 -#elif defined __WIN32
51745 - fh = CreateFile(fn->ptr,
51750 - FILE_ATTRIBUTE_READONLY,
51751 +#elif defined _WIN32
51752 + fh = CreateFile(fn->ptr,
51757 + FILE_ATTRIBUTE_READONLY,
51760 if (!fh) return -1;
51765 - FORMAT_MESSAGE_ALLOCATE_BUFFER |
51766 + FORMAT_MESSAGE_ALLOCATE_BUFFER |
51767 FORMAT_MESSAGE_FROM_SYSTEM,
51776 p = MapViewOfFile(mh,
51783 -# error no mmap found
51784 +# error no mmap found
51791 --- ../lighttpd-1.4.11/src/sys-files.h 1970-01-01 03:00:00.000000000 +0300
51792 +++ lighttpd-1.4.12/src/sys-files.h 2006-07-16 00:26:04.000000000 +0300
51794 +#ifndef _SYS_FILES_H_
51795 +#define _SYS_FILES_H_
51797 +#define DIR_SEPERATOR_UNIX '/'
51798 +#define DIR_SEPERATOR_WIN '\\'
51801 +#include <windows.h>
51802 +#include <io.h> /* open */
51803 +#include <direct.h> /* chdir */
51805 +#include "buffer.h"
51807 +#define DIR_SEPERATOR DIR_SEPERATOR_WIN
51809 +#define __S_ISTYPE(mode, mask) (((mode) & _S_IFMT) == (mask))
51811 +#define S_ISDIR(mode) __S_ISTYPE((mode), _S_IFDIR)
51812 +#define S_ISCHR(mode) __S_ISTYPE((mode), _S_IFCHR)
51813 +#define S_ISBLK(mode) __S_ISTYPE((mode), _S_IFBLK)
51814 +#define S_ISREG(mode) __S_ISTYPE((mode), _S_IFREG)
51815 +/* we don't support symlinks */
51816 +#define S_ISLNK(mode) 0
51818 +#define lstat stat
51819 +#define mkstemp mktemp
51820 +#define mkdir(x, y) mkdir(x)
51823 + const char *d_name;
51828 + WIN32_FIND_DATA finddata;
51829 + struct dirent dent;
51832 +DIR *opendir(const char *dn);
51833 +struct dirent *readdir(DIR *d);
51834 +void closedir(DIR *d);
51836 +buffer *filename_unix2local(buffer *b);
51837 +buffer *pathname_unix2local(buffer *b);
51840 +#include <unistd.h>
51841 +#include <dirent.h>
51843 +#define DIR_SEPERATOR DIR_SEPERATOR_UNIX
51845 +#define filename_unix2local(x) (x)
51846 +#define pathname_unix2local(x) (x)
51849 +#define PATHNAME_APPEND_SLASH(x) \
51850 + if (x->used > 1 && x->ptr[x->used - 2] != DIR_SEPERATOR) { \
51851 + char sl[2] = { DIR_SEPERATOR, 0 }; \
51852 + BUFFER_APPEND_STRING_CONST(x, sl); \
51855 +#ifndef O_LARGEFILE
51856 +# define O_LARGEFILE 0
51861 --- ../lighttpd-1.4.11/src/sys-mmap.h 2005-08-11 01:26:34.000000000 +0300
51862 +++ lighttpd-1.4.12/src/sys-mmap.h 2006-07-16 00:26:04.000000000 +0300
51864 #ifndef WIN32_MMAP_H
51865 #define WIN32_MMAP_H
51870 #define MAP_FAILED -1
51871 #define PROT_SHARED 0
51872 --- ../lighttpd-1.4.11/src/sys-process.h 1970-01-01 03:00:00.000000000 +0300
51873 +++ lighttpd-1.4.12/src/sys-process.h 2006-07-16 00:26:04.000000000 +0300
51875 +#ifndef _SYS_PROCESS_H_
51876 +#define _SYS_PROCESS_H_
51879 +#include <process.h>
51881 +/* win32 has no fork() */
51882 +#define kill(x, y)
51883 +#define getpid() 0
51886 +#include <sys/wait.h>
51887 +#include <unistd.h>
51892 --- ../lighttpd-1.4.11/src/sys-socket.h 2005-08-11 01:26:39.000000000 +0300
51893 +++ lighttpd-1.4.12/src/sys-socket.h 2006-07-18 13:03:40.000000000 +0300
51895 #ifndef WIN32_SOCKET_H
51896 #define WIN32_SOCKET_H
51901 #include <winsock2.h>
51903 #define ECONNRESET WSAECONNRESET
51904 #define EINPROGRESS WSAEINPROGRESS
51905 #define EALREADY WSAEALREADY
51906 +#define ENOTCONN WSAENOTCONN
51907 +#define EWOULDBLOCK WSAEWOULDBLOCK
51908 #define ioctl ioctlsocket
51909 #define hstrerror(x) ""
51910 +#define STDIN_FILENO 0
51911 +#define STDOUT_FILENO 1
51912 +#define STDERR_FILENO 2
51913 +#define ssize_t int
51915 +int inet_aton(const char *cp, struct in_addr *inp);
51916 +#define HAVE_INET_ADDR
51917 +#undef HAVE_INET_ATON
51920 #include <sys/socket.h>
51921 #include <sys/ioctl.h>
51923 #include <sys/un.h>
51924 #include <arpa/inet.h>
51927 +#define SUN_LEN(su) \
51928 + (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
51931 +#define closesocket(x) close(x)
51934 +#endif /* !_WIN32 */
51938 + struct sockaddr_in6 ipv6;
51940 + struct sockaddr_in ipv4;
51941 +#ifdef HAVE_SYS_UN_H
51942 + struct sockaddr_un un;
51944 + struct sockaddr plain;
51948 --- ../lighttpd-1.4.11/src/sys-strings.h 1970-01-01 03:00:00.000000000 +0300
51949 +++ lighttpd-1.4.12/src/sys-strings.h 2006-07-16 00:26:03.000000000 +0300
51951 +#ifndef _SYS_STRINGS_H_
51952 +#define _SYS_STRINGS_H_
51955 +#define strcasecmp stricmp
51956 +#define strncasecmp strnicmp
51957 +#define strtoll(p, e, b) _strtoi64(p, e, b)
51962 --- ../lighttpd-1.4.11/tests/LightyTest.pm 2006-01-14 20:32:31.000000000 +0200
51963 +++ lighttpd-1.4.12/tests/LightyTest.pm 2006-07-18 13:03:40.000000000 +0300
51964 @@ -87,14 +87,16 @@
51965 # pre-process configfile if necessary
51968 - unlink($self->{TESTDIR}."/tmp/cfg.file");
51969 - system("cat ".$self->{SRCDIR}."/".$self->{CONFIGFILE}.' | perl -pe "s#\@SRCDIR\@#'.$self->{BASEDIR}.'/tests/#" > '.$self->{TESTDIR}.'/tmp/cfg.file');
51970 + $ENV{'SRCDIR'} = $self->{BASEDIR}.'/tests';
51971 + $ENV{'PORT'} = $self->{PORT};
51973 unlink($self->{LIGHTTPD_PIDFILE});
51975 - system($self->{LIGHTTPD_PATH}." -f ".$self->{TESTDIR}."/tmp/cfg.file -m ".$self->{MODULES_PATH});
51976 + if (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'strace') {
51977 + system("strace -tt -s 512 -o strace ".$self->{LIGHTTPD_PATH}." -D -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH}." &");
51978 + } elsif (defined $ENV{"TRACEME"} && $ENV{"TRACEME"} eq 'valgrind') {
51979 + 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}." &");
51981 - 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}." &");
51982 + system($self->{LIGHTTPD_PATH}." -f ".$self->{SRCDIR}."/".$self->{CONFIGFILE}." -m ".$self->{MODULES_PATH});
51985 select(undef, undef, undef, 0.1);
51986 @@ -184,7 +186,7 @@
51987 (my $h = $1) =~ tr/[A-Z]/[a-z]/;
51989 if (defined $resp_hdr{$h}) {
51990 - diag(sprintf("header %s is duplicated: %s and %s\n",
51991 + diag(sprintf("header '%s' is duplicated: '%s' and '%s'\n",
51992 $h, $resp_hdr{$h}, $2));
51994 $resp_hdr{$h} = $2;
51995 @@ -196,6 +198,9 @@
51999 + $t->{etag} = $resp_hdr{'etag'};
52000 + $t->{date} = $resp_hdr{'date'};
52003 if (defined $resp_hdr{"content-length"}) {
52004 $resp_body = substr($lines, 0, $resp_hdr{"content-length"});
52005 --- ../lighttpd-1.4.11/tests/Makefile.am 2005-09-16 15:48:40.000000000 +0300
52006 +++ lighttpd-1.4.12/tests/Makefile.am 2006-07-16 00:26:05.000000000 +0300
52007 @@ -39,10 +39,18 @@
52022 + proxy-backend-1.conf \
52023 + proxy-backend-2.conf
52026 TESTS_ENVIRONMENT=$(srcdir)/wrapper.sh $(srcdir) $(top_builddir)
52027 --- ../lighttpd-1.4.11/tests/bug-06.conf 2005-08-27 17:44:19.000000000 +0300
52028 +++ lighttpd-1.4.12/tests/bug-06.conf 2006-07-16 00:26:04.000000000 +0300
52030 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52031 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52032 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52033 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52035 ## bind to port (default: 80)
52039 ## bind to localhost (default: all interfaces)
52040 server.bind = "localhost"
52041 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52042 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52043 server.name = "www.example.org"
52044 server.tag = "Apache 1.3.29"
52047 ######################## MODULE CONFIG ############################
52050 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52051 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52053 mimetype.assign = ( ".png" => "image/png",
52054 ".jpg" => "image/jpeg",
52056 ".c" => "text/plain",
52057 ".conf" => "text/plain" )
52059 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52060 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52061 compress.filetype = ("text/plain", "text/html")
52063 setenv.add-environment = ( "TRAC_ENV" => "foo")
52065 "host" => "127.0.0.1",
52067 # "mode" => "authorizer",
52068 -# "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52069 +# "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52073 @@ -106,7 +106,7 @@
52074 ssl.pemfile = "server.pem"
52076 auth.backend = "plain"
52077 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52078 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52079 auth.backend.plain.groupfile = "lighttpd.group"
52081 auth.backend.ldap.hostname = "localhost"
52082 @@ -149,15 +149,15 @@
52083 status.config-url = "/server-config"
52085 simple-vhost.document-root = "pages"
52086 -simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
52087 +simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
52088 simple-vhost.default-host = "www.example.org"
52090 $HTTP["host"] == "vvv.example.org" {
52091 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52092 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52095 $HTTP["host"] == "zzz.example.org" {
52096 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52097 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52098 server.name = "zzz.example.org"
52101 --- ../lighttpd-1.4.11/tests/bug-12.conf 2005-08-27 17:44:19.000000000 +0300
52102 +++ lighttpd-1.4.12/tests/bug-12.conf 2006-07-16 00:26:04.000000000 +0300
52104 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52105 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52106 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52107 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52109 ## bind to port (default: 80)
52113 ## bind to localhost (default: all interfaces)
52114 server.bind = "localhost"
52115 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52116 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52117 server.name = "www.example.org"
52118 server.tag = "Apache 1.3.29"
52121 ######################## MODULE CONFIG ############################
52124 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52125 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52127 mimetype.assign = ( ".png" => "image/png",
52128 ".jpg" => "image/jpeg",
52130 ".c" => "text/plain",
52131 ".conf" => "text/plain" )
52133 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52134 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52135 compress.filetype = ("text/plain", "text/html")
52137 setenv.add-environment = ( "TRAC_ENV" => "foo")
52139 "host" => "127.0.0.1",
52141 # "mode" => "authorizer",
52142 -# "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52143 +# "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52147 @@ -108,7 +108,7 @@
52148 ssl.pemfile = "server.pem"
52150 auth.backend = "plain"
52151 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52152 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52153 auth.backend.plain.groupfile = "lighttpd.group"
52155 auth.backend.ldap.hostname = "localhost"
52156 @@ -151,15 +151,15 @@
52157 status.config-url = "/server-config"
52159 simple-vhost.document-root = "pages"
52160 -simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
52161 +simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
52162 simple-vhost.default-host = "www.example.org"
52164 $HTTP["host"] == "vvv.example.org" {
52165 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52166 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52169 $HTTP["host"] == "zzz.example.org" {
52170 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52171 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52172 server.name = "zzz.example.org"
52175 --- ../lighttpd-1.4.11/tests/cachable.t 1970-01-01 03:00:00.000000000 +0300
52176 +++ lighttpd-1.4.12/tests/cachable.t 2006-07-18 13:03:40.000000000 +0300
52178 +#!/usr/bin/env perl
52180 + # add current source dir to the include-path
52181 + # we need this for make distcheck
52182 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
52183 + unshift @INC, $srcdir;
52188 +use Test::More tests => 12;
52191 +my $tf = LightyTest->new();
52194 +$tf->{CONFIGFILE} = 'lighttpd.conf';
52196 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
52198 +## check if If-Modified-Since, If-None-Match works
52200 +$t->{REQUEST} = ( <<EOF
52202 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT
52205 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52206 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since');
52208 +$t->{REQUEST} = ( <<EOF
52210 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52213 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Last-Modified' => ''} ];
52214 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-Modified-Since, comment');
52216 +my $now = $t->{date};
52218 +$t->{REQUEST} = ( <<EOF
52220 +If-Modified-Since: $now
52223 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52224 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since');
52226 +$t->{REQUEST} = ( <<EOF
52228 +If-Modified-Since: $now; foo
52231 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52232 +ok($tf->handle_http($t) == 0, 'Conditional GET - new If-Modified-Since, comment');
52234 +$t->{REQUEST} = ( <<EOF
52236 +If-None-Match: foo
52239 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+ETag' => ''} ];
52240 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52242 +my $etag = $t->{etag};
52244 +$t->{REQUEST} = ( <<EOF
52246 +If-None-Match: $etag
52249 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52250 +ok($tf->handle_http($t) == 0, 'Conditional GET - old If-None-Match');
52252 +$t->{REQUEST} = ( <<EOF
52254 +If-None-Match: $etag
52255 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52258 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52259 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + old Last-Modified');
52261 +$t->{REQUEST} = ( <<EOF
52263 +If-None-Match: $etag
52264 +If-Modified-Since: $now; foo
52267 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 304 } ];
52268 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag, Last-Modified + comment');
52270 +$t->{REQUEST} = ( <<EOF
52272 +If-None-Match: Foo
52273 +If-Modified-Since: Sun, 01 Jan 1970 00:00:01 GMT; foo
52276 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52277 +ok($tf->handle_http($t) == 0, 'Conditional GET - old ETAG + old Last-Modified');
52279 +$t->{REQUEST} = ( <<EOF
52281 +If-None-Match: $etag
52282 +If-Modified-Since: $now foo
52285 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 412 } ];
52286 +ok($tf->handle_http($t) == 0, 'Conditional GET - ETag + Last-Modified + overlong timestamp');
52288 +ok($tf->stop_proc == 0, "Stopping lighttpd");
52290 --- ../lighttpd-1.4.11/tests/condition.conf 2005-08-27 17:44:19.000000000 +0300
52291 +++ lighttpd-1.4.12/tests/condition.conf 2006-07-16 00:26:05.000000000 +0300
52293 debug.log-request-handling = "enable"
52294 debug.log-condition-handling = "enable"
52296 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52297 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52298 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52299 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52301 ## bind to port (default: 80)
52304 ## bind to localhost (default: all interfaces)
52305 server.bind = "localhost"
52306 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52307 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52308 server.name = "www.example.org"
52309 server.tag = "Apache 1.3.29"
52311 @@ -22,25 +22,25 @@
52312 ######################## MODULE CONFIG ############################
52315 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52316 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52318 mimetype.assign = ( ".html" => "text/html" )
52320 url.redirect = ("^" => "/default")
52322 $HTTP["host"] == "www.example.org" {
52323 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52324 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52325 server.name = "www.example.org"
52326 url.redirect = ("^" => "/match_1")
52328 else $HTTP["host"] == "test1.example.org" {
52329 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52330 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52331 server.name = "test1.example.org"
52332 url.redirect = ("^" => "/match_2")
52335 else $HTTP["host"] == "test2.example.org" {
52336 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52337 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52338 server.name = "test2.example.org"
52339 url.redirect = ("^" => "/match_3")
52344 else $HTTP["host"] == "test3.example.org" {
52345 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52346 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52347 server.name = "test3.example.org"
52348 url.redirect = ("^" => "/match_4")
52350 --- ../lighttpd-1.4.11/tests/core-keepalive.t 2005-11-17 15:54:19.000000000 +0200
52351 +++ lighttpd-1.4.12/tests/core-keepalive.t 2006-07-16 00:26:05.000000000 +0300
52354 GET /12345.txt HTTP/1.0
52355 Host: 123.example.org
52356 -Connection: keep-alive
52360 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } , { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
52361 --- ../lighttpd-1.4.11/tests/default.conf 1970-01-01 03:00:00.000000000 +0300
52362 +++ lighttpd-1.4.12/tests/default.conf 2006-07-16 00:26:05.000000000 +0300
52364 +server.name = "www.example.org"
52366 +## bind to port (default: 80)
52367 +server.port = env.PORT
52370 +server.dir-listing = "enable"
52372 +#server.event-handler = "linux-sysepoll"
52373 +#server.event-handler = "linux-rtsig"
52375 +server.modules = (
52382 + "mod_simple_vhost",
52384 + "mod_secdownload",
52391 + "mod_accesslog" )
52393 +server.indexfiles = ( "index.php", "index.html",
52394 + "index.htm", "default.htm" )
52396 +ssi.extension = ( ".shtml" )
52398 +######################## MODULE CONFIG ############################
52401 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52402 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52404 +mimetype.assign = ( ".png" => "image/png",
52405 + ".jpg" => "image/jpeg",
52406 + ".jpeg" => "image/jpeg",
52407 + ".gif" => "image/gif",
52408 + ".html" => "text/html",
52409 + ".htm" => "text/html",
52410 + ".pdf" => "application/pdf",
52411 + ".swf" => "application/x-shockwave-flash",
52412 + ".spl" => "application/futuresplash",
52413 + ".txt" => "text/plain",
52414 + ".tar.gz" => "application/x-tgz",
52415 + ".tgz" => "application/x-tgz",
52416 + ".gz" => "application/x-gzip",
52417 + ".c" => "text/plain",
52418 + ".conf" => "text/plain" )
52420 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52421 +compress.filetype = ("text/plain", "text/html")
52423 +setenv.add-environment = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
52425 +cgi.assign = ( ".pl" => "/usr/bin/perl",
52426 + ".cgi" => "/usr/bin/perl",
52427 + ".py" => "/usr/bin/python" )
52429 +userdir.include-user = ( "jan" )
52430 +userdir.path = "/"
52432 +ssl.engine = "disable"
52433 +ssl.pemfile = "server.pem"
52435 +auth.backend = "plain"
52436 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52437 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
52438 +auth.backend.plain.groupfile = "lighttpd.group"
52440 +auth.backend.ldap.hostname = "localhost"
52441 +auth.backend.ldap.base-dn = "dc=my-domain,dc=com"
52442 +auth.backend.ldap.filter = "(uid=$)"
52444 +auth.require = ( "/server-status" =>
52446 + "method" => "digest",
52447 + "realm" => "download archiv",
52448 + "require" => "valid-user"
52452 + "method" => "basic",
52453 + "realm" => "download archiv",
52454 + "require" => "user=jan"
52456 + "/server-config" =>
52458 + "method" => "basic",
52459 + "realm" => "download archiv",
52460 + "require" => "valid-user"
52464 +url.access-deny = ( "~", ".inc")
52466 +url.redirect = ( "^/redirect/$" => "http://localhost:2048/" )
52468 +url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
52469 + "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
52471 +#### status module
52472 +status.status-url = "/server-status"
52473 +status.config-url = "/server-config"
52475 --- ../lighttpd-1.4.11/tests/docroot/www/dummydir/.svn/entries 2006-03-09 19:21:49.000000000 +0200
52476 +++ lighttpd-1.4.12/tests/docroot/www/dummydir/.svn/entries 2006-07-18 13:03:40.000000000 +0300
52480 uuid="152afb58-edef-0310-8abb-c4023f1b3aa9"
52481 - revision="1040"/>
52482 + repos="svn://svn.lighttpd.net/lighttpd"
52483 + revision="1199"/>
52485 --- ../lighttpd-1.4.11/tests/fastcgi-10.conf 2005-08-31 23:36:34.000000000 +0300
52486 +++ lighttpd-1.4.12/tests/fastcgi-10.conf 2006-07-16 00:26:04.000000000 +0300
52488 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52489 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52490 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52491 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52493 ## bind to port (default: 80)
52496 ## bind to localhost (default: all interfaces)
52497 server.bind = "localhost"
52498 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52499 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52500 server.name = "www.example.org"
52501 server.tag = "Apache 1.3.29"
52504 ######################## MODULE CONFIG ############################
52507 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52508 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52510 mimetype.assign = ( ".png" => "image/png",
52511 ".jpg" => "image/jpeg",
52513 ".c" => "text/plain",
52514 ".conf" => "text/plain" )
52516 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52517 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52518 compress.filetype = ("text/plain", "text/html")
52522 ssl.pemfile = "server.pem"
52524 auth.backend = "plain"
52525 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52526 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52527 auth.backend.plain.groupfile = "lighttpd.group"
52529 auth.backend.ldap.hostname = "localhost"
52530 @@ -128,11 +128,11 @@
52531 status.config-url = "/server-config"
52533 $HTTP["host"] == "vvv.example.org" {
52534 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52535 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52538 $HTTP["host"] == "zzz.example.org" {
52539 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52540 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52541 server.name = "zzz.example.org"
52544 --- ../lighttpd-1.4.11/tests/fastcgi-13.conf 2006-01-03 12:38:17.000000000 +0200
52545 +++ lighttpd-1.4.12/tests/fastcgi-13.conf 2006-07-18 13:03:40.000000000 +0300
52547 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52548 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52549 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52550 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52552 debug.log-request-header = "enable"
52553 debug.log-response-header = "enable"
52556 ## bind to localhost (default: all interfaces)
52557 server.bind = "localhost"
52558 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52559 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52560 server.name = "www.example.org"
52561 server.tag = "Apache 1.3.29"
52564 ######################## MODULE CONFIG ############################
52567 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52568 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52570 mimetype.assign = ( ".png" => "image/png",
52571 ".jpg" => "image/jpeg",
52573 ".c" => "text/plain",
52574 ".conf" => "text/plain" )
52576 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52577 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52578 compress.filetype = ("text/plain", "text/html")
52583 "host" => "127.0.0.1",
52585 - "bin-path" => "/home/jan/Documents/php-5.1.0/sapi/cgi/php -c /usr/local/lib/php.ini",
52586 + "bin-path" => "/home/jan/Documents/php-5.1.4/sapi/cgi/php -c /usr/local/lib/php.ini",
52587 "bin-copy-environment" => ( "PATH", "SHELL", "USER" ),
52590 @@ -102,7 +102,7 @@
52591 ssl.pemfile = "server.pem"
52593 auth.backend = "plain"
52594 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52595 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52596 auth.backend.plain.groupfile = "lighttpd.group"
52598 auth.backend.ldap.hostname = "localhost"
52599 @@ -145,11 +145,11 @@
52600 status.config-url = "/server-config"
52602 $HTTP["host"] == "vvv.example.org" {
52603 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52604 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52607 $HTTP["host"] == "zzz.example.org" {
52608 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52609 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52610 server.name = "zzz.example.org"
52613 --- ../lighttpd-1.4.11/tests/fastcgi-auth.conf 2005-08-27 17:44:19.000000000 +0300
52614 +++ lighttpd-1.4.12/tests/fastcgi-auth.conf 2006-07-16 00:26:05.000000000 +0300
52616 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52617 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52618 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52619 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52621 debug.log-request-header = "enable"
52622 debug.log-response-header = "enable"
52625 ## bind to localhost (default: all interfaces)
52626 server.bind = "localhost"
52627 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52628 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52629 server.name = "www.example.org"
52630 server.tag = "Apache 1.3.29"
52633 ######################## MODULE CONFIG ############################
52636 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52637 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
52639 mimetype.assign = ( ".png" => "image/png",
52640 ".jpg" => "image/jpeg",
52642 ".c" => "text/plain",
52643 ".conf" => "text/plain" )
52645 -compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52646 +compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52647 compress.filetype = ("text/plain", "text/html")
52652 "host" => "127.0.0.1",
52654 - "bin-path" => "@SRCDIR@/fcgi-auth",
52655 + "bin-path" => env.SRCDIR + "/fcgi-auth",
52656 "mode" => "authorizer",
52657 - "docroot" => "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/",
52658 + "docroot" => env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/",
52662 @@ -106,7 +106,7 @@
52663 ssl.pemfile = "server.pem"
52665 auth.backend = "plain"
52666 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52667 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52668 auth.backend.plain.groupfile = "lighttpd.group"
52670 auth.backend.ldap.hostname = "localhost"
52671 @@ -149,11 +149,11 @@
52672 status.config-url = "/server-config"
52674 $HTTP["host"] == "vvv.example.org" {
52675 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52676 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52679 $HTTP["host"] == "zzz.example.org" {
52680 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52681 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52682 server.name = "zzz.example.org"
52685 --- ../lighttpd-1.4.11/tests/fastcgi-responder.conf 2005-08-27 17:44:19.000000000 +0300
52686 +++ lighttpd-1.4.12/tests/fastcgi-responder.conf 2006-07-16 00:26:05.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 #debug.log-request-header = "enable"
52694 #debug.log-response-header = "enable"
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")
52722 @@ -90,10 +90,11 @@
52724 "host" => "127.0.0.1",
52726 - "bin-path" => "@SRCDIR@/fcgi-responder",
52727 + "bin-path" => env.SRCDIR + "/fcgi-responder",
52728 "check-local" => "disable",
52731 + "min-procs" => 1,
52732 + "allow-x-send-file" => "enable",
52736 @@ -109,7 +110,7 @@
52737 ssl.pemfile = "server.pem"
52739 auth.backend = "plain"
52740 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52741 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
52742 auth.backend.plain.groupfile = "lighttpd.group"
52744 auth.backend.ldap.hostname = "localhost"
52745 @@ -152,11 +153,11 @@
52746 status.config-url = "/server-config"
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/fcgi-responder.c 2005-08-11 01:26:55.000000000 +0300
52760 +++ lighttpd-1.4.12/tests/fcgi-responder.c 2006-07-16 00:26:05.000000000 +0300
52763 int num_requests = 2;
52765 - while (num_requests > 0 &&
52766 - FCGI_Accept() >= 0) {
52769 - if (NULL != (p = getenv("QUERY_STRING"))) {
52770 + while (num_requests > 0 && FCGI_Accept() >= 0) {
52772 + char* doc_root = NULL;
52773 + char fname[4096];
52774 + char* pfname = (char *)fname;
52776 + doc_root = getenv("DOCUMENT_ROOT");
52777 + p = getenv("QUERY_STRING");
52779 + if (NULL != p && NULL != doc_root) {
52780 + snprintf(pfname, sizeof(fname), "%s/phpinfo.php", doc_root);
52781 if (0 == strcmp(p, "lf")) {
52782 printf("Status: 200 OK\n\n");
52783 } else if (0 == strcmp(p, "crlf")) {
52785 printf("Status: 200 OK\r\n");
52788 + } else if (0 == strcmp(p,"x-lighttpd-send-file")) {
52789 + printf("Status: 200 OK\r\n");
52790 + printf("X-LIGHTTPD-send-file: %s\r\n", pfname);
52792 + } else if (0 == strcmp(p,"xsendfile")) {
52793 + printf("Status: 200 OK\r\n");
52794 + printf("X-Sendfile: %s\r\n", pfname);
52796 + } else if (0 == strcmp(p,"xsendfile-mixed-case")) {
52797 + printf("Status: 200 OK\r\n");
52798 + printf("X-SeNdFiLe: %s\r\n", pfname);
52800 } else if (0 == strcmp(p, "die-at-end")) {
52801 printf("Status: 200 OK\r\n\r\n");
52803 --- ../lighttpd-1.4.11/tests/lighttpd.conf 2006-03-09 15:26:58.000000000 +0200
52804 +++ lighttpd-1.4.12/tests/lighttpd.conf 2006-07-16 00:26:05.000000000 +0300
52806 -debug.log-request-handling = "enable"
52807 -debug.log-condition-handling = "enable"
52808 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52809 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
52810 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52811 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52812 +server.tag = "Apache 1.3.29"
52814 ## 64 Mbyte ... nice limit
52815 server.max-request-size = 65000
52817 -## bind to port (default: 80)
52818 -server.port = 2048
52819 +include "default.conf"
52821 -## bind to localhost (default: all interfaces)
52822 -server.bind = "localhost"
52823 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
52824 -server.name = "www.example.org"
52825 -server.tag = "Apache 1.3.29"
52827 -server.dir-listing = "enable"
52829 -#server.event-handler = "linux-sysepoll"
52830 -#server.event-handler = "linux-rtsig"
52832 -#server.modules.path = ""
52833 -server.modules = (
52836 - "mod_secdownload",
52842 - "mod_simple_vhost",
52845 -# "mod_localizer",
52851 - "mod_accesslog" )
52853 -server.indexfiles = ( "index.php", "index.html",
52854 - "index.htm", "default.htm" )
52857 -######################## MODULE CONFIG ############################
52859 -ssi.extension = ( ".shtml" )
52861 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
52863 -mimetype.assign = ( ".png" => "image/png",
52864 - ".jpg" => "image/jpeg",
52865 - ".jpeg" => "image/jpeg",
52866 - ".gif" => "image/gif",
52867 - ".html" => "text/html",
52868 - ".htm" => "text/html",
52869 - ".pdf" => "application/pdf",
52870 - ".swf" => "application/x-shockwave-flash",
52871 - ".spl" => "application/futuresplash",
52872 - ".txt" => "text/plain",
52873 - ".tar.gz" => "application/x-tgz",
52874 - ".tgz" => "application/x-tgz",
52875 - ".gz" => "application/x-gzip",
52876 - ".c" => "text/plain",
52877 - ".conf" => "text/plain" )
52878 +setenv.add-request-header = ( "FOO" => "foo")
52879 +setenv.add-response-header = ( "BAR" => "foo")
52881 $HTTP["host"] == "cache.example.org" {
52882 - compress.cache-dir = "@SRCDIR@/tmp/lighttpd/cache/compress/"
52883 + compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/"
52885 -compress.filetype = ("text/plain", "text/html")
52887 -setenv.add-environment = ( "TRAC_ENV" => "tracenv", "SETENV" => "setenv")
52888 -setenv.add-request-header = ( "FOO" => "foo")
52889 -setenv.add-response-header = ( "BAR" => "foo")
52891 $HTTP["url"] =~ "\.pdf$" {
52892 server.range-requests = "disable"
52893 @@ -85,76 +23,31 @@
52894 "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
52898 -cgi.assign = ( ".pl" => "/usr/bin/perl",
52899 - ".cgi" => "/usr/bin/perl",
52900 - ".py" => "/usr/bin/python" )
52902 -userdir.include-user = ( "jan" )
52903 -userdir.path = "/"
52905 -ssl.engine = "disable"
52906 -ssl.pemfile = "server.pem"
52908 $HTTP["host"] == "auth-htpasswd.example.org" {
52909 auth.backend = "htpasswd"
52912 -auth.backend = "plain"
52913 -auth.backend.plain.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.user"
52915 -auth.backend.htpasswd.userfile = "@SRCDIR@/tmp/lighttpd/lighttpd.htpasswd"
52918 -auth.require = ( "/server-status" =>
52920 - "method" => "digest",
52921 - "realm" => "download archiv",
52922 - "require" => "group=www|user=jan|host=192.168.2.10"
52924 - "/server-config" =>
52926 - "method" => "basic",
52927 - "realm" => "download archiv",
52928 - "require" => "valid-user"
52932 -url.access-deny = ( "~", ".inc")
52934 -url.rewrite = ( "^/rewrite/foo($|\?.+)" => "/indexfile/rewrite.php$1",
52935 - "^/rewrite/bar(?:$|\?(.+))" => "/indexfile/rewrite.php?bar&$1" )
52937 -expire.url = ( "/expire/access" => "access 2 hours",
52938 - "/expire/modification" => "access plus 1 seconds 2 minutes")
52940 -#cache.cache-dir = "/home/weigon/wwwroot/cache/"
52942 -#### status module
52943 -status.status-url = "/server-status"
52944 -status.config-url = "/server-config"
52946 $HTTP["host"] == "vvv.example.org" {
52947 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52948 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52949 secdownload.secret = "verysecret"
52950 - secdownload.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52951 + secdownload.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52952 secdownload.uri-prefix = "/sec/"
52953 secdownload.timeout = 120
52956 $HTTP["host"] == "zzz.example.org" {
52957 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
52958 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52959 server.name = "zzz.example.org"
52962 $HTTP["host"] == "no-simple.example.org" {
52963 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/123.example.org/pages/"
52964 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/123.example.org/pages/"
52965 server.name = "zzz.example.org"
52968 $HTTP["host"] !~ "(no-simple\.example\.org)" {
52969 simple-vhost.document-root = "pages"
52970 - simple-vhost.server-root = "@SRCDIR@/tmp/lighttpd/servers/"
52971 + simple-vhost.server-root = env.SRCDIR + "/tmp/lighttpd/servers/"
52972 simple-vhost.default-host = "www.example.org"
52975 --- ../lighttpd-1.4.11/tests/lowercase.conf 1970-01-01 03:00:00.000000000 +0300
52976 +++ lighttpd-1.4.12/tests/lowercase.conf 2006-07-16 00:26:05.000000000 +0300
52978 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
52979 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
52981 +## bind to port (default: 80)
52982 +server.port = 2048
52984 +## bind to localhost (default: all interfaces)
52985 +server.bind = "localhost"
52986 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
52988 +server.force-lowercase-filenames = "enable"
52990 +server.dir-listing = "enable"
52992 +server.modules = (
52995 + "mod_secdownload",
53004 +server.indexfiles = ( "index.php", "index.html",
53005 + "index.htm", "default.htm" )
53008 +######################## MODULE CONFIG ############################
53010 +mimetype.assign = ( ".png" => "image/png",
53011 + ".jpg" => "image/jpeg",
53012 + ".jpeg" => "image/jpeg",
53013 + ".gif" => "image/gif",
53014 + ".html" => "text/html",
53015 + ".htm" => "text/html",
53016 + ".pdf" => "application/pdf",
53017 + ".swf" => "application/x-shockwave-flash",
53018 + ".spl" => "application/futuresplash",
53019 + ".txt" => "text/plain",
53020 + ".tar.gz" => "application/x-tgz",
53021 + ".tgz" => "application/x-tgz",
53022 + ".gz" => "application/x-gzip",
53023 + ".c" => "text/plain",
53024 + ".conf" => "text/plain" )
53027 +fastcgi.server = ( ".php" => ( ( "host" => "127.0.0.1", "port" => 1026, "broken-scriptfilename" => "enable" ) ),
53028 + "/prefix.fcgi" => ( ( "host" => "127.0.0.1", "port" => 1026, "check-local" => "disable", "broken-scriptfilename" => "enable" ) )
53032 +cgi.assign = ( ".pl" => "/usr/bin/perl",
53033 + ".cgi" => "/usr/bin/perl",
53034 + ".py" => "/usr/bin/python" )
53036 +auth.backend = "plain"
53037 +auth.backend.plain.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.user"
53039 +auth.backend.htpasswd.userfile = env.SRCDIR + "/tmp/lighttpd/lighttpd.htpasswd"
53041 +$HTTP["host"] == "lowercase-auth" {
53042 + auth.require = ( "/image.jpg" =>
53044 + "method" => "digest",
53045 + "realm" => "download archiv",
53046 + "require" => "valid-user"
53051 +$HTTP["host"] == "lowercase-deny" {
53052 + url.access-deny = ( ".jpg")
53055 +$HTTP["host"] == "lowercase-exclude" {
53056 + static-file.exclude-extensions = ( ".jpg" )
53058 --- ../lighttpd-1.4.11/tests/lowercase.t 1970-01-01 03:00:00.000000000 +0300
53059 +++ lighttpd-1.4.12/tests/lowercase.t 2006-07-16 00:26:05.000000000 +0300
53061 +#!/usr/bin/env perl
53063 + # add current source dir to the include-path
53064 + # we need this for make distcheck
53065 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
53066 + unshift @INC, $srcdir;
53071 +use Test::More tests => 10;
53074 +my $tf = LightyTest->new();
53077 +$tf->{CONFIGFILE} = 'lowercase.conf';
53079 +ok($tf->start_proc == 0, "Starting lighttpd") or die();
53081 +## check if lower-casing works
53083 +$t->{REQUEST} = ( <<EOF
53084 +GET /image.JPG HTTP/1.0
53087 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53088 +ok($tf->handle_http($t) == 0, 'uppercase access');
53090 +$t->{REQUEST} = ( <<EOF
53091 +GET /image.jpg HTTP/1.0
53094 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53095 +ok($tf->handle_http($t) == 0, 'lowercase access');
53097 +## check that mod-auth works
53099 +$t->{REQUEST} = ( <<EOF
53100 +GET /image.JPG HTTP/1.0
53101 +Host: lowercase-auth
53104 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53105 +ok($tf->handle_http($t) == 0, 'uppercase access');
53107 +$t->{REQUEST} = ( <<EOF
53108 +GET /image.jpg HTTP/1.0
53109 +Host: lowercase-auth
53112 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 401 } ];
53113 +ok($tf->handle_http($t) == 0, 'lowercase access');
53116 +## check that mod-staticfile exclude works
53117 +$t->{REQUEST} = ( <<EOF
53118 +GET /image.JPG HTTP/1.0
53119 +Host: lowercase-exclude
53122 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53123 +ok($tf->handle_http($t) == 0, 'upper case access to staticfile.exclude-extension');
53125 +$t->{REQUEST} = ( <<EOF
53126 +GET /image.jpg HTTP/1.0
53127 +Host: lowercase-exclude
53130 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53131 +ok($tf->handle_http($t) == 0, 'lowercase access');
53134 +## check that mod-access exclude works
53135 +$t->{REQUEST} = ( <<EOF
53136 +GET /image.JPG HTTP/1.0
53137 +Host: lowercase-deny
53140 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53141 +ok($tf->handle_http($t) == 0, 'uppercase access to url.access-deny protected location');
53143 +$t->{REQUEST} = ( <<EOF
53144 +GET /image.jpg HTTP/1.0
53145 +Host: lowercase-deny
53148 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 403 } ];
53149 +ok($tf->handle_http($t) == 0, 'lowercase access');
53153 +ok($tf->stop_proc == 0, "Stopping lighttpd");
53155 --- ../lighttpd-1.4.11/tests/mod-cgi.t 2005-09-01 14:43:05.000000000 +0300
53156 +++ lighttpd-1.4.12/tests/mod-cgi.t 2006-07-18 13:03:40.000000000 +0300
53158 GET /nph-status.pl HTTP/1.0
53161 -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53162 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 502 } ];
53163 ok($tf->handle_http($t) == 0, 'NPH + perl, Bug #14');
53165 $t->{REQUEST} = ( <<EOF
53166 --- ../lighttpd-1.4.11/tests/mod-fastcgi.t 2006-03-09 15:30:45.000000000 +0200
53167 +++ lighttpd-1.4.12/tests/mod-fastcgi.t 2006-07-18 13:03:40.000000000 +0300
53172 -use Test::More tests => 47;
53173 +use Test::More tests => 49;
53176 my $tf = LightyTest->new();
53181 - skip "no PHP running on port 1026", 30 unless $tf->listening_on(1026);
53182 + skip "no PHP running on port 1026", 29 unless $tf->listening_on(1026);
53184 ok($tf->start_proc == 0, "Starting lighttpd") or die();
53186 @@ -223,7 +223,7 @@
53190 - skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.0/sapi/cgi/php";
53191 + skip "no php found", 4 unless -x "/home/jan/Documents/php-5.1.4/sapi/cgi/php";
53192 $tf->{CONFIGFILE} = 'fastcgi-13.conf';
53193 ok($tf->start_proc == 0, "Starting lighttpd with $tf->{CONFIGFILE}") or die();
53194 $t->{REQUEST} = ( <<EOF
53195 @@ -285,6 +285,34 @@
53196 $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => 'test123' } ];
53197 ok($tf->handle_http($t) == 0, 'line-ending \r\n + \r\n');
53199 + # X-LIGHTTPD-send-file
53200 + $t->{REQUEST} = ( <<EOF
53201 +GET /index.fcgi?x-lighttpd-send-file HTTP/1.0
53202 +Host: www.example.org
53205 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53207 + ok($tf->handle_http($t) == 0, 'X-LIGHTTPD-send-file');
53209 + $t->{REQUEST} = ( <<EOF
53210 +GET /index.fcgi?xsendfile HTTP/1.0
53211 +Host: www.example.org
53214 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53216 + ok($tf->handle_http($t) == 0, 'X-Sendfile');
53218 + $t->{REQUEST} = ( <<EOF
53219 +GET /index.fcgi?xsendfile-mixed-case HTTP/1.0
53220 +Host: www.example.org
53223 + $t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'HTTP-Content' => '<?php phpinfo(); ?>
53225 + ok($tf->handle_http($t) == 0, 'X-SeNdFiLe in mixed case');
53227 $t->{REQUEST} = ( <<EOF
53228 GET /index.fcgi?die-at-end HTTP/1.0
53229 Host: www.example.org
53230 --- ../lighttpd-1.4.11/tests/mod-proxy.t 1970-01-01 03:00:00.000000000 +0300
53231 +++ lighttpd-1.4.12/tests/mod-proxy.t 2006-07-18 13:03:40.000000000 +0300
53233 +#!/usr/bin/env perl
53235 + # add current source dir to the include-path
53236 + # we need this for make distcheck
53237 + (my $srcdir = $0) =~ s#/[^/]+$#/#;
53238 + unshift @INC, $srcdir;
53243 +use Test::More tests => 21;
53246 +my $tf_proxy = LightyTest->new();
53247 +my $tf_backend1 = LightyTest->new();
53248 +my $tf_backend2 = LightyTest->new();
53252 +## we need two procs
53253 +## 1. the real webserver
53254 +## 2. the proxy server
53257 + skip "disabled for now", 21;
53258 +$tf_proxy->{PORT} = 2048;
53259 +$tf_proxy->{CONFIGFILE} = 'proxy.conf';
53260 +$tf_proxy->{LIGHTTPD_PIDFILE} = $tf_proxy->{SRCDIR}.'/tmp/lighttpd/lighttpd-proxy.pid';
53262 +$tf_backend1->{PORT} = 2050;
53263 +$tf_backend1->{CONFIGFILE} = 'proxy-backend-1.conf';
53264 +$tf_backend1->{LIGHTTPD_PIDFILE} = $tf_backend1->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-1.pid';
53266 +$tf_backend2->{PORT} = 2051;
53267 +$tf_backend2->{CONFIGFILE} = 'proxy-backend-2.conf';
53268 +$tf_backend2->{LIGHTTPD_PIDFILE} = $tf_backend2->{SRCDIR}.'/tmp/lighttpd/lighttpd-backend-2.pid';
53271 +ok($tf_backend1->start_proc == 0, "Starting lighttpd") or die();
53273 +ok($tf_proxy->start_proc == 0, "Starting lighttpd as proxy") or die();
53277 +$t->{REQUEST} = ( <<EOF
53278 +GET /index.html HTTP/1.0
53279 +Host: www.example.org
53282 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200 } ];
53283 +ok($tf_proxy->handle_http($t) == 0, 'valid request');
53285 +$t->{REQUEST} = ( <<EOF
53286 +GET /index.html HTTP/1.0
53287 +Host: www.example.org
53290 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, 'Server' => 'proxy-backend-1' } ];
53291 +ok($tf_proxy->handle_http($t) == 0, 'drop Server from real server');
53293 +$t->{REQUEST} = ( <<EOF
53294 +GET /balance-rr/foo HTTP/1.0
53295 +Host: www.example.org
53298 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53299 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one backend');
53301 +$t->{REQUEST} = ( <<EOF
53302 +GET /balance-rr/foo HTTP/1.0
53303 +Host: www.example.org
53306 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53307 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - one host down, failover');
53309 +$t->{REQUEST} = ( <<EOF
53310 +GET /balance-fair/foo HTTP/1.0
53311 +Host: www.example.org
53314 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53315 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - one backend');
53317 +## backend 2 starting
53318 +ok($tf_backend2->start_proc == 0, "Starting second proxy backend") or die();
53320 +$t->{REQUEST} = ( <<EOF
53321 +GET /balance-rr/foo HTTP/1.0
53322 +Host: www.example.org
53325 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53326 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 1');
53328 +$t->{REQUEST} = ( <<EOF
53329 +GET /balance-rr/foo HTTP/1.0
53330 +Host: www.example.org
53333 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53334 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - lb, backend 2');
53336 +$t->{REQUEST} = ( <<EOF
53337 +GET /balance-hash/foo HTTP/1.0
53338 +Host: www.example.org
53341 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53342 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1');
53344 +$t->{REQUEST} = ( <<EOF
53345 +GET /balance-hash/foo HTTP/1.0
53346 +Host: www.example.org
53349 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-1' } ];
53350 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 1 - same URL');
53352 +$t->{REQUEST} = ( <<EOF
53353 +GET /balance-hash/bar HTTP/1.0
53354 +Host: www.example.org
53357 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53358 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2');
53360 +$t->{REQUEST} = ( <<EOF
53361 +GET /balance-hash/bar HTTP/1.0
53362 +Host: www.example.org
53365 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53366 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - lb, backend 2 - same URL');
53368 +## backend 1 stopping, failover
53369 +ok($tf_backend1->stop_proc == 0, "Stopping backend 1");
53371 +$t->{REQUEST} = ( <<EOF
53372 +GET /balance-hash/foo HTTP/1.0
53373 +Host: www.example.org
53376 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53377 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2');
53379 +$t->{REQUEST} = ( <<EOF
53380 +GET /balance-hash/bar HTTP/1.0
53381 +Host: www.example.org
53384 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53385 +ok($tf_proxy->handle_http($t) == 0, 'balance hash - failover to backend 2 - same URL');
53387 +$t->{REQUEST} = ( <<EOF
53388 +GET /balance-rr/foo HTTP/1.0
53389 +Host: www.example.org
53392 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53393 +ok($tf_proxy->handle_http($t) == 0, 'balance rr - failover to backend 2');
53395 +$t->{REQUEST} = ( <<EOF
53396 +GET /balance-fair/foo HTTP/1.0
53397 +Host: www.example.org
53400 +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 404, 'Server' => 'proxy-backend-2' } ];
53401 +ok($tf_proxy->handle_http($t) == 0, 'balance fair - failover to backend 2');
53404 +ok($tf_backend2->stop_proc == 0, "Stopping lighttpd");
53406 +ok($tf_proxy->stop_proc == 0, "Stopping lighttpd proxy");
53408 --- ../lighttpd-1.4.11/tests/proxy-backend-1.conf 1970-01-01 03:00:00.000000000 +0300
53409 +++ lighttpd-1.4.12/tests/proxy-backend-1.conf 2006-07-16 00:26:05.000000000 +0300
53411 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53412 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-1.pid"
53414 +include "default.conf"
53417 +server.tag = "proxy-backend-1"
53418 --- ../lighttpd-1.4.11/tests/proxy-backend-2.conf 1970-01-01 03:00:00.000000000 +0300
53419 +++ lighttpd-1.4.12/tests/proxy-backend-2.conf 2006-07-16 00:26:04.000000000 +0300
53421 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53422 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-backend-2.pid"
53424 +include "default.conf"
53427 +server.tag = "proxy-backend-2"
53428 --- ../lighttpd-1.4.11/tests/proxy.conf 1970-01-01 03:00:00.000000000 +0300
53429 +++ lighttpd-1.4.12/tests/proxy.conf 2006-07-16 00:26:05.000000000 +0300
53431 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53432 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd-proxy.pid"
53433 +server.tag = "proxy"
53435 +include "default.conf"
53437 +## 127.0.0.1 and 127.0.0.2 are the same host
53439 + "" => (( "host" => "127.0.0.1",
53440 + "port" => 2050 ),
53441 + ( "host" => "127.0.0.2",
53445 +$HTTP["url"] =~ "^/balance-rr/" {
53446 + proxy.balance = "round-robin"
53449 +$HTTP["url"] =~ "^/balance-hash/" {
53450 + proxy.balance = "hash"
53453 +$HTTP["url"] =~ "^/balance-fair/" {
53454 + proxy.balance = "fair"
53457 --- ../lighttpd-1.4.11/tests/var-include.conf 2005-08-27 17:44:19.000000000 +0300
53458 +++ lighttpd-1.4.12/tests/var-include.conf 2006-07-16 00:26:05.000000000 +0300
53460 debug.log-request-handling = "enable"
53461 debug.log-condition-handling = "enable"
53463 -server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53464 -server.pid-file = "@SRCDIR@/tmp/lighttpd/lighttpd.pid"
53465 +server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53466 +server.pid-file = env.SRCDIR + "/tmp/lighttpd/lighttpd.pid"
53468 ## bind to port (default: 80)
53471 ## bind to localhost (default: all interfaces)
53472 server.bind = "localhost"
53473 -server.errorlog = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.error.log"
53474 +server.errorlog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.error.log"
53475 server.name = "www.example.org"
53476 server.tag = "Apache 1.3.29"
53478 @@ -21,19 +21,19 @@
53479 ######################## MODULE CONFIG ############################
53482 -accesslog.filename = "@SRCDIR@/tmp/lighttpd/logs/lighttpd.access.log"
53483 +accesslog.filename = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.access.log"
53485 mimetype.assign = ( ".html" => "text/html" )
53487 url.redirect = ("^" => "/default")
53489 $HTTP["host"] == "www.example.org" {
53490 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53491 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53492 server.name = "www.example.org"
53493 url.redirect = ("^" => "/redirect")
53495 $HTTP["host"] == "test.example.org" {
53496 - server.document-root = "@SRCDIR@/tmp/lighttpd/servers/www.example.org/pages/"
53497 + server.document-root = env.SRCDIR + "/tmp/lighttpd/servers/www.example.org/pages/"
53498 server.name = "test.example.org"